From befc7a40781cea62819e8d6de64bb2b848f22f93 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Sun, 25 May 2014 15:46:23 +0200 Subject: [PATCH 001/740] adding column for the content of the container --- CMakeLists.txt | 4 -- apps/opencs/model/world/columns.hpp | 1 + apps/opencs/model/world/idtable.cpp | 1 + apps/opencs/model/world/refidadapterimp.cpp | 4 +- apps/opencs/model/world/refidadapterimp.hpp | 7 ++-- apps/opencs/model/world/refidcollection.cpp | 5 ++- apps/opencs/model/world/refiddata.hpp | 42 ++++++++++----------- 7 files changed, 33 insertions(+), 31 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 392fdfc66..9168d9a5a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,16 +38,12 @@ if(EXISTS ${PROJECT_SOURCE_DIR}/.git) set(GIT_VERSION "${GIT_VERSION_MAJOR}.${GIT_VERSION_MINOR}.${GIT_VERSION_RELEASE}") - if(NOT ${OPENMW_VERSION} STREQUAL ${GIT_VERSION}) - message(FATAL_ERROR "Silly Zini forgot to update the version again...") - else(NOT ${OPENMW_VERSION} STREQUAL ${GIT_VERSION}) set(OPENMW_VERSION_MAJOR ${GIT_VERSION_MAJOR}) set(OPENMW_VERSION_MINOR ${GIT_VERSION_MINOR}) set(OPENMW_VERSION_RELEASE ${GIT_VERSION_RELEASE}) set(OPENMW_VERSION_COMMITHASH "${COMMITHASH}") set(OPENMW_VERSION_TAGHASH "${TAGHASH}") - endif(NOT ${OPENMW_VERSION} STREQUAL ${GIT_VERSION}) message(STATUS "OpenMW version ${OPENMW_VERSION}") else(MATCH) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 855e89cad..fa9c92e7d 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -167,6 +167,7 @@ namespace CSMWorld ColumnId_PcRank = 154, ColumnId_Scope = 155, ColumnId_ReferenceableId = 156, + ColumnId_ContainerContent = 157, // 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/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 50998c36f..31797d081 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -130,6 +130,7 @@ void CSMWorld::IdTable::cloneRecord(const std::string& origin, CSMWorld::UniversalId::Type type) { int index = mIdCollection->getAppendIndex (destination); + beginInsertRows (QModelIndex(), index, index); mIdCollection->cloneRecord(origin, destination, type); endInsertRows(); diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index f00e9fc77..afb61acc6 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -173,9 +173,9 @@ void CSMWorld::ClothingRefIdAdapter::setData (const RefIdColumn *column, RefIdDa } CSMWorld::ContainerRefIdAdapter::ContainerRefIdAdapter (const NameColumns& columns, - const RefIdColumn *weight, const RefIdColumn *organic, const RefIdColumn *respawn) + const RefIdColumn *weight, const RefIdColumn *organic, const RefIdColumn *respawn, const RefIdColumn *content) : NameRefIdAdapter (UniversalId::Type_Container, columns), mWeight (weight), - mOrganic (organic), mRespawn (respawn) + mOrganic (organic), mRespawn (respawn), mContent(content) {} QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index bd509a86b..59c8c6461 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -34,7 +34,7 @@ namespace CSMWorld BaseRefIdAdapter (UniversalId::Type type, const BaseColumns& base); virtual std::string getId (const RecordBase& record) const; - + virtual void setId (RecordBase& record, const std::string& id); virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) @@ -57,7 +57,7 @@ namespace CSMWorld { (dynamic_cast&> (record).get().mId) = id; } - + template std::string BaseRefIdAdapter::getId (const RecordBase& record) const { @@ -610,11 +610,12 @@ namespace CSMWorld const RefIdColumn *mWeight; const RefIdColumn *mOrganic; const RefIdColumn *mRespawn; + const RefIdColumn *mContent; public: ContainerRefIdAdapter (const NameColumns& columns, const RefIdColumn *weight, - const RefIdColumn *organic, const RefIdColumn *respawn); + const RefIdColumn *organic, const RefIdColumn *respawn, const RefIdColumn *content); virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index f515e34d8..1745ce957 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -165,6 +165,9 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.push_back (RefIdColumn (Columns::ColumnId_Respawn, ColumnBase::Display_Boolean)); const RefIdColumn *respawn = &mColumns.back(); + mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent, ColumnBase::Display_None, ColumnBase::Flag_Dialogue, false, false)); + const RefIdColumn *content = &mColumns.back(); + CreatureColumns creatureColumns (actorsColumns); mColumns.push_back (RefIdColumn (Columns::ColumnId_CreatureType, ColumnBase::Display_CreatureType)); @@ -340,7 +343,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mAdapters.insert (std::make_pair (UniversalId::Type_Clothing, new ClothingRefIdAdapter (enchantableColumns, clothingType))); mAdapters.insert (std::make_pair (UniversalId::Type_Container, - new ContainerRefIdAdapter (nameColumns, weightCapacity, organic, respawn))); + new ContainerRefIdAdapter (nameColumns, weightCapacity, organic, respawn, content))); mAdapters.insert (std::make_pair (UniversalId::Type_Creature, new CreatureRefIdAdapter (creatureColumns))); mAdapters.insert (std::make_pair (UniversalId::Type_Door, diff --git a/apps/opencs/model/world/refiddata.hpp b/apps/opencs/model/world/refiddata.hpp index 1b600364c..535e914ee 100644 --- a/apps/opencs/model/world/refiddata.hpp +++ b/apps/opencs/model/world/refiddata.hpp @@ -231,27 +231,27 @@ namespace CSMWorld void save (int index, ESM::ESMWriter& writer) const; - //RECORD CONTAINERS ACCESS METHODS - const RefIdDataContainer& getBooks() const; - const RefIdDataContainer& getActivators() const; - const RefIdDataContainer& getPotions() const; - const RefIdDataContainer& getApparati() const; - const RefIdDataContainer& getArmors() const; - const RefIdDataContainer& getClothing() const; - const RefIdDataContainer& getContainers() const; - const RefIdDataContainer& getCreatures() const; - const RefIdDataContainer& getDoors() const; - const RefIdDataContainer& getIngredients() const; - const RefIdDataContainer& getCreatureLevelledLists() const; - const RefIdDataContainer& getItemLevelledList() const; - const RefIdDataContainer& getLights() const; - const RefIdDataContainer& getLocpicks() const; - const RefIdDataContainer& getMiscellaneous() const; - const RefIdDataContainer& getNPCs() const; - const RefIdDataContainer& getWeapons() const; - const RefIdDataContainer& getProbes() const; - const RefIdDataContainer& getRepairs() const; - const RefIdDataContainer& getStatics() const; + //RECORD CONTAINERS ACCESS METHODS + const RefIdDataContainer& getBooks() const; + const RefIdDataContainer& getActivators() const; + const RefIdDataContainer& getPotions() const; + const RefIdDataContainer& getApparati() const; + const RefIdDataContainer& getArmors() const; + const RefIdDataContainer& getClothing() const; + const RefIdDataContainer& getContainers() const; + const RefIdDataContainer& getCreatures() const; + const RefIdDataContainer& getDoors() const; + const RefIdDataContainer& getIngredients() const; + const RefIdDataContainer& getCreatureLevelledLists() const; + const RefIdDataContainer& getItemLevelledList() const; + const RefIdDataContainer& getLights() const; + const RefIdDataContainer& getLocpicks() const; + const RefIdDataContainer& getMiscellaneous() const; + const RefIdDataContainer& getNPCs() const; + const RefIdDataContainer& getWeapons() const; + const RefIdDataContainer& getProbes() const; + const RefIdDataContainer& getRepairs() const; + const RefIdDataContainer& getStatics() const; }; } From 41db48720d49d0b87bc1bc8d705bfb4ae7785ef5 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 27 May 2014 14:01:15 +0200 Subject: [PATCH 002/740] does not compile --- apps/opencs/model/world/refidadapter.cpp | 16 +++++- apps/opencs/model/world/refidadapter.hpp | 7 +++ apps/opencs/model/world/refidadapterimp.cpp | 60 +++++++++++++++++++++ apps/opencs/model/world/refidadapterimp.hpp | 8 +++ 4 files changed, 90 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/refidadapter.cpp b/apps/opencs/model/world/refidadapter.cpp index 94ae38c3c..283f062fe 100644 --- a/apps/opencs/model/world/refidadapter.cpp +++ b/apps/opencs/model/world/refidadapter.cpp @@ -1,6 +1,20 @@ #include "refidadapter.hpp" +#include "cassert" +#include + CSMWorld::RefIdAdapter::RefIdAdapter() {} -CSMWorld::RefIdAdapter::~RefIdAdapter() {} \ No newline at end of file +CSMWorld::RefIdAdapter::~RefIdAdapter() {} + +QVariant CSMWorld::RefIdAdapter::getData (const CSMWorld::RefIdColumn* column, const CSMWorld::RefIdData& data, int idnex, int subRowIndex, int subColIndex) const +{ + assert(false); + return QVariant(); +} + +void CSMWorld::RefIdAdapter::setData (const CSMWorld::RefIdColumn* column, CSMWorld::RefIdData& data, const QVariant& value, int index, int subRowIndex, int subColIndex) const +{ + assert(false); +} diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index 0870a2d3e..673b1f5a4 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -30,6 +30,13 @@ namespace CSMWorld const QVariant& value) const = 0; ///< If the data type does not match an exception is thrown. + virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, + int idnex, int subRowIndex, int subColIndex) const; + + virtual void setData (const RefIdColumn *column, RefIdData& data, + const QVariant& value, int index, + int subRowIndex, int subColIndex) const; + virtual std::string getId (const RecordBase& record) const = 0; virtual void setId(RecordBase& record, const std::string& id) = 0; }; diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index afb61acc6..df64e9f05 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -222,6 +222,66 @@ void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdD NameRefIdAdapter::setData (column, data, index, value); } +void CSMWorld::ContainerRefIdAdapter::setData(const RefIdColumn *column, RefIdData& data, + int index, + const QVariant& value, + int subRowIndex, + int subColIndex) +{ + using RefIdAdapter::setData; + Record& record = static_cast&> ( + data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); + + if (column==mContent) + { + switch (subColIndex) + { + case 0: + record.get().mInventory.mList.at(subRowIndex).mItem.assign(std::string(value.toString().toUtf8().constData())); + break; + + case 1: + record.get().mInventory.mList.at(subRowIndex).mCount = value.toInt(); + break; + } + } else + { + throw "This column does not hold multiple values."; + } +} + +QVariant CSMWorld::ContainerRefIdAdapter::getData (const CSMWorld::RefIdColumn* column, + const CSMWorld::RefIdData& data, + int index, + int subRowIndex, + int subColIndex) const +{ + using RefIdAdapter::getData; + const Record& record = static_cast&> ( + data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); + + if (column==mContent) + { + const ESM::ContItem& content = record.get().mInventory.mList.at(subRowIndex); + + switch (subColIndex) + { + case 0: + return QString::fromUtf8(content.mItem.toString().c_str()); + + case 1: + return content.mCount; + + default: + throw "Trying to access non-existing column in the nested table!"; + } + } else + { + throw "This column does not hold multiple values."; + } +} + + CSMWorld::CreatureColumns::CreatureColumns (const ActorColumns& actorColumns) : ActorColumns (actorColumns) {} diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 59c8c6461..f29501698 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -617,9 +617,17 @@ namespace CSMWorld ContainerRefIdAdapter (const NameColumns& columns, const RefIdColumn *weight, const RefIdColumn *organic, const RefIdColumn *respawn, const RefIdColumn *content); + using RefIdAdapter::getData; + virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index, + int subRowIndex, int subColIndex) const; + virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; + using RefIdAdapter::setData; + virtual void setData (const RefIdColumn *column, RefIdData& data, int index, + const QVariant& value, int subRowIndex, int subColIndex) const; + virtual void setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const; ///< If the data type does not match an exception is thrown. From 6720d85a04315ddd1d1807dfeb7646b438159790 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 27 May 2014 14:50:21 +0200 Subject: [PATCH 003/740] fixed compilation, thanks greye --- apps/opencs/model/world/refidadapterimp.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index df64e9f05..8c98e1808 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -226,9 +226,8 @@ void CSMWorld::ContainerRefIdAdapter::setData(const RefIdColumn *column, RefIdDa int index, const QVariant& value, int subRowIndex, - int subColIndex) + int subColIndex) const { - using RefIdAdapter::setData; Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); @@ -256,7 +255,6 @@ QVariant CSMWorld::ContainerRefIdAdapter::getData (const CSMWorld::RefIdColumn* int subRowIndex, int subColIndex) const { - using RefIdAdapter::getData; const Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); From 55d451febef1d0e204d5782b71c9330a2f8cd2d7 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 2 Jun 2014 20:41:37 +0200 Subject: [PATCH 004/740] changes in the model (idtable) to support nested data --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/collection.hpp | 8 +++ apps/opencs/model/world/collectionbase.cpp | 1 + apps/opencs/model/world/collectionbase.hpp | 2 + apps/opencs/model/world/columnbase.hpp | 10 +++- apps/opencs/model/world/idtable.cpp | 54 ++++++++++++++++++--- apps/opencs/model/world/idtable.hpp | 11 +++++ apps/opencs/model/world/refidadapter.cpp | 4 +- apps/opencs/model/world/refidadapter.hpp | 4 +- apps/opencs/model/world/refidadapterimp.cpp | 7 ++- apps/opencs/model/world/refidadapterimp.hpp | 6 +-- apps/opencs/model/world/refidcollection.cpp | 12 ++++- apps/opencs/model/world/refidcollection.hpp | 2 + apps/opencs/view/world/dialoguesubview.cpp | 46 ++++++++++-------- apps/opencs/view/world/util.cpp | 3 +- 15 files changed, 133 insertions(+), 39 deletions(-) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index cbe90b1d3..d41a015ca 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 + idtable idtableproxymodel regionmap data nestedtablemodel ) diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 1fb3e1f1d..88ef59ace 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -82,6 +82,8 @@ namespace CSMWorld virtual QVariant getData (int index, int column) const; + virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const; + virtual void setData (int index, int column, const QVariant& data); virtual const ColumnBase& getColumn (int column) const; @@ -277,6 +279,12 @@ namespace CSMWorld return mColumns.at (column)->get (mRecords.at (index)); } + template + QVariant Collection::getNestedData(int row, int column, int subRow, int subColumn) const + { + return 10; //TODO + } + template void Collection::setData (int index, int column, const QVariant& data) { diff --git a/apps/opencs/model/world/collectionbase.cpp b/apps/opencs/model/world/collectionbase.cpp index 241f198cb..7b6912575 100644 --- a/apps/opencs/model/world/collectionbase.cpp +++ b/apps/opencs/model/world/collectionbase.cpp @@ -2,6 +2,7 @@ #include "collectionbase.hpp" #include +#include #include "columnbase.hpp" diff --git a/apps/opencs/model/world/collectionbase.hpp b/apps/opencs/model/world/collectionbase.hpp index 442055d5f..19017047b 100644 --- a/apps/opencs/model/world/collectionbase.hpp +++ b/apps/opencs/model/world/collectionbase.hpp @@ -44,6 +44,8 @@ namespace CSMWorld virtual QVariant getData (int index, int column) const = 0; + virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const = 0; + virtual void setData (int index, int column, const QVariant& data) = 0; // Not in use. Temporarily removed so that the implementation of RefIdCollection can continue without diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index fe310d0aa..c8670a03b 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -89,7 +89,9 @@ namespace CSMWorld Display_RefRecordType, Display_DialogueType, Display_QuestStatusType, - Display_Gender + Display_Gender, + + Display_Nested }; int mColumnId; @@ -125,6 +127,12 @@ namespace CSMWorld throw std::logic_error ("Column " + getTitle() + " is not editable"); } }; + + template + struct NestedColumn + { + virtual QVariant getNested(const Record& record, int subColumn, int subSow) const = 0; + }; } #endif diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 31797d081..04d1b333b 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -36,7 +36,13 @@ QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const if (role==Qt::EditRole && !mIdCollection->getColumn (index.column()).isEditable()) return QVariant(); - return mIdCollection->getData (index.row(), index.column()); + if (index.internalId() != 0) + { + std::pair parentAdress(unfoldIndexAdress(index.internalId())); + return mIdCollection->getNestedData(index.row(), index.column(), parentAdress.first, parentAdress.second); + } else { + return mIdCollection->getData (index.row(), index.column()); + } } QVariant CSMWorld::IdTable::headerData (int section, Qt::Orientation orientation, int role) const @@ -97,8 +103,11 @@ bool CSMWorld::IdTable::removeRows (int row, int count, const QModelIndex& paren QModelIndex CSMWorld::IdTable::index (int row, int column, const QModelIndex& parent) const { + unsigned int encodedId = 0; if (parent.isValid()) - return QModelIndex(); + { + encodedId = this->foldIndexAdress(parent); + } if (row<0 || row>=mIdCollection->getSize()) return QModelIndex(); @@ -106,12 +115,24 @@ QModelIndex CSMWorld::IdTable::index (int row, int column, const QModelIndex& pa if (column<0 || column>=mIdCollection->getColumns()) return QModelIndex(); - return createIndex (row, column); + return createIndex(row, column, encodedId); } QModelIndex CSMWorld::IdTable::parent (const QModelIndex& index) const { - return QModelIndex(); + if (index.internalId() == 0) //0 is used for indexs with invalid parent (top level data) + { + return QModelIndex(); + } + + unsigned int id = index.internalId(); + const std::pair& adress(unfoldIndexAdress(id)); + + if (adress.first >= this->rowCount() || adress.second >= this->columnCount()) + { + throw "Parent index is not present in the model"; + } + return createIndex(adress.first, adress.second); } void CSMWorld::IdTable::addRecord (const std::string& id, UniversalId::Type type) @@ -136,10 +157,10 @@ void CSMWorld::IdTable::cloneRecord(const std::string& origin, endInsertRows(); } - +///This method can return only indexes to the top level table cells QModelIndex CSMWorld::IdTable::getModelIndex (const std::string& id, int column) const { - return index (mIdCollection->getIndex (id), column); + return index(mIdCollection->getIndex (id), column); } void CSMWorld::IdTable::setRecord (const std::string& id, const RecordBase& record) @@ -238,7 +259,28 @@ std::pair CSMWorld::IdTable::view (int row) return std::make_pair (UniversalId (UniversalId::Type_Scene, id), hint); } +///For top level data/columns int CSMWorld::IdTable::getColumnId(int column) const { return mIdCollection->getColumn(column).getId(); +} + +unsigned int CSMWorld::IdTable::foldIndexAdress (const QModelIndex& index) const +{ + unsigned int out = index.row() * this->columnCount(); + out += index.column(); + return ++out; +} + +std::pair< int, int > CSMWorld::IdTable::unfoldIndexAdress (unsigned int id) const +{ + if (id == 0) + { + throw "Attempt to unfold index id of the top level data cell"; + } + + --id; + int row = id / this->columnCount(); + int column = id - row * this->columnCount(); + return std::make_pair(row, column); } \ No newline at end of file diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index 8b5462825..deb07a1b2 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -8,6 +8,15 @@ #include "universalid.hpp" #include "columns.hpp" +/*! \brief + * Clas for holding the model. Uses typical qt table abstraction/interface for granting access to the individiual fields of the records, + * Some records are holding nested data (for instance inventory list of the npc). In casses like this, table model offers interface + * to access nested data in the qt way – that is specify parent. Since some of those nested data require multiple columns to + * represent informations, single int (default way to index model in the qmodelindex) is not sufficiant. Therefore tablemodelindex class + * can hold two ints for the sake of indexing two dimensions of the table. This model does not support multiple levels of the nested + * data. Vast majority of methods makes sense only for the top level data. + */ + namespace CSMWorld { class CollectionBase; @@ -44,6 +53,8 @@ namespace CSMWorld // not implemented IdTable (const IdTable&); IdTable& operator= (const IdTable&); + unsigned int foldIndexAdress(const QModelIndex& index) const; + std::pair unfoldIndexAdress(unsigned int id) const; public: diff --git a/apps/opencs/model/world/refidadapter.cpp b/apps/opencs/model/world/refidadapter.cpp index 283f062fe..2259a6e44 100644 --- a/apps/opencs/model/world/refidadapter.cpp +++ b/apps/opencs/model/world/refidadapter.cpp @@ -8,13 +8,13 @@ CSMWorld::RefIdAdapter::RefIdAdapter() {} CSMWorld::RefIdAdapter::~RefIdAdapter() {} -QVariant CSMWorld::RefIdAdapter::getData (const CSMWorld::RefIdColumn* column, const CSMWorld::RefIdData& data, int idnex, int subRowIndex, int subColIndex) const +QVariant CSMWorld::RefIdAdapter::getNestedData (const CSMWorld::RefIdColumn* column, const CSMWorld::RefIdData& data, int idnex, int subRowIndex, int subColIndex) const { assert(false); return QVariant(); } -void CSMWorld::RefIdAdapter::setData (const CSMWorld::RefIdColumn* column, CSMWorld::RefIdData& data, const QVariant& value, int index, int subRowIndex, int subColIndex) const +void CSMWorld::RefIdAdapter::setNestedData (const CSMWorld::RefIdColumn* column, CSMWorld::RefIdData& data, const QVariant& value, int index, int subRowIndex, int subColIndex) const { assert(false); } diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index 673b1f5a4..c9c778020 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -30,10 +30,10 @@ namespace CSMWorld const QVariant& value) const = 0; ///< If the data type does not match an exception is thrown. - virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, + virtual QVariant getNestedData (const RefIdColumn *column, const RefIdData& data, int idnex, int subRowIndex, int subColIndex) const; - virtual void setData (const RefIdColumn *column, RefIdData& data, + virtual void setNestedData (const RefIdColumn *column, RefIdData& data, const QVariant& value, int index, int subRowIndex, int subColIndex) const; diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 8c98e1808..750e4af87 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -222,7 +222,7 @@ void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdD NameRefIdAdapter::setData (column, data, index, value); } -void CSMWorld::ContainerRefIdAdapter::setData(const RefIdColumn *column, RefIdData& data, +void CSMWorld::ContainerRefIdAdapter::setNestedData(const RefIdColumn *column, RefIdData& data, int index, const QVariant& value, int subRowIndex, @@ -242,6 +242,9 @@ void CSMWorld::ContainerRefIdAdapter::setData(const RefIdColumn *column, RefIdDa case 1: record.get().mInventory.mList.at(subRowIndex).mCount = value.toInt(); break; + + default: + throw "Trying to access non-existing column in the nested table!"; } } else { @@ -249,7 +252,7 @@ void CSMWorld::ContainerRefIdAdapter::setData(const RefIdColumn *column, RefIdDa } } -QVariant CSMWorld::ContainerRefIdAdapter::getData (const CSMWorld::RefIdColumn* column, +QVariant CSMWorld::ContainerRefIdAdapter::getNestedData (const CSMWorld::RefIdColumn* column, const CSMWorld::RefIdData& data, int index, int subRowIndex, diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index f29501698..eab0151b5 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -617,15 +617,13 @@ namespace CSMWorld ContainerRefIdAdapter (const NameColumns& columns, const RefIdColumn *weight, const RefIdColumn *organic, const RefIdColumn *respawn, const RefIdColumn *content); - using RefIdAdapter::getData; - virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index, + virtual QVariant getNestedData (const RefIdColumn *column, const RefIdData& data, int index, int subRowIndex, int subColIndex) const; virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; - using RefIdAdapter::setData; - virtual void setData (const RefIdColumn *column, RefIdData& data, int index, + virtual void setNestedData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value, int subRowIndex, int subColIndex) const; virtual void setData (const RefIdColumn *column, RefIdData& data, int index, diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 1745ce957..74aa67e3b 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -165,7 +165,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.push_back (RefIdColumn (Columns::ColumnId_Respawn, ColumnBase::Display_Boolean)); const RefIdColumn *respawn = &mColumns.back(); - mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent, ColumnBase::Display_None, ColumnBase::Flag_Dialogue, false, false)); + mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent, ColumnBase::Display_Nested, ColumnBase::Flag_Dialogue, false, false)); const RefIdColumn *content = &mColumns.back(); CreatureColumns creatureColumns (actorsColumns); @@ -419,6 +419,16 @@ QVariant CSMWorld::RefIdCollection::getData (int index, int column) const return adaptor.getData (&mColumns.at (column), mData, localIndex.first); } +QVariant CSMWorld::RefIdCollection::getNestedData (int row, int column, int subRow, int subColumn) const +{ + RefIdData::LocalIndex localIndex = mData.globalToLocalIndex(row); + + const RefIdAdapter& adaptor = findAdaptor (localIndex.second); + + //if this overloaded, base class method was not overriden, crash will happen (assert(false)) Don't try to use this method for non-nested columns! + return adaptor.getNestedData(&mColumns.at(column), mData, localIndex.first, subRow, subColumn); +} + void CSMWorld::RefIdCollection::setData (int index, int column, const QVariant& data) { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (index); diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index dd6213677..d03b45814 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -65,6 +65,8 @@ namespace CSMWorld virtual QVariant getData (int index, int column) const; + virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const; + virtual void setData (int index, int column, const QVariant& data); virtual void removeRows (int index, int count); diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index abdc33103..4ac8e8780 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -295,7 +295,7 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: { connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited())); skip = true; - } + } //lisp cond pairs would be nice in the C++ connect(proxy, SIGNAL(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display)), this, SLOT(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display))); mProxys.push_back(proxy); //deleted in the destructor @@ -361,6 +361,7 @@ void CSVWorld::EditWidget::remake(int row) int unlocked = 0; int locked = 0; const int columns = mTable->columnCount(); + for (int i=0; iheaderData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt(); @@ -368,28 +369,35 @@ void CSVWorld::EditWidget::remake(int row) if (flags & CSMWorld::ColumnBase::Flag_Dialogue) { CSMWorld::ColumnBase::Display display = static_cast - (mTable->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); - - mDispatcher.makeDelegate(display); - QWidget *editor = mDispatcher.makeEditor(display, (mTable->index (row, i))); + (mTable->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); - if (editor) + if (display != CSMWorld::ColumnBase::Display_Nested) { - mWidgetMapper->addMapping (editor, i); - QLabel* label = new QLabel(mTable->headerData (i, Qt::Horizontal).toString(), mMainWidget); - label->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - editor->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); - if (! (mTable->flags (mTable->index (row, i)) & Qt::ItemIsEditable)) - { - lockedLayout->addWidget (label, locked, 0); - lockedLayout->addWidget (editor, locked, 1); - ++locked; - } else + mDispatcher.makeDelegate (display); + QWidget* editor = mDispatcher.makeEditor (display, (mTable->index (row, i))); + + if (editor) { - unlockedLayout->addWidget (label, unlocked, 0); - unlockedLayout->addWidget (editor, unlocked, 1); - ++unlocked; + mWidgetMapper->addMapping (editor, i); + QLabel* label = new QLabel (mTable->headerData (i, Qt::Horizontal).toString(), mMainWidget); + label->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed); + editor->setSizePolicy (QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); + + if (! (mTable->flags (mTable->index (row, i)) & Qt::ItemIsEditable)) + { + lockedLayout->addWidget (label, locked, 0); + lockedLayout->addWidget (editor, locked, 1); + ++locked; + } else + { + unlockedLayout->addWidget (label, unlocked, 0); + unlockedLayout->addWidget (editor, unlocked, 1); + ++unlocked; + } } + } else + { + //TODO } } } diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index b2a32b551..5fa93fe79 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -172,7 +172,8 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO display == CSMWorld::ColumnBase::Display_Class || display == CSMWorld::ColumnBase::Display_Faction || display == CSMWorld::ColumnBase::Display_Miscellaneous || - display == CSMWorld::ColumnBase::Display_Sound) + display == CSMWorld::ColumnBase::Display_Sound || + display == CSMWorld::ColumnBase::Display_Region) { return new DropLineEdit(parent); } From 29231b8fc9a10fc3e4122bd70cfa88e571ad3ad2 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 9 Jun 2014 10:26:53 +0200 Subject: [PATCH 005/740] starting new branch --- apps/opencs/view/world/dialoguesubview.cpp | 39 +++++++++++++++------- apps/opencs/view/world/dialoguesubview.hpp | 4 +-- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 4ac8e8780..d537ac4f1 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include "../../model/world/columnbase.hpp" #include "../../model/world/idtable.hpp" @@ -261,6 +263,7 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: } std::map::iterator delegateIt(mDelegates.find(display)); + if (delegateIt != mDelegates.end()) { editor = delegateIt->second->createEditor(qobject_cast(mParent), QStyleOptionViewItem(), index, display); @@ -371,7 +374,20 @@ void CSVWorld::EditWidget::remake(int row) CSMWorld::ColumnBase::Display display = static_cast (mTable->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); - if (display != CSMWorld::ColumnBase::Display_Nested) + if (display == CSMWorld::ColumnBase::Display_Nested) + { + const QModelIndex& parent = mTable->index(row, i); + if (parent.data().isValid() && mTable->hasChildren(parent)) + { + qDebug()<setModel(mTable); + table->setRootIndex(mTable->index(row, i)); + } + //TODO + } else { mDispatcher.makeDelegate (display); QWidget* editor = mDispatcher.makeEditor (display, (mTable->index (row, i))); @@ -394,10 +410,9 @@ void CSVWorld::EditWidget::remake(int row) unlockedLayout->addWidget (editor, unlocked, 1); ++unlocked; } - } - } else - { - //TODO + } else { + qDebug()<<"No edit widget"; + } } } } @@ -421,13 +436,12 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM mMainLayout(NULL), mUndoStack(document.getUndoStack()), mTable(dynamic_cast(document.getData().getTableModel(id))), - mRow (-1), mLocked(false), mDocument(document) { connect(mTable, SIGNAL(dataChanged (const QModelIndex&, const QModelIndex&)), this, SLOT(dataChanged(const QModelIndex&))); - mRow = mTable->getModelIndex (id.getId(), 0).row(); + mCurrentId(id.getId()); QWidget *mainWidget = new QWidget(this); QHBoxLayout *buttonsLayout = new QHBoxLayout; @@ -477,7 +491,7 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM mMainLayout = new QVBoxLayout(mainWidget); - mEditWidget = new EditWidget(mainWidget, mRow, mTable, mUndoStack, false); + mEditWidget = new EditWidget(mainWidget, mCurrentId, mTable, mUndoStack, false); connect(mEditWidget, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), this, SLOT(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); @@ -498,14 +512,15 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM deleteButton->setDisabled(true); } - dataChanged(mTable->index(mRow, 0)); + dataChanged(getModelIndex(mCurrentId, 0)); mMainLayout->addLayout(buttonsLayout); setWidget(mainWidget); } void CSVWorld::DialogueSubView::prevId() { - int newRow = mRow - 1; + int new Row = getModelIndex(mCurrentId, 0).row() - 1; + if (newRow < 0) { return; @@ -552,12 +567,12 @@ void CSVWorld::DialogueSubView::nextId() } CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (newRow, 1)).toInt()); - if (!(state == CSMWorld::RecordBase::State_Deleted || state == CSMWorld::RecordBase::State_Erased)) + if (!(state == CSMWorld::RecordBase::State_Deleted)) { mEditWidget->remake(newRow); setUniversalId(CSMWorld::UniversalId (static_cast (mTable->data (mTable->index (newRow, 2)).toInt()), mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); - mRow = newRow; + mCurrentId = std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData()); mEditWidget->setDisabled(mLocked); return; } diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 5642f46a0..dd14b3095 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -165,7 +165,7 @@ namespace CSVWorld QVBoxLayout* mMainLayout; CSMWorld::IdTable* mTable; QUndoStack& mUndoStack; - int mRow; + std::string mCurrentId; bool mLocked; const CSMDoc::Document& mDocument; TableBottomBox* mBottom; @@ -206,4 +206,4 @@ namespace CSVWorld }; } -#endif \ No newline at end of file +#endif From 21a1f6f4aef555775cdd66e4b4d7483d95f9b8cb Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 9 Jun 2014 10:35:39 +0200 Subject: [PATCH 006/740] working on the issue --- apps/opencs/model/world/collection.hpp | 20 ++++- apps/opencs/model/world/collectionbase.cpp | 19 +++- apps/opencs/model/world/collectionbase.hpp | 8 +- apps/opencs/model/world/idtable.cpp | 89 +++++++++++++++++-- apps/opencs/model/world/idtable.hpp | 22 +++++ apps/opencs/model/world/refidadapter.cpp | 10 ++- apps/opencs/model/world/refidadapter.hpp | 22 ++++- apps/opencs/model/world/refidadapterimp.cpp | 98 ++++++++++++++++++++- apps/opencs/model/world/refidadapterimp.hpp | 25 +++++- apps/opencs/model/world/refidcollection.cpp | 41 +++++++++ apps/opencs/model/world/refidcollection.hpp | 6 ++ 11 files changed, 342 insertions(+), 18 deletions(-) diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 1fb3e1f1d..3f110b4dd 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -73,6 +73,10 @@ namespace CSMWorld ///< Add a new record (modified) virtual int getSize() const; + + virtual int getNestedColumnsCount(int column) const; + + virtual int getNestedRowsCount(int row, int column) const; virtual std::string getId (int index) const; @@ -92,7 +96,7 @@ namespace CSMWorld virtual void purge(); ///< Remove records that are flagged as erased. - virtual void removeRows (int index, int count) ; + virtual void removeRows (int index, int count); virtual void appendBlankRecord (const std::string& id, UniversalId::Type type = UniversalId::Type_None); @@ -247,6 +251,20 @@ namespace CSMWorld { return mRecords.size(); } + + template + int Collection::getNestedRowsCount(int row, int column) const + { + //TODO + return 0; + } + + template + int Collection::getNestedColumnsCount(int column) const + { + //TODO + return 0; + } template std::string Collection::getId (int index) const diff --git a/apps/opencs/model/world/collectionbase.cpp b/apps/opencs/model/world/collectionbase.cpp index 241f198cb..eed157a7b 100644 --- a/apps/opencs/model/world/collectionbase.cpp +++ b/apps/opencs/model/world/collectionbase.cpp @@ -28,4 +28,21 @@ int CSMWorld::CollectionBase::findColumnIndex (Columns::ColumnId id) const throw std::logic_error ("invalid column index"); return index; -} \ No newline at end of file +} + +void CSMWorld::CollectionBase::setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn) +{ + assert(false); //TODO remove and make pure abstract +} + +int CSMWorld::CollectionBase::getNestedColumnsCount(int row, int column) const +{ + assert(false); //TODO remove and make pure abstract + return 0; +} + +int CSMWorld::CollectionBase::getNestedRowsCount(int row, int column) const +{ + assert(false); //TODO, make pure abstract + return 0; +} diff --git a/apps/opencs/model/world/collectionbase.hpp b/apps/opencs/model/world/collectionbase.hpp index 442055d5f..4c3afc092 100644 --- a/apps/opencs/model/world/collectionbase.hpp +++ b/apps/opencs/model/world/collectionbase.hpp @@ -33,6 +33,10 @@ namespace CSMWorld virtual ~CollectionBase(); virtual int getSize() const = 0; + + virtual int getNestedRowsCount(int row, int column) const; + + virtual int getNestedColumnsCount(int row, int column) const; virtual std::string getId (int index) const = 0; @@ -46,6 +50,8 @@ namespace CSMWorld virtual void setData (int index, int column, const QVariant& data) = 0; + virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn); + // Not in use. Temporarily removed so that the implementation of RefIdCollection can continue without // these functions for now. // virtual void merge() = 0; @@ -106,4 +112,4 @@ namespace CSMWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 50998c36f..59fc3a508 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -1,6 +1,8 @@ #include "idtable.hpp" +#include + #include "collectionbase.hpp" #include "columnbase.hpp" @@ -14,16 +16,21 @@ CSMWorld::IdTable::~IdTable() int CSMWorld::IdTable::rowCount (const QModelIndex & parent) const { - if (parent.isValid()) - return 0; - + if (hasChildren(parent)) + { + int nestedRows = mIdCollection->getNestedRowsCount(parent.row(), parent.column()); + return nestedRows; + } + return mIdCollection->getSize(); } int CSMWorld::IdTable::columnCount (const QModelIndex & parent) const { if (parent.isValid()) - return 0; + { + return mIdCollection->getNestedColumnsCount(parent.row(), parent.column()); + } return mIdCollection->getColumns(); } @@ -36,7 +43,17 @@ QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const if (role==Qt::EditRole && !mIdCollection->getColumn (index.column()).isEditable()) return QVariant(); +<<<<<<< Updated upstream return mIdCollection->getData (index.row(), index.column()); +======= + if (index.internalId() != 0) + { + std::pair parentAdress(unfoldIndexAdress(index.internalId())); + return mIdCollection->getNestedData(parentAdress.first, parentAdress.second, index.row(), index.column()); + } else { + return mIdCollection->getData (index.row(), index.column()); + } +>>>>>>> Stashed changes } QVariant CSMWorld::IdTable::headerData (int section, Qt::Orientation orientation, int role) const @@ -60,11 +77,18 @@ bool CSMWorld::IdTable::setData ( const QModelIndex &index, const QVariant &valu { if (mIdCollection->getColumn (index.column()).isEditable() && role==Qt::EditRole) { - mIdCollection->setData (index.row(), index.column(), value); + if (index.internalId() == 0) + { + mIdCollection->setData (index.row(), index.column(), value); - emit dataChanged (CSMWorld::IdTable::index (index.row(), 0), - CSMWorld::IdTable::index (index.row(), mIdCollection->getColumns()-1)); + emit dataChanged (CSMWorld::IdTable::index (index.row(), 0), + CSMWorld::IdTable::index (index.row(), mIdCollection->getColumns()-1)); + } else + { + const std::pair& parentAdress(unfoldIndexAdress(index.internalId())); + mIdCollection->setNestedData(parentAdress.first, parentAdress.second, value, index.row(), index.column()); + } return true; } @@ -111,7 +135,23 @@ QModelIndex CSMWorld::IdTable::index (int row, int column, const QModelIndex& pa QModelIndex CSMWorld::IdTable::parent (const QModelIndex& index) const { +<<<<<<< Updated upstream return QModelIndex(); +======= + if (index.internalId() == 0) //0 is used for indexs with invalid parent (top level data) + { + return QModelIndex(); + } + + const std::pair& adress(unfoldIndexAdress(index.internalId())); + + if (adress.first >= this->rowCount() || adress.second >= this->columnCount()) + { + qDebug()<<"Parent index is not present in the model"; + throw "Parent index is not present in the model"; + } + return createIndex(adress.first, adress.second, 0); +>>>>>>> Stashed changes } void CSMWorld::IdTable::addRecord (const std::string& id, UniversalId::Type type) @@ -240,4 +280,37 @@ std::pair CSMWorld::IdTable::view (int row) int CSMWorld::IdTable::getColumnId(int column) const { return mIdCollection->getColumn(column).getId(); -} \ No newline at end of file +<<<<<<< Updated upstream +} +======= +} + +bool CSMWorld::IdTable::hasChildren(const QModelIndex& index) const +{ + return (index.isValid() && + mIdCollection->getColumn (index.column()).mDisplayType == ColumnBase::Display_Nested && + index.data().isValid()); +} + +unsigned int CSMWorld::IdTable::foldIndexAdress (const QModelIndex& index) const +{ + unsigned int out = index.row() * this->columnCount(); + out += index.column(); + ++out; + return out; +} + +std::pair< int, int > CSMWorld::IdTable::unfoldIndexAdress (unsigned int id) const +{ + if (id == 0) + { + qDebug()<<"Attempt to unfold index id of the top level data cell"; + throw "Attempt to unfold index id of the top level data cell"; + } + + --id; + int row = id / this->columnCount(); + int column = id - row * this->columnCount(); + return std::make_pair(row, column); +} +>>>>>>> Stashed changes diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index 8b5462825..bf9f4a555 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -8,6 +8,19 @@ #include "universalid.hpp" #include "columns.hpp" +<<<<<<< Updated upstream +======= +/*! \brief + * Clas for holding the model. Uses typical qt table abstraction/interface for granting access to the individiual fields of the records, + * Some records are holding nested data (for instance inventory list of the npc). In casses like this, table model offers interface + * to access nested data in the qt way – that is specify parent. The parent is encoded in the internalid of the index model + * See methods fold and unfold adress to see why. This approach has some serious limitations: it allows only + * a single level of the nesting. At the point of creating this code this seemed to be a good enough solution. + * If for some reason it turned out that in fact multiple levels of nesting are needed, change in the addressing of the + * index is most likely the very first to be considered. + */ + +>>>>>>> Stashed changes namespace CSMWorld { class CollectionBase; @@ -44,6 +57,13 @@ namespace CSMWorld // not implemented IdTable (const IdTable&); IdTable& operator= (const IdTable&); +<<<<<<< Updated upstream +======= + + unsigned int foldIndexAdress(const QModelIndex& index) const; + + std::pair unfoldIndexAdress(unsigned int id) const; +>>>>>>> Stashed changes public: @@ -71,6 +91,8 @@ namespace CSMWorld const; virtual QModelIndex parent (const QModelIndex& index) const; + + virtual bool hasChildren (const QModelIndex& index) const; void addRecord (const std::string& id, UniversalId::Type type = UniversalId::Type_None); ///< \param type Will be ignored, unless the collection supports multiple record types diff --git a/apps/opencs/model/world/refidadapter.cpp b/apps/opencs/model/world/refidadapter.cpp index 94ae38c3c..785e98d5e 100644 --- a/apps/opencs/model/world/refidadapter.cpp +++ b/apps/opencs/model/world/refidadapter.cpp @@ -3,4 +3,12 @@ CSMWorld::RefIdAdapter::RefIdAdapter() {} -CSMWorld::RefIdAdapter::~RefIdAdapter() {} \ No newline at end of file +<<<<<<< Updated upstream +CSMWorld::RefIdAdapter::~RefIdAdapter() {} +======= +CSMWorld::RefIdAdapter::~RefIdAdapter() {} + +CSMWorld::NestedRefIdAdapter::NestedRefIdAdapter() {} + +CSMWorld::NestedRefIdAdapter::~NestedRefIdAdapter() {} +>>>>>>> Stashed changes diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index 0870a2d3e..3a9d02dca 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -31,8 +31,28 @@ namespace CSMWorld ///< If the data type does not match an exception is thrown. virtual std::string getId (const RecordBase& record) const = 0; + virtual void setId(RecordBase& record, const std::string& id) = 0; }; + + class NestedRefIdAdapter + { + public: + NestedRefIdAdapter(); + + virtual ~NestedRefIdAdapter(); + + virtual void setNestedData (const RefIdColumn *column, RefIdData& data, int row, + const QVariant& value, int subRowIndex, int subColIndex) const = 0; + + virtual QVariant getNestedData (const RefIdColumn *column, const RefIdData& data, + int index, int subRowIndex, int subColIndex) const = 0; + + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const = 0; + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const = 0; + }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index f00e9fc77..b67b26cdb 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -1,6 +1,8 @@ #include "refidadapterimp.hpp" +#include + CSMWorld::PotionRefIdAdapter::PotionRefIdAdapter (const InventoryColumns& columns, const RefIdColumn *autoCalc) : InventoryRefIdAdapter (UniversalId::Type_Potion, columns), @@ -178,6 +180,32 @@ CSMWorld::ContainerRefIdAdapter::ContainerRefIdAdapter (const NameColumns& colum mOrganic (organic), mRespawn (respawn) {} +int CSMWorld::ContainerRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const +{ + qDebug()<<"getting nested columns count"; + if (column==mContent) + { + return 2; + } else { + throw "Trying to obtain nested columns count, but column does not have nested columns!"; + } +} + +int CSMWorld::ContainerRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const +{ + qDebug()<<"getting nested rows count"; + const Record& record = static_cast&> ( + data.getRecord(RefIdData::LocalIndex (index, UniversalId::Type_Container))); + + qDebug() << "exception above"; + if (column==mContent) + { + qDebug() << record.get().mInventory.mList.size(); + return record.get().mInventory.mList.size(); + } else { + throw "Trying to obtain nested rows count, but column does not have nested columns!"; + } +} QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, int index) const { @@ -192,6 +220,9 @@ QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, co if (column==mRespawn) return (record.get().mFlags & ESM::Container::Respawn)!=0; + + if (column==mContent) + return true; return NameRefIdAdapter::getData (column, data, index); } @@ -222,6 +253,71 @@ void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdD NameRefIdAdapter::setData (column, data, index, value); } +<<<<<<< Updated upstream +======= +void CSMWorld::ContainerRefIdAdapter::setNestedData(const RefIdColumn *column, RefIdData& data, + int row, + const QVariant& value, + int subRowIndex, + int subColIndex) const +{ + Record& record = static_cast&> ( + data.getRecord (RefIdData::LocalIndex (row, UniversalId::Type_Container))); + + if (column==mContent) + { + switch (subColIndex) + { + case 0: + record.get().mInventory.mList.at(subRowIndex).mItem.assign(std::string(value.toString().toUtf8().constData())); + break; + + case 1: + record.get().mInventory.mList.at(subRowIndex).mCount = value.toInt(); + break; + + default: + throw "Trying to access non-existing column in the nested table!"; + } + } else + { + throw "This column does not hold multiple values."; + } +} + +QVariant CSMWorld::ContainerRefIdAdapter::getNestedData (const CSMWorld::RefIdColumn* column, + const CSMWorld::RefIdData& data, + int index, + int subRowIndex, + int subColIndex) const +{ + qDebug()<<"Accessing content column"; + const Record& record = static_cast&> ( + data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); + + if (column==mContent) + { + const ESM::ContItem& content = record.get().mInventory.mList.at(subRowIndex); + + switch (subColIndex) + { + case 0: + return QString::fromUtf8(content.mItem.toString().c_str()); + + case 1: + return content.mCount; + + default: + throw "Trying to access non-existing column in the nested table!"; + } + } else + { + throw "This column does not hold multiple values."; + } +} + + +>>>>>>> Stashed changes CSMWorld::CreatureColumns::CreatureColumns (const ActorColumns& actorColumns) : ActorColumns (actorColumns) {} @@ -572,4 +668,4 @@ void CSMWorld::WeaponRefIdAdapter::setData (const RefIdColumn *column, RefIdData else EnchantableRefIdAdapter::setData (column, data, index, value); } -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index bd509a86b..ed6c50fe3 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -23,6 +23,7 @@ namespace CSMWorld }; /// \brief Base adapter for all refereceable record types + /// Adapters that can handle nested tables, needs to return valid qvariant for parent columns template class BaseRefIdAdapter : public RefIdAdapter { @@ -605,7 +606,7 @@ namespace CSMWorld ///< If the data type does not match an exception is thrown. }; - class ContainerRefIdAdapter : public NameRefIdAdapter + class ContainerRefIdAdapter : public NameRefIdAdapter, public NestedRefIdAdapter { const RefIdColumn *mWeight; const RefIdColumn *mOrganic; @@ -614,14 +615,30 @@ namespace CSMWorld public: ContainerRefIdAdapter (const NameColumns& columns, const RefIdColumn *weight, +<<<<<<< Updated upstream const RefIdColumn *organic, const RefIdColumn *respawn); +======= + const RefIdColumn *organic, const RefIdColumn *respawn, const RefIdColumn *content); - virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) - const; + virtual QVariant getNestedData (const RefIdColumn *column, const RefIdData& data, + int index, int subRowIndex, int subColIndex) const; +>>>>>>> Stashed changes + + virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; +<<<<<<< Updated upstream +======= + virtual void setNestedData (const RefIdColumn *column, RefIdData& data, int index, + const QVariant& value, int subRowIndex, int subColIndex) const; + +>>>>>>> Stashed changes virtual void setData (const RefIdColumn *column, RefIdData& data, int index, - const QVariant& value) const; + const QVariant& value) const; ///< If the data type does not match an exception is thrown. + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const; + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; }; struct CreatureColumns : public ActorColumns diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index f515e34d8..c9d6700b5 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -3,6 +3,7 @@ #include #include +#include #include @@ -416,6 +417,19 @@ QVariant CSMWorld::RefIdCollection::getData (int index, int column) const return adaptor.getData (&mColumns.at (column), mData, localIndex.first); } +<<<<<<< Updated upstream +======= +QVariant CSMWorld::RefIdCollection::getNestedData (int row, int column, int subRow, int subColumn) const +{ + RefIdData::LocalIndex localIndex = mData.globalToLocalIndex(row); + + const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdaptor (localIndex.second)); + + //if this overloaded, base class method was not overriden, crash will happen (assert(false)) Don't try to use this method for non-nested columns! + return adaptor.getNestedData (&mColumns.at (column), mData, localIndex.first, subRow, subColumn); +} + +>>>>>>> Stashed changes void CSMWorld::RefIdCollection::setData (int index, int column, const QVariant& data) { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (index); @@ -425,6 +439,15 @@ void CSMWorld::RefIdCollection::setData (int index, int column, const QVariant& adaptor.setData (&mColumns.at (column), mData, localIndex.first, data); } +void CSMWorld::RefIdCollection::setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn) +{ + RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + + const RefIdAdapter& adaptor = findAdaptor (localIndex.second); + + dynamic_cast(adaptor).setNestedData (&mColumns.at (column), mData, localIndex.first, data, subRow, subColumn); +} + void CSMWorld::RefIdCollection::removeRows (int index, int count) { mData.erase (index, count); @@ -566,3 +589,21 @@ const CSMWorld::RefIdData& CSMWorld::RefIdCollection::getDataSet() const return mData; } +int CSMWorld::RefIdCollection::getNestedRowsCount(int row, int column) const +{ + RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + + const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdaptor (localIndex.second)); + + const int count = adaptor.getNestedRowsCount(&mColumns.at(column), mData, localIndex.first); + return count; +} + +int CSMWorld::RefIdCollection::getNestedColumnsCount(int row, int column) const +{ + RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + + const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdaptor (localIndex.second)); + + return adaptor.getNestedColumnsCount(&mColumns.at(column), mData); +} diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index dd6213677..f4ac556cf 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -55,6 +55,10 @@ namespace CSMWorld virtual int getSize() const; + virtual int getNestedRowsCount(int row, int column) const; + + virtual int getNestedColumnsCount(int row, int column) const; + virtual std::string getId (int index) const; virtual int getIndex (const std::string& id) const; @@ -67,6 +71,8 @@ namespace CSMWorld virtual void setData (int index, int column, const QVariant& data); + virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn); + virtual void removeRows (int index, int count); virtual void cloneRecord(const std::string& origin, From 6f5935edb38dd30e00360053b9d1fd8b26b28b05 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 9 Jun 2014 11:37:48 +0200 Subject: [PATCH 007/740] subview does not store row number anymore --- apps/opencs/view/world/dialoguesubview.cpp | 93 +++++++++++++--------- 1 file changed, 56 insertions(+), 37 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index d537ac4f1..03321728b 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -379,14 +379,15 @@ void CSVWorld::EditWidget::remake(int row) const QModelIndex& parent = mTable->index(row, i); if (parent.data().isValid() && mTable->hasChildren(parent)) { + /* qDebug()<setModel(mTable); table->setRootIndex(mTable->index(row, i)); + */ } - //TODO } else { mDispatcher.makeDelegate (display); @@ -410,9 +411,7 @@ void CSVWorld::EditWidget::remake(int row) unlockedLayout->addWidget (editor, unlocked, 1); ++unlocked; } - } else { - qDebug()<<"No edit widget"; - } + } } } } @@ -441,7 +440,7 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM { connect(mTable, SIGNAL(dataChanged (const QModelIndex&, const QModelIndex&)), this, SLOT(dataChanged(const QModelIndex&))); - mCurrentId(id.getId()); + mCurrentId = id.getId(); QWidget *mainWidget = new QWidget(this); QHBoxLayout *buttonsLayout = new QHBoxLayout; @@ -491,7 +490,7 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM mMainLayout = new QVBoxLayout(mainWidget); - mEditWidget = new EditWidget(mainWidget, mCurrentId, mTable, mUndoStack, false); + mEditWidget = new EditWidget(mainWidget, mTable->getModelIndex(mCurrentId, 0).row(), mTable, mUndoStack, false); connect(mEditWidget, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), this, SLOT(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); @@ -512,14 +511,14 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM deleteButton->setDisabled(true); } - dataChanged(getModelIndex(mCurrentId, 0)); + dataChanged(mTable->getModelIndex(mCurrentId, 0)); mMainLayout->addLayout(buttonsLayout); setWidget(mainWidget); } void CSVWorld::DialogueSubView::prevId() { - int new Row = getModelIndex(mCurrentId, 0).row() - 1; + int newRow = mTable->getModelIndex(mCurrentId, 0).row() - 1; if (newRow < 0) { @@ -540,7 +539,7 @@ void CSVWorld::DialogueSubView::prevId() mEditWidget->remake(newRow); setUniversalId(CSMWorld::UniversalId (static_cast (mTable->data (mTable->index (newRow, 2)).toInt()), mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); - mRow = newRow; + mCurrentId = std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData()); mEditWidget->setDisabled(mLocked); return; } @@ -550,7 +549,7 @@ void CSVWorld::DialogueSubView::prevId() void CSVWorld::DialogueSubView::nextId() { - int newRow = mRow + 1; + int newRow = mTable->getModelIndex(mCurrentId, 0).row() + 1; if (newRow >= mTable->rowCount()) { @@ -571,7 +570,7 @@ void CSVWorld::DialogueSubView::nextId() { mEditWidget->remake(newRow); setUniversalId(CSMWorld::UniversalId (static_cast (mTable->data (mTable->index (newRow, 2)).toInt()), - mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); + mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); mCurrentId = std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData()); mEditWidget->setDisabled(mLocked); return; @@ -583,8 +582,10 @@ void CSVWorld::DialogueSubView::nextId() void CSVWorld::DialogueSubView::setEditLock (bool locked) { mLocked = locked; - CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (mRow, 1)).toInt()); - if (state == CSMWorld::RecordBase::State_Deleted || state == CSMWorld::RecordBase::State_Erased) + QModelIndex index(mTable->getModelIndex(mCurrentId, 0)); + + CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (index.row(), 1)).toInt()); + if (state == CSMWorld::RecordBase::State_Deleted) { mEditWidget->setDisabled(true); } else @@ -595,10 +596,12 @@ void CSVWorld::DialogueSubView::setEditLock (bool locked) void CSVWorld::DialogueSubView::dataChanged(const QModelIndex & index) { - if (index.row() == mRow) + QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); + + if (!currentIndex.isValid() && index.row() == currentIndex.row()) { - CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (mRow, 1)).toInt()); - if (state == CSMWorld::RecordBase::State_Deleted || state == CSMWorld::RecordBase::State_Erased) + CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (currentIndex.row(), 1)).toInt()); + if (state == CSMWorld::RecordBase::State_Deleted) { mEditWidget->setDisabled(true); } else @@ -621,15 +624,24 @@ void CSVWorld::DialogueSubView::tableMimeDataDropped(QWidget* editor, void CSVWorld::DialogueSubView::revertRecord() { - int rows = mTable->rowCount(); - if (!mLocked && mTable->columnCount() > 0 && mRow < mTable->rowCount() ) + const int rows = mTable->rowCount(); + QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); + + if (!currentIndex.isValid()) + { + return; + } + + const int currentRow = currentIndex.row(); + + if (!mLocked && mTable->columnCount() > 0 && currentRow < mTable->rowCount() ) { CSMWorld::RecordBase::State state = - static_cast (mTable->data (mTable->index (mRow, 1)).toInt()); + static_cast (mTable->data (mTable->index (currentRow, 1)).toInt()); if (state!=CSMWorld::RecordBase::State_BaseOnly) { - mUndoStack.push(new CSMWorld::RevertCommand(*mTable, mTable->data(mTable->index (mRow, 0)).toString().toUtf8().constData())); + mUndoStack.push(new CSMWorld::RevertCommand(*mTable, mCurrentId)); } if (rows != mTable->rowCount()) { @@ -638,11 +650,11 @@ void CSVWorld::DialogueSubView::revertRecord() mEditWidget->setDisabled(true); //closing the editor is other option return; } - if (mRow >= mTable->rowCount()) + if (currentIndex.row() >= mTable->rowCount()) { prevId(); } else { - dataChanged(mTable->index(mRow, 0)); + dataChanged(currentIndex); } } } @@ -650,19 +662,20 @@ void CSVWorld::DialogueSubView::revertRecord() void CSVWorld::DialogueSubView::deleteRecord() { - int rows = mTable->rowCount(); + const int rows = mTable->rowCount(); + QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); //easier than disabling the button - CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (mRow, 1)).toInt()); - bool deledetedOrErased = (state == CSMWorld::RecordBase::State_Deleted || state == CSMWorld::RecordBase::State_Erased); + CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (currentIndex.row(), 1)).toInt()); + bool deledetedOrErased = (state == CSMWorld::RecordBase::State_Deleted); if (!mLocked && mTable->columnCount() > 0 && !deledetedOrErased && - mRow < rows && + currentIndex.row() < rows && mBottom->canCreateAndDelete()) { - mUndoStack.push(new CSMWorld::DeleteCommand(*mTable, mTable->data(mTable->index (mRow, 0)).toString().toUtf8().constData())); + mUndoStack.push(new CSMWorld::DeleteCommand(*mTable, mCurrentId)); if (rows != mTable->rowCount()) { if (mTable->rowCount() == 0) @@ -670,11 +683,11 @@ void CSVWorld::DialogueSubView::deleteRecord() mEditWidget->setDisabled(true); //closing the editor is other option return; } - if (mRow >= mTable->rowCount()) + if (currentIndex.row() >= mTable->rowCount()) { prevId(); } else { - dataChanged(mTable->index(mRow, 0)); + dataChanged(currentIndex); } } } @@ -682,29 +695,35 @@ void CSVWorld::DialogueSubView::deleteRecord() void CSVWorld::DialogueSubView::requestFocus (const std::string& id) { - mRow = mTable->getModelIndex (id, 0).row(); - mEditWidget->remake(mRow); + mCurrentId = std::string(id); + mEditWidget->remake(mTable->getModelIndex (id, 0).row()); } void CSVWorld::DialogueSubView::cloneRequest () { - mBottom->cloneRequest(mTable->data(mTable->index (mRow, 0)).toString().toUtf8().constData(), - static_cast(mTable->data(mTable->index(mRow, 2)).toInt())); + mBottom->cloneRequest(mCurrentId, static_cast(mTable->data(mTable->getModelIndex(mCurrentId, 2)).toInt())); } void CSVWorld::DialogueSubView::showPreview () { - if (mTable->hasPreview() && mRow < mTable->rowCount()) + QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); + + if (currentIndex.isValid() && + mTable->hasPreview() && + currentIndex.row() < mTable->rowCount()) { - emit focusId(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Preview, mTable->data(mTable->index (mRow, 0)).toString().toUtf8().constData()), ""); + emit focusId(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Preview, mCurrentId), ""); } } void CSVWorld::DialogueSubView::viewRecord() { - if (mRow < mTable->rowCount()) + QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); + + if (currentIndex.isValid() && + currentIndex.row() < mTable->rowCount()) { - std::pair params = mTable->view (mRow); + std::pair params = mTable->view (currentIndex.row()); if (params.first.getType()!=CSMWorld::UniversalId::Type_None) emit focusId (params.first, params.second); From 649ce543698db2f87460f9b26c0d84c9b48606a2 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 9 Jun 2014 11:53:06 +0200 Subject: [PATCH 008/740] merging --- CMakeLists.txt | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 874d65af3..3632f1e08 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,19 +36,8 @@ if(EXISTS ${PROJECT_SOURCE_DIR}/.git) string(REGEX REPLACE "^openmw-[0-9]+\\.([0-9]+).*" "\\1" GIT_VERSION_MINOR "${VERSION}") string(REGEX REPLACE "^openmw-[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" GIT_VERSION_RELEASE "${VERSION}") -<<<<<<< HEAD - set(GIT_VERSION "${GIT_VERSION_MAJOR}.${GIT_VERSION_MINOR}.${GIT_VERSION_RELEASE}") - - set(OPENMW_VERSION_MAJOR ${GIT_VERSION_MAJOR}) - set(OPENMW_VERSION_MINOR ${GIT_VERSION_MINOR}) - set(OPENMW_VERSION_RELEASE ${GIT_VERSION_RELEASE}) - - set(OPENMW_VERSION_COMMITHASH "${COMMITHASH}") - set(OPENMW_VERSION_TAGHASH "${TAGHASH}") -======= set(OPENMW_VERSION_COMMITHASH "${COMMITHASH}") set(OPENMW_VERSION_TAGHASH "${TAGHASH}") ->>>>>>> master/refs message(STATUS "OpenMW version ${OPENMW_VERSION}") else(MATCH) From c8458654ac19121fdf2851658a3737121829bf94 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 9 Jun 2014 13:16:10 +0200 Subject: [PATCH 009/740] correcting problems --- apps/opencs/view/world/dialoguesubview.cpp | 41 +++++++--------------- 1 file changed, 13 insertions(+), 28 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 523b358ae..db80af025 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -20,7 +20,6 @@ #include #include #include -#include #include "../../model/world/columnbase.hpp" #include "../../model/world/idtable.hpp" @@ -375,22 +374,21 @@ void CSVWorld::EditWidget::remake(int row) { CSMWorld::ColumnBase::Display display = static_cast (mTable->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); - +/* commented out for now TODO if (display == CSMWorld::ColumnBase::Display_Nested) { const QModelIndex& parent = mTable->index(row, i); if (parent.data().isValid() && mTable->hasChildren(parent)) { - /* qDebug()<setModel(mTable); table->setRootIndex(mTable->index(row, i)); - */ + } - } else + } else */ { mDispatcher.makeDelegate (display); QWidget* editor = mDispatcher.makeEditor (display, (mTable->index (row, i))); @@ -583,40 +581,28 @@ void CSVWorld::DialogueSubView::nextId() void CSVWorld::DialogueSubView::setEditLock (bool locked) { mLocked = locked; - QModelIndex index(mTable->getModelIndex(mCurrentId, 0)); + QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); - CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (index.row(), 1)).toInt()); - if (state == CSMWorld::RecordBase::State_Deleted) - { - mEditWidget->setDisabled(true); - } else + mEditWidget->setDisabled (state==CSMWorld::RecordBase::State_Deleted || locked); + + if (currentIndex.isValid()) { - mEditWidget->setDisabled(mLocked); - } - - CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (mRow, 1)).toInt()); + CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (currentIndex.row(), 1)).toInt()); - mEditWidget->setDisabled (state==CSMWorld::RecordBase::State_Deleted || locked); + mCommandDispatcher.setEditLock (locked); + } - mCommandDispatcher.setEditLock (locked); } void CSVWorld::DialogueSubView::dataChanged(const QModelIndex & index) { QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); - if (!currentIndex.isValid() && index.row() == currentIndex.row()) + mEditWidget->setDisabled (state==CSMWorld::RecordBase::State_Deleted || mLocked); + + if (currentIndex.isValid() && index.row() == currentIndex.row()) { CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (currentIndex.row(), 1)).toInt()); - if (state == CSMWorld::RecordBase::State_Deleted) - { - mEditWidget->setDisabled(true); - } else - { - mEditWidget->setDisabled(mLocked); - } - - mEditWidget->setDisabled (state==CSMWorld::RecordBase::State_Deleted || mLocked); } } @@ -719,7 +705,6 @@ void CSVWorld::DialogueSubView::showPreview () if (currentIndex.isValid() && mTable->getFeatures() & CSMWorld::IdTable::Feature_Preview && - mTable->hasPreview() && currentIndex.row() < mTable->rowCount()) { emit focusId(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Preview, mCurrentId), ""); From 9ee00534b9818226232bc7b7aaf832b37cbcd4b0 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 9 Jun 2014 13:18:17 +0200 Subject: [PATCH 010/740] check if index is valid before attempting to use it --- apps/opencs/view/world/dialoguesubview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index db80af025..8ffc0da56 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -660,11 +660,11 @@ void CSVWorld::DialogueSubView::deleteRecord() const int rows = mTable->rowCount(); QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); - //easier than disabling the button CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (currentIndex.row(), 1)).toInt()); bool deledetedOrErased = (state == CSMWorld::RecordBase::State_Deleted); if (!mLocked && + currentIndex.isValid() && mTable->columnCount() > 0 && !deledetedOrErased && currentIndex.row() < rows && From 8763309a1bdc0e15839cdfd3509ed68e28fc0917 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 9 Jun 2014 13:31:15 +0200 Subject: [PATCH 011/740] reformatting to make code easier to read --- apps/opencs/view/world/dialoguesubview.cpp | 63 ++++++++++++++-------- 1 file changed, 42 insertions(+), 21 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 8ffc0da56..9d6538c1c 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -133,25 +133,25 @@ void CSVWorld::DialogueDelegateDispatcherProxy::tableMimeDataDropped(const std:: if (mDisplay == CSMWorld::ColumnBase::Display_Referenceable) { if ( type == CSMWorld::UniversalId::Type_Activator - || type == CSMWorld::UniversalId::Type_Potion - || type == CSMWorld::UniversalId::Type_Apparatus - || type == CSMWorld::UniversalId::Type_Armor - || type == CSMWorld::UniversalId::Type_Book - || type == CSMWorld::UniversalId::Type_Clothing - || type == CSMWorld::UniversalId::Type_Container - || type == CSMWorld::UniversalId::Type_Creature - || type == CSMWorld::UniversalId::Type_Door - || type == CSMWorld::UniversalId::Type_Ingredient - || type == CSMWorld::UniversalId::Type_CreatureLevelledList - || type == CSMWorld::UniversalId::Type_ItemLevelledList - || type == CSMWorld::UniversalId::Type_Light - || type == CSMWorld::UniversalId::Type_Lockpick - || type == CSMWorld::UniversalId::Type_Miscellaneous - || type == CSMWorld::UniversalId::Type_Npc - || type == CSMWorld::UniversalId::Type_Probe - || type == CSMWorld::UniversalId::Type_Repair - || type == CSMWorld::UniversalId::Type_Static - || type == CSMWorld::UniversalId::Type_Weapon) + || type == CSMWorld::UniversalId::Type_Potion + || type == CSMWorld::UniversalId::Type_Apparatus + || type == CSMWorld::UniversalId::Type_Armor + || type == CSMWorld::UniversalId::Type_Book + || type == CSMWorld::UniversalId::Type_Clothing + || type == CSMWorld::UniversalId::Type_Container + || type == CSMWorld::UniversalId::Type_Creature + || type == CSMWorld::UniversalId::Type_Door + || type == CSMWorld::UniversalId::Type_Ingredient + || type == CSMWorld::UniversalId::Type_CreatureLevelledList + || type == CSMWorld::UniversalId::Type_ItemLevelledList + || type == CSMWorld::UniversalId::Type_Light + || type == CSMWorld::UniversalId::Type_Lockpick + || type == CSMWorld::UniversalId::Type_Miscellaneous + || type == CSMWorld::UniversalId::Type_Npc + || type == CSMWorld::UniversalId::Type_Probe + || type == CSMWorld::UniversalId::Type_Repair + || type == CSMWorld::UniversalId::Type_Static + || type == CSMWorld::UniversalId::Type_Weapon) { type = CSMWorld::UniversalId::Type_Referenceable; } @@ -266,16 +266,20 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: if (delegateIt != mDelegates.end()) { editor = delegateIt->second->createEditor(qobject_cast(mParent), QStyleOptionViewItem(), index, display); + DialogueDelegateDispatcherProxy* proxy = new DialogueDelegateDispatcherProxy(editor, display); bool skip = false; if (qobject_cast(editor)) { connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited())); + connect(editor, SIGNAL(tableMimeDataDropped(const std::vector&, const CSMDoc::Document*)), proxy, SLOT(tableMimeDataDropped(const std::vector&, const CSMDoc::Document*))); + connect(proxy, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), this, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); + skip = true; } if(!skip && qobject_cast(editor)) @@ -299,7 +303,9 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: skip = true; } //lisp cond pairs would be nice in the C++ - connect(proxy, SIGNAL(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display)), this, SLOT(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display))); + connect(proxy, SIGNAL(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display)), + this, SLOT(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display))); + mProxys.push_back(proxy); //deleted in the destructor } return editor; @@ -326,7 +332,9 @@ mUndoStack(undoStack), mTable(table) { remake (row); - connect(&mDispatcher, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), this, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); + + connect(&mDispatcher, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), + this, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); } void CSVWorld::EditWidget::remake(int row) @@ -345,6 +353,7 @@ void CSVWorld::EditWidget::remake(int row) mWidgetMapper = 0; } mWidgetMapper = new QDataWidgetMapper (this); + mWidgetMapper->setModel(mTable); mWidgetMapper->setItemDelegate(&mDispatcher); @@ -536,10 +545,14 @@ void CSVWorld::DialogueSubView::prevId() if (!(state == CSMWorld::RecordBase::State_Deleted || state == CSMWorld::RecordBase::State_Erased)) { mEditWidget->remake(newRow); + setUniversalId(CSMWorld::UniversalId (static_cast (mTable->data (mTable->index (newRow, 2)).toInt()), mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); + mCurrentId = std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData()); + mEditWidget->setDisabled(mLocked); + return; } --newRow; @@ -568,10 +581,14 @@ void CSVWorld::DialogueSubView::nextId() if (!(state == CSMWorld::RecordBase::State_Deleted)) { mEditWidget->remake(newRow); + setUniversalId(CSMWorld::UniversalId (static_cast (mTable->data (mTable->index (newRow, 2)).toInt()), mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); + mCurrentId = std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData()); + mEditWidget->setDisabled(mLocked); + return; } ++newRow; @@ -620,6 +637,7 @@ void CSVWorld::DialogueSubView::tableMimeDataDropped(QWidget* editor, void CSVWorld::DialogueSubView::revertRecord() { const int rows = mTable->rowCount(); + QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); if (!currentIndex.isValid()) @@ -643,6 +661,7 @@ void CSVWorld::DialogueSubView::revertRecord() if (mTable->rowCount() == 0) { mEditWidget->setDisabled(true); //closing the editor is other option + return; } if (currentIndex.row() >= mTable->rowCount()) @@ -676,6 +695,7 @@ void CSVWorld::DialogueSubView::deleteRecord() if (mTable->rowCount() == 0) { mEditWidget->setDisabled(true); //closing the editor is other option + return; } if (currentIndex.row() >= mTable->rowCount()) @@ -691,6 +711,7 @@ void CSVWorld::DialogueSubView::deleteRecord() void CSVWorld::DialogueSubView::requestFocus (const std::string& id) { mCurrentId = std::string(id); + mEditWidget->remake(mTable->getModelIndex (id, 0).row()); } From 7eb82f74aecfc97cadc014c8f13bfaaf50661016 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 16 Jun 2014 10:22:14 +0200 Subject: [PATCH 012/740] Fixed complitaion. --- apps/opencs/view/world/dialoguesubview.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 9d6538c1c..e9910f42b 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -600,12 +600,12 @@ void CSVWorld::DialogueSubView::setEditLock (bool locked) mLocked = locked; QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); - mEditWidget->setDisabled (state==CSMWorld::RecordBase::State_Deleted || locked); - if (currentIndex.isValid()) { CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (currentIndex.row(), 1)).toInt()); + mEditWidget->setDisabled (state==CSMWorld::RecordBase::State_Deleted || locked); + mCommandDispatcher.setEditLock (locked); } @@ -615,11 +615,12 @@ void CSVWorld::DialogueSubView::dataChanged(const QModelIndex & index) { QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); - mEditWidget->setDisabled (state==CSMWorld::RecordBase::State_Deleted || mLocked); if (currentIndex.isValid() && index.row() == currentIndex.row()) { CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (currentIndex.row(), 1)).toInt()); + + mEditWidget->setDisabled (state==CSMWorld::RecordBase::State_Deleted || mLocked); } } From 786c68f09a2f31c699c7753faa785d117f18b0e5 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 16 Jun 2014 11:31:57 +0200 Subject: [PATCH 013/740] refactoring dialogue subview --- apps/opencs/view/world/dialoguesubview.cpp | 20 ++++++++++++++++---- apps/opencs/view/world/dialoguesubview.hpp | 3 +++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index e9910f42b..0f2ae73dd 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -448,7 +448,9 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType())) { connect(mTable, SIGNAL(dataChanged (const QModelIndex&, const QModelIndex&)), this, SLOT(dataChanged(const QModelIndex&))); - mCurrentId = id.getId(); + + changeCurrentId(id.getId()); + QWidget *mainWidget = new QWidget(this); QHBoxLayout *buttonsLayout = new QHBoxLayout; @@ -509,7 +511,9 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM new TableBottomBox (creatorFactory, document.getData(), document.getUndoStack(), id, this)); mBottom->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); + connect(mBottom, SIGNAL(requestFocus(const std::string&)), this, SLOT(requestFocus(const std::string&))); + connect(addButton, SIGNAL(clicked()), mBottom, SLOT(createRequest())); if(!mBottom->canCreateAndDelete()) @@ -549,7 +553,7 @@ void CSVWorld::DialogueSubView::prevId() setUniversalId(CSMWorld::UniversalId (static_cast (mTable->data (mTable->index (newRow, 2)).toInt()), mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); - mCurrentId = std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData()); + changeCurrentId(std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); mEditWidget->setDisabled(mLocked); @@ -585,7 +589,7 @@ void CSVWorld::DialogueSubView::nextId() setUniversalId(CSMWorld::UniversalId (static_cast (mTable->data (mTable->index (newRow, 2)).toInt()), mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); - mCurrentId = std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData()); + changeCurrentId(std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); mEditWidget->setDisabled(mLocked); @@ -615,7 +619,6 @@ void CSVWorld::DialogueSubView::dataChanged(const QModelIndex & index) { QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); - if (currentIndex.isValid() && index.row() == currentIndex.row()) { CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (currentIndex.row(), 1)).toInt()); @@ -746,3 +749,12 @@ void CSVWorld::DialogueSubView::viewRecord() emit focusId (params.first, params.second); } } + +void CSVWorld::DialogueSubView::changeCurrentId(const std::string& newId) +{ + std::vector selection; + mCurrentId = std::string(newId); + + selection.push_back(mCurrentId); + mCommandDispatcher.setSelection(selection); +} diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 2a9dd2e4f..2fdceacb1 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -181,6 +181,9 @@ namespace CSVWorld bool sorting = false); virtual void setEditLock (bool locked); + + private: + void changeCurrentId(const std::string& newCurrent); private slots: From d6288a805512b1113896c8f2d09b052045af7369 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 16 Jun 2014 11:58:55 +0200 Subject: [PATCH 014/740] Remove unneded revert and delete slots --- apps/opencs/view/world/dialoguesubview.cpp | 80 +--------------------- apps/opencs/view/world/dialoguesubview.hpp | 4 -- 2 files changed, 3 insertions(+), 81 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 0f2ae73dd..e798c8320 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -495,8 +495,8 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM connect(nextButton, SIGNAL(clicked()), this, SLOT(nextId())); connect(prevButton, SIGNAL(clicked()), this, SLOT(prevId())); connect(cloneButton, SIGNAL(clicked()), this, SLOT(cloneRequest())); - connect(revertButton, SIGNAL(clicked()), this, SLOT(revertRecord())); - connect(deleteButton, SIGNAL(clicked()), this, SLOT(deleteRecord())); + connect(revertButton, SIGNAL(clicked()), &mCommandDispatcher, SLOT(executeRevert())); + connect(deleteButton, SIGNAL(clicked()), &mCommandDispatcher, SLOT(executeDelete())); mMainLayout = new QVBoxLayout(mainWidget); @@ -638,83 +638,9 @@ void CSVWorld::DialogueSubView::tableMimeDataDropped(QWidget* editor, } } -void CSVWorld::DialogueSubView::revertRecord() -{ - const int rows = mTable->rowCount(); - - QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); - - if (!currentIndex.isValid()) - { - return; - } - - const int currentRow = currentIndex.row(); - - if (!mLocked && mTable->columnCount() > 0 && currentRow < mTable->rowCount() ) - { - CSMWorld::RecordBase::State state = - static_cast (mTable->data (mTable->index (currentRow, 1)).toInt()); - - if (state!=CSMWorld::RecordBase::State_BaseOnly) - { - mUndoStack.push(new CSMWorld::RevertCommand(*mTable, mCurrentId)); - } - if (rows != mTable->rowCount()) - { - if (mTable->rowCount() == 0) - { - mEditWidget->setDisabled(true); //closing the editor is other option - - return; - } - if (currentIndex.row() >= mTable->rowCount()) - { - prevId(); - } else { - dataChanged(currentIndex); - } - } - } -} - -void CSVWorld::DialogueSubView::deleteRecord() -{ - const int rows = mTable->rowCount(); - QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); - - CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (currentIndex.row(), 1)).toInt()); - bool deledetedOrErased = (state == CSMWorld::RecordBase::State_Deleted); - - if (!mLocked && - currentIndex.isValid() && - mTable->columnCount() > 0 && - !deledetedOrErased && - currentIndex.row() < rows && - mBottom->canCreateAndDelete()) - { - mUndoStack.push(new CSMWorld::DeleteCommand(*mTable, mCurrentId)); - if (rows != mTable->rowCount()) - { - if (mTable->rowCount() == 0) - { - mEditWidget->setDisabled(true); //closing the editor is other option - - return; - } - if (currentIndex.row() >= mTable->rowCount()) - { - prevId(); - } else { - dataChanged(currentIndex); - } - } - } -} - void CSVWorld::DialogueSubView::requestFocus (const std::string& id) { - mCurrentId = std::string(id); + changeCurrentId(id); mEditWidget->remake(mTable->getModelIndex (id, 0).row()); } diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 2fdceacb1..050aad947 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -195,10 +195,6 @@ namespace CSVWorld void viewRecord(); - void revertRecord(); - - void deleteRecord(); - void cloneRequest(); void dataChanged(const QModelIndex & index); From bbe7854968d5ecb44b767bc1b64963fd8bceddcc Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 17 Jun 2014 10:46:54 +0200 Subject: [PATCH 015/740] Corrected formatting to follow our standard better. --- apps/opencs/view/world/dialoguesubview.cpp | 32 +++++++++++----------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index e798c8320..bc2a6048a 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -518,17 +518,17 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM if(!mBottom->canCreateAndDelete()) { - cloneButton->setDisabled(true); - addButton->setDisabled(true); - deleteButton->setDisabled(true); + cloneButton->setDisabled (true); + addButton->setDisabled (true); + deleteButton->setDisabled (true); } - dataChanged(mTable->getModelIndex(mCurrentId, 0)); - mMainLayout->addLayout(buttonsLayout); - setWidget(mainWidget); + dataChanged(mTable->getModelIndex (mCurrentId, 0)); + mMainLayout->addLayout (buttonsLayout); + setWidget (mainWidget); } -void CSVWorld::DialogueSubView::prevId() +void CSVWorld::DialogueSubView::prevId () { int newRow = mTable->getModelIndex(mCurrentId, 0).row() - 1; @@ -563,7 +563,7 @@ void CSVWorld::DialogueSubView::prevId() } } -void CSVWorld::DialogueSubView::nextId() +void CSVWorld::DialogueSubView::nextId () { int newRow = mTable->getModelIndex(mCurrentId, 0).row() + 1; @@ -615,7 +615,7 @@ void CSVWorld::DialogueSubView::setEditLock (bool locked) } -void CSVWorld::DialogueSubView::dataChanged(const QModelIndex & index) +void CSVWorld::DialogueSubView::dataChanged (const QModelIndex & index) { QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); @@ -627,10 +627,10 @@ void CSVWorld::DialogueSubView::dataChanged(const QModelIndex & index) } } -void CSVWorld::DialogueSubView::tableMimeDataDropped(QWidget* editor, - const QModelIndex& index, - const CSMWorld::UniversalId& id, - const CSMDoc::Document* document) +void CSVWorld::DialogueSubView::tableMimeDataDropped (QWidget* editor, + const QModelIndex& index, + const CSMWorld::UniversalId& id, + const CSMDoc::Document* document) { if (document == &mDocument) { @@ -662,9 +662,9 @@ void CSVWorld::DialogueSubView::showPreview () } } -void CSVWorld::DialogueSubView::viewRecord() +void CSVWorld::DialogueSubView::viewRecord () { - QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); + QModelIndex currentIndex(mTable->getModelIndex (mCurrentId, 0)); if (currentIndex.isValid() && currentIndex.row() < mTable->rowCount()) @@ -676,7 +676,7 @@ void CSVWorld::DialogueSubView::viewRecord() } } -void CSVWorld::DialogueSubView::changeCurrentId(const std::string& newId) +void CSVWorld::DialogueSubView::changeCurrentId (const std::string& newId) { std::vector selection; mCurrentId = std::string(newId); From 32fcc9ad6194533f7e367f46ae500c133cffb102 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 17 Jun 2014 11:14:12 +0200 Subject: [PATCH 016/740] Trying to merge. --- apps/opencs/model/world/idtable.cpp | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 59fc3a508..cbfb7f923 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -43,9 +43,6 @@ QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const if (role==Qt::EditRole && !mIdCollection->getColumn (index.column()).isEditable()) return QVariant(); -<<<<<<< Updated upstream - return mIdCollection->getData (index.row(), index.column()); -======= if (index.internalId() != 0) { std::pair parentAdress(unfoldIndexAdress(index.internalId())); @@ -53,7 +50,6 @@ QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const } else { return mIdCollection->getData (index.row(), index.column()); } ->>>>>>> Stashed changes } QVariant CSMWorld::IdTable::headerData (int section, Qt::Orientation orientation, int role) const @@ -135,9 +131,6 @@ QModelIndex CSMWorld::IdTable::index (int row, int column, const QModelIndex& pa QModelIndex CSMWorld::IdTable::parent (const QModelIndex& index) const { -<<<<<<< Updated upstream - return QModelIndex(); -======= if (index.internalId() == 0) //0 is used for indexs with invalid parent (top level data) { return QModelIndex(); @@ -151,7 +144,6 @@ QModelIndex CSMWorld::IdTable::parent (const QModelIndex& index) const throw "Parent index is not present in the model"; } return createIndex(adress.first, adress.second, 0); ->>>>>>> Stashed changes } void CSMWorld::IdTable::addRecord (const std::string& id, UniversalId::Type type) @@ -280,9 +272,6 @@ std::pair CSMWorld::IdTable::view (int row) int CSMWorld::IdTable::getColumnId(int column) const { return mIdCollection->getColumn(column).getId(); -<<<<<<< Updated upstream -} -======= } bool CSMWorld::IdTable::hasChildren(const QModelIndex& index) const @@ -313,4 +302,3 @@ std::pair< int, int > CSMWorld::IdTable::unfoldIndexAdress (unsigned int id) con int column = id - row * this->columnCount(); return std::make_pair(row, column); } ->>>>>>> Stashed changes From 5bee682bb3dce1ccddddcb6bb4cf82e7055c2564 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 17 Jun 2014 14:58:25 +0200 Subject: [PATCH 017/740] modified: ../../view/world/dialoguesubview.cpp --- apps/opencs/model/world/idtable.cpp | 2 +- apps/opencs/model/world/refidadapterimp.hpp | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 2a0ba43ea..7db4662ba 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -42,7 +42,7 @@ QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const if (role==Qt::EditRole && !mIdCollection->getColumn (index.column()).isEditable()) return QVariant(); - if (index.hasChildren()) + if (hasChildren(index)) { std::pair parentAdress(unfoldIndexAdress(index.internalId())); return mIdCollection->getNestedData(parentAdress.first, parentAdress.second, index.row(), index.column()); diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index cde5dc455..a01e59371 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -624,11 +624,7 @@ namespace CSMWorld virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; virtual void setNestedData (const RefIdColumn *column, RefIdData& data, int index, -<<<<<<< HEAD const QVariant& value, int subRowIndex, int subColIndex) const; -======= - const QVariant& value, int subRowIndex, int subColIndex) const; ->>>>>>> 187fccc8cc630f1f469b4f5fc4e23a28ad8253ec virtual void setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const; From ce5e889015ca9d8b585db2f1f24854e854ff5064 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 17 Jun 2014 18:28:49 +0200 Subject: [PATCH 018/740] Nested table sits inside it's own layout now. --- apps/opencs/model/world/idtable.cpp | 25 ++++---- apps/opencs/model/world/refidcollection.cpp | 3 +- apps/opencs/view/world/dialoguesubview.cpp | 59 +++++++++---------- apps/opencs/view/world/dialoguesubview.hpp | 64 ++++++++++++++------- 4 files changed, 88 insertions(+), 63 deletions(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 7db4662ba..49d23bed4 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -1,4 +1,3 @@ - #include "idtable.hpp" #include @@ -17,8 +16,7 @@ int CSMWorld::IdTable::rowCount (const QModelIndex & parent) const { if (hasChildren(parent)) { - int nestedRows = mIdCollection->getNestedRowsCount(parent.row(), parent.column()); - return nestedRows; + return mIdCollection->getNestedRowsCount(parent.row(), parent.column()); } return mIdCollection->getSize(); @@ -26,7 +24,8 @@ int CSMWorld::IdTable::rowCount (const QModelIndex & parent) const int CSMWorld::IdTable::columnCount (const QModelIndex & parent) const { - if (parent.isValid()) + if (parent.isValid() && + parent.data().isValid()) { return mIdCollection->getNestedColumnsCount(parent.row(), parent.column()); } @@ -42,16 +41,21 @@ QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const if (role==Qt::EditRole && !mIdCollection->getColumn (index.column()).isEditable()) return QVariant(); - if (hasChildren(index)) + if (index.internalId() != 0) { std::pair parentAdress(unfoldIndexAdress(index.internalId())); - return mIdCollection->getNestedData(parentAdress.first, parentAdress.second, index.row(), index.column()); + return mIdCollection->getNestedData(parentAdress.first, + parentAdress.second, + index.row(), + index.column()); } else { return mIdCollection->getData (index.row(), index.column()); } } -QVariant CSMWorld::IdTable::headerData (int section, Qt::Orientation orientation, int role) const +QVariant CSMWorld::IdTable::headerData (int section, + Qt::Orientation orientation, + int role) const { if (orientation==Qt::Vertical) return QVariant(); @@ -68,7 +72,7 @@ QVariant CSMWorld::IdTable::headerData (int section, Qt::Orientation orientation return QVariant(); } -bool CSMWorld::IdTable::setData ( const QModelIndex &index, const QVariant &value, int role) +bool CSMWorld::IdTable::setData (const QModelIndex &index, const QVariant &value, int role) { if (mIdCollection->getColumn (index.column()).isEditable() && role==Qt::EditRole) { @@ -291,10 +295,7 @@ std::pair< int, int > CSMWorld::IdTable::unfoldIndexAdress (unsigned int id) con bool CSMWorld::IdTable::hasChildren(const QModelIndex& index) const { return (index.isValid() && - CSMWorld::ColumnBase::Display_Nested == static_cast (headerData - (index.column(), - Qt::Horizontal, - CSMWorld::ColumnBase::Role_Display).toInt()) && + CSMWorld::ColumnBase::Display_Nested == static_cast (headerData (index.column(), Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()) && index.internalId() == 0 && index.data().isValid()); } diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index ad7fbd049..936663399 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -601,8 +601,7 @@ int CSMWorld::RefIdCollection::getNestedRowsCount(int row, int column) const const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdaptor (localIndex.second)); - const int count = adaptor.getNestedRowsCount(&mColumns.at(column), mData, localIndex.first); - return count; + return adaptor.getNestedRowsCount(&mColumns.at(column), mData, localIndex.first); } int CSMWorld::RefIdCollection::getNestedColumnsCount(int row, int column) const diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index a9a1bb96e..08bac8b08 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "../../model/world/columnbase.hpp" #include "../../model/world/idtable.hpp" @@ -133,25 +134,25 @@ void CSVWorld::DialogueDelegateDispatcherProxy::tableMimeDataDropped(const std:: if (mDisplay == CSMWorld::ColumnBase::Display_Referenceable) { if ( type == CSMWorld::UniversalId::Type_Activator - || type == CSMWorld::UniversalId::Type_Potion - || type == CSMWorld::UniversalId::Type_Apparatus - || type == CSMWorld::UniversalId::Type_Armor - || type == CSMWorld::UniversalId::Type_Book - || type == CSMWorld::UniversalId::Type_Clothing - || type == CSMWorld::UniversalId::Type_Container - || type == CSMWorld::UniversalId::Type_Creature - || type == CSMWorld::UniversalId::Type_Door - || type == CSMWorld::UniversalId::Type_Ingredient - || type == CSMWorld::UniversalId::Type_CreatureLevelledList - || type == CSMWorld::UniversalId::Type_ItemLevelledList - || type == CSMWorld::UniversalId::Type_Light - || type == CSMWorld::UniversalId::Type_Lockpick - || type == CSMWorld::UniversalId::Type_Miscellaneous - || type == CSMWorld::UniversalId::Type_Npc - || type == CSMWorld::UniversalId::Type_Probe - || type == CSMWorld::UniversalId::Type_Repair - || type == CSMWorld::UniversalId::Type_Static - || type == CSMWorld::UniversalId::Type_Weapon) + || type == CSMWorld::UniversalId::Type_Potion + || type == CSMWorld::UniversalId::Type_Apparatus + || type == CSMWorld::UniversalId::Type_Armor + || type == CSMWorld::UniversalId::Type_Book + || type == CSMWorld::UniversalId::Type_Clothing + || type == CSMWorld::UniversalId::Type_Container + || type == CSMWorld::UniversalId::Type_Creature + || type == CSMWorld::UniversalId::Type_Door + || type == CSMWorld::UniversalId::Type_Ingredient + || type == CSMWorld::UniversalId::Type_CreatureLevelledList + || type == CSMWorld::UniversalId::Type_ItemLevelledList + || type == CSMWorld::UniversalId::Type_Light + || type == CSMWorld::UniversalId::Type_Lockpick + || type == CSMWorld::UniversalId::Type_Miscellaneous + || type == CSMWorld::UniversalId::Type_Npc + || type == CSMWorld::UniversalId::Type_Probe + || type == CSMWorld::UniversalId::Type_Repair + || type == CSMWorld::UniversalId::Type_Static + || type == CSMWorld::UniversalId::Type_Weapon) { type = CSMWorld::UniversalId::Type_Referenceable; } @@ -304,7 +305,7 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: } //lisp cond pairs would be nice in the C++ connect(proxy, SIGNAL(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display)), - this, SLOT(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display))); + this, SLOT(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display))); mProxys.push_back(proxy); //deleted in the destructor } @@ -334,7 +335,7 @@ mTable(table) remake (row); connect(&mDispatcher, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), - this, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); + this, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); } void CSVWorld::EditWidget::remake(int row) @@ -366,9 +367,12 @@ void CSVWorld::EditWidget::remake(int row) QVBoxLayout *mainLayout = new QVBoxLayout(mMainWidget); QGridLayout *unlockedLayout = new QGridLayout(); QGridLayout *lockedLayout = new QGridLayout(); + QVBoxLayout *tablesLayout = new QVBoxLayout(); + mainLayout->addLayout(lockedLayout, 0); mainLayout->addWidget(line, 1); mainLayout->addLayout(unlockedLayout, 2); + mainLayout->addLayout(tablesLayout, 3); mainLayout->addStretch(1); int unlocked = 0; @@ -384,15 +388,12 @@ void CSVWorld::EditWidget::remake(int row) CSMWorld::ColumnBase::Display display = static_cast (mTable->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); - if (display == CSMWorld::ColumnBase::Display_Nested) + if (mTable->hasChildren(mTable->index(row, i))) { - const QModelIndex& parent = mTable->index(row, i); - if (parent.data().isValid() && mTable->hasChildren(parent)) - { - QTableView* table = new QTableView(this); - table->setModel(mTable); - table->setRootIndex(mTable->index(row, i)); - } + QTableView* table = new QTableView(); + table->setModel(mTable); + table->setRootIndex(mTable->index(row, i)); + tablesLayout->addWidget(table); } else { mDispatcher.makeDelegate (display); diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 050aad947..f36785e88 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -38,16 +38,23 @@ namespace CSVWorld { const CSMWorld::IdTable* mTable; public: - NotEditableSubDelegate(const CSMWorld::IdTable* table, QObject * parent = 0); + NotEditableSubDelegate(const CSMWorld::IdTable* table, + QObject * parent = 0); - virtual void setEditorData (QLabel* editor, const QModelIndex& index) const; + virtual void setEditorData (QLabel* editor, + const QModelIndex& index) const; - virtual void setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const; + virtual void setModelData (QWidget* editor, QAbstractItemModel* model, + const QModelIndex& index, + CSMWorld::ColumnBase::Display display) const; - virtual void paint (QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; + virtual void paint (QPainter* painter, + const QStyleOptionViewItem& option, + const QModelIndex& index) const; ///< does nothing - virtual QSize sizeHint (const QStyleOptionViewItem& option, const QModelIndex& index) const; + virtual QSize sizeHint (const QStyleOptionViewItem& option, + const QModelIndex& index) const; ///< does nothing virtual QWidget *createEditor (QWidget *parent, @@ -75,16 +82,20 @@ namespace CSVWorld std::auto_ptr mIndexWrapper; public: - DialogueDelegateDispatcherProxy(QWidget* editor, CSMWorld::ColumnBase::Display display); + DialogueDelegateDispatcherProxy(QWidget* editor, + CSMWorld::ColumnBase::Display display); QWidget* getEditor() const; public slots: void editorDataCommited(); void setIndex(const QModelIndex& index); - void tableMimeDataDropped(const std::vector& data, const CSMDoc::Document* document); + void tableMimeDataDropped(const std::vector& data, + const CSMDoc::Document* document); signals: - void editorDataCommited(QWidget* editor, const QModelIndex& index, CSMWorld::ColumnBase::Display display); + void editorDataCommited(QWidget* editor, + const QModelIndex& index, + CSMWorld::ColumnBase::Display display); void tableMimeDataDropped(QWidget* editor, const QModelIndex& index, const CSMWorld::UniversalId& id, @@ -105,30 +116,42 @@ namespace CSVWorld NotEditableSubDelegate mNotEditableDelegate; - std::vector mProxys; //once we move to the C++11 we should use unique_ptr + std::vector mProxys; +//once we move to the C++11 we should use unique_ptr public: - DialogueDelegateDispatcher(QObject* parent, CSMWorld::IdTable* table, QUndoStack& undoStack); + DialogueDelegateDispatcher(QObject* parent, + CSMWorld::IdTable* table, + QUndoStack& undoStack); ~DialogueDelegateDispatcher(); CSVWorld::CommandDelegate* makeDelegate(CSMWorld::ColumnBase::Display display); - QWidget* makeEditor(CSMWorld::ColumnBase::Display display, const QModelIndex& index); + QWidget* makeEditor(CSMWorld::ColumnBase::Display display, + const QModelIndex& index); ///< will return null if delegate is not present, parent of the widget is same as for dispatcher itself - virtual void setEditorData (QWidget* editor, const QModelIndex& index) const; + virtual void setEditorData (QWidget* editor, + const QModelIndex& index) const; - virtual void setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const; + virtual void setModelData (QWidget* editor, + QAbstractItemModel* model, + const QModelIndex& index, + CSMWorld::ColumnBase::Display display) const; - virtual void paint (QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; + virtual void paint (QPainter* painter, + const QStyleOptionViewItem& option, + const QModelIndex& index) const; ///< does nothing - virtual QSize sizeHint (const QStyleOptionViewItem& option, const QModelIndex& index) const; + virtual QSize sizeHint (const QStyleOptionViewItem& option, + const QModelIndex& index) const; ///< does nothing private slots: - void editorDataCommited(QWidget* editor, const QModelIndex& index, CSMWorld::ColumnBase::Display display); + void editorDataCommited(QWidget* editor, const QModelIndex& index, + CSMWorld::ColumnBase::Display display); signals: void tableMimeDataDropped(QWidget* editor, const QModelIndex& index, @@ -149,7 +172,8 @@ namespace CSVWorld public: - EditWidget (QWidget *parent, int row, CSMWorld::IdTable* table, QUndoStack& undoStack, bool createAndDelete = false); + EditWidget (QWidget *parent, int row, CSMWorld::IdTable* table, + QUndoStack& undoStack, bool createAndDelete = false); void remake(int row); @@ -167,7 +191,7 @@ namespace CSVWorld QVBoxLayout* mMainLayout; CSMWorld::IdTable* mTable; QUndoStack& mUndoStack; - std::string mCurrentId; + std::string mCurrentId; bool mLocked; const CSMDoc::Document& mDocument; TableBottomBox* mBottom; @@ -181,9 +205,9 @@ namespace CSVWorld bool sorting = false); virtual void setEditLock (bool locked); - + private: - void changeCurrentId(const std::string& newCurrent); + void changeCurrentId(const std::string& newCurrent); private slots: From 75b5513c6c4d6f59eced88b4e60deae43ad218fb Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 17 Jun 2014 22:02:20 +0200 Subject: [PATCH 019/740] Column is responsible for telling that it can nest columns now. --- apps/opencs/model/world/columnbase.cpp | 11 ++++++++--- apps/opencs/model/world/columnbase.hpp | 11 +++++++---- apps/opencs/model/world/idtable.cpp | 4 +--- apps/opencs/model/world/refidcollection.cpp | 6 +++--- apps/opencs/model/world/refidcollection.hpp | 4 ++-- 5 files changed, 21 insertions(+), 15 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index f6363fe2e..e81943843 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -3,8 +3,8 @@ #include "columns.hpp" -CSMWorld::ColumnBase::ColumnBase (int columnId, Display displayType, int flags) -: mColumnId (columnId), mDisplayType (displayType), mFlags (flags) +CSMWorld::ColumnBase::ColumnBase (int columnId, Display displayType, int flags, bool canNest) + : mColumnId (columnId), mDisplayType (displayType), mFlags (flags), mCanNest(canNest) {} CSMWorld::ColumnBase::~ColumnBase() {} @@ -22,4 +22,9 @@ std::string CSMWorld::ColumnBase::getTitle() const int CSMWorld::ColumnBase::getId() const { return mColumnId; -} \ No newline at end of file +} + +bool CSMWorld::ColumnBase::canHaveNestedColumns() const +{ + return mCanNest; +} diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index c8670a03b..9761b95aa 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -91,14 +91,15 @@ namespace CSMWorld Display_QuestStatusType, Display_Gender, - Display_Nested + Display_NestedItemList }; int mColumnId; int mFlags; Display mDisplayType; + const bool mCanNest; - ColumnBase (int columnId, Display displayType, int flag); + ColumnBase (int columnId, Display displayType, int flag, bool canNest = false); virtual ~ColumnBase(); @@ -110,6 +111,8 @@ namespace CSMWorld virtual std::string getTitle() const; virtual int getId() const; + + bool canHaveNestedColumns() const; }; template @@ -117,8 +120,8 @@ namespace CSMWorld { int mFlags; - Column (int columnId, Display displayType, int flags = Flag_Table | Flag_Dialogue) - : ColumnBase (columnId, displayType, flags) {} + Column (int columnId, Display displayType, int flags = Flag_Table | Flag_Dialogue, bool canNest = false) + : ColumnBase (columnId, displayType, flags, canNest) {} virtual QVariant get (const Record& record) const = 0; diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 49d23bed4..6aba322c1 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -1,7 +1,5 @@ #include "idtable.hpp" -#include - #include "collectionbase.hpp" #include "columnbase.hpp" @@ -295,7 +293,7 @@ std::pair< int, int > CSMWorld::IdTable::unfoldIndexAdress (unsigned int id) con bool CSMWorld::IdTable::hasChildren(const QModelIndex& index) const { return (index.isValid() && - CSMWorld::ColumnBase::Display_Nested == static_cast (headerData (index.column(), Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()) && index.internalId() == 0 && + mIdCollection->getColumn (index.column()).canHaveNestedColumns() && index.data().isValid()); } diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 936663399..a8fac216b 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -12,8 +12,8 @@ #include "columns.hpp" CSMWorld::RefIdColumn::RefIdColumn (int columnId, Display displayType, int flag, - bool editable, bool userEditable) -: ColumnBase (columnId, displayType, flag), mEditable (editable), mUserEditable (userEditable) + bool editable, bool userEditable, bool canNest) + : ColumnBase (columnId, displayType, flag, canNest), mEditable (editable), mUserEditable (userEditable) {} bool CSMWorld::RefIdColumn::isEditable() const @@ -166,7 +166,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.push_back (RefIdColumn (Columns::ColumnId_Respawn, ColumnBase::Display_Boolean)); const RefIdColumn *respawn = &mColumns.back(); - mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent, ColumnBase::Display_Nested, ColumnBase::Flag_Dialogue, false, false)); + mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue, true, true, true)); const RefIdColumn *content = &mColumns.back(); CreatureColumns creatureColumns (actorsColumns); diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index cb0baa45b..fec621ac1 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -26,8 +26,8 @@ namespace CSMWorld public: RefIdColumn (int columnId, Display displayType, - int flag = Flag_Table | Flag_Dialogue, bool editable = true, - bool userEditable = true); + int flag = Flag_Table | Flag_Dialogue, bool editable = true, + bool userEditable = true, bool canNest = false); virtual bool isEditable() const; From 1fb18873cbe88d3e41c6e66c1a4fce7132d72c11 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Wed, 18 Jun 2014 15:35:31 +0200 Subject: [PATCH 020/740] adding proxy model that is ment to be used by the dialoguesubview --- apps/opencs/CMakeLists.txt | 1 + apps/opencs/model/world/columns.hpp | 1 + apps/opencs/model/world/nestedtablemodel.cpp | 34 ++++++++++++++++ apps/opencs/model/world/nestedtablemodel.hpp | 42 ++++++++++++++++++++ 4 files changed, 78 insertions(+) create mode 100644 apps/opencs/model/world/nestedtablemodel.cpp create mode 100644 apps/opencs/model/world/nestedtablemodel.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index d9cac95f3..e76e64610 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -19,6 +19,7 @@ opencs_hdrs_noqt (model/doc opencs_units (model/world idtable idtableproxymodel regionmap data commanddispatcher + nestedtablemodel ) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index fa9c92e7d..e824c4392 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -168,6 +168,7 @@ namespace CSMWorld ColumnId_Scope = 155, ColumnId_ReferenceableId = 156, ColumnId_ContainerContent = 157, + ColumnId_ItemCount = 158, // 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/nestedtablemodel.cpp b/apps/opencs/model/world/nestedtablemodel.cpp new file mode 100644 index 000000000..20a68faad --- /dev/null +++ b/apps/opencs/model/world/nestedtablemodel.cpp @@ -0,0 +1,34 @@ +#include "nestedtablemodel.hpp" + +#include "./idtable.hpp" + +CSMWorld::NestedTableModel::NestedTableModel(const QModelIndex& parent, + ColumnBase::Display columnId, + CSMWorld::IdTable* parentModel) + : mParentColumn(parent.column()) +{ + const int parentRow = parent.row(); + mId = std::string(parentModel->index(parentRow, 0).data().toString().toUtf8()); + QAbstractProxyModel::setSourceModel(parentModel); +} + +QModelIndex CSMWorld::NestedTableModel::mapFromSource(const QModelIndex& sourceIndex) const +{ + const QModelIndex& testedParent = sourceModel()->parent(sourceIndex); + const QModelIndex& parent = dynamic_cast(sourceModel())->getModelIndex (mId, mParentColumn); + if (testedParent == parent) + { + return createIndex(sourceIndex.row(), sourceIndex.column()); + } + else + { + return QModelIndex(); + } + +} + +QModelIndex CSMWorld::NestedTableModel::mapToSource(const QModelIndex& proxyIndex) const +{ + const QModelIndex& parent = dynamic_cast(sourceModel())->getModelIndex (mId, mParentColumn); + return sourceModel()->index(proxyIndex.row(), proxyIndex.column(), parent); +} diff --git a/apps/opencs/model/world/nestedtablemodel.hpp b/apps/opencs/model/world/nestedtablemodel.hpp new file mode 100644 index 000000000..acab1f851 --- /dev/null +++ b/apps/opencs/model/world/nestedtablemodel.hpp @@ -0,0 +1,42 @@ + +#ifndef CSM_WOLRD_NESTEDTABLEMODEL_H +#define CSM_WOLRD_NESTEDTABLEMODEL_H + +#include + +#include + +#include "universalid.hpp" +#include "columns.hpp" +#include "columnbase.hpp" + +/*! \brief + * Proxy model used to connect view in the dialogue into the nested columns of the main model. + */ + +namespace CSMWorld +{ + class CollectionBase; + class RecordBase; + class IdTable; + + class NestedTableModel : public QAbstractProxyModel + { + const int mParentColumn; + std::string mId; + std::vector mHeaderTitle; + std::vector mHeaderDisplay; + + public: + NestedTableModel(const QModelIndex& parent, + ColumnBase::Display displayType, + IdTable* parentModel); + //parent is the parent of columns to work with. Columnid provides information about the column + + virtual QModelIndex mapFromSource(const QModelIndex& sourceIndex) const; + + virtual QModelIndex mapToSource(const QModelIndex& proxyIndex) const; + }; +} + +#endif From b63f2f4cd538651643d9084f89d30cebbdcee89d Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Wed, 18 Jun 2014 16:53:46 +0200 Subject: [PATCH 021/740] Actually using new nestedmodel --- apps/opencs/model/world/nestedtablemodel.cpp | 48 +++++++++++++++++++- apps/opencs/model/world/nestedtablemodel.hpp | 15 ++++-- apps/opencs/view/world/dialoguesubview.cpp | 23 ++++++++-- apps/opencs/view/world/dialoguesubview.hpp | 4 ++ 4 files changed, 81 insertions(+), 9 deletions(-) diff --git a/apps/opencs/model/world/nestedtablemodel.cpp b/apps/opencs/model/world/nestedtablemodel.cpp index 20a68faad..9a685557e 100644 --- a/apps/opencs/model/world/nestedtablemodel.cpp +++ b/apps/opencs/model/world/nestedtablemodel.cpp @@ -1,10 +1,11 @@ #include "nestedtablemodel.hpp" +#include #include "./idtable.hpp" CSMWorld::NestedTableModel::NestedTableModel(const QModelIndex& parent, ColumnBase::Display columnId, - CSMWorld::IdTable* parentModel) + CSMWorld::IdTable* parentModel) : mParentColumn(parent.column()) { const int parentRow = parent.row(); @@ -20,7 +21,7 @@ QModelIndex CSMWorld::NestedTableModel::mapFromSource(const QModelIndex& sourceI { return createIndex(sourceIndex.row(), sourceIndex.column()); } - else + else { return QModelIndex(); } @@ -32,3 +33,46 @@ QModelIndex CSMWorld::NestedTableModel::mapToSource(const QModelIndex& proxyInde const QModelIndex& parent = dynamic_cast(sourceModel())->getModelIndex (mId, mParentColumn); return sourceModel()->index(proxyIndex.row(), proxyIndex.column(), parent); } + +int CSMWorld::NestedTableModel::rowCount(const QModelIndex& index) const +{ + assert (!index.isValid()); + + CSMWorld::IdTable* table = dynamic_cast(sourceModel()); + + return table->rowCount(table->getModelIndex(mId, mParentColumn)); +} + +int CSMWorld::NestedTableModel::columnCount(const QModelIndex& parent) const +{ + assert (!parent.isValid()); + + CSMWorld::IdTable* table = dynamic_cast(sourceModel()); + + return table->columnCount(table->getModelIndex(mId, mParentColumn)); +} + +QModelIndex CSMWorld::NestedTableModel::index(int row, int column, const QModelIndex& parent) const +{ + assert (!parent.isValid()); + + CSMWorld::IdTable* table = dynamic_cast(sourceModel()); + + unsigned rows = table->rowCount(parent); + usigned columns = table->columnCount(parent); + + if (row < 0 || + row >= rows || + column < 0 || + column >= columns) + { + return QModelIndex(); + } + + return createIndex(row, column); +} + +QModelIndex CSMWorld::NestedTableModel::parent(const QModelIndex& index) const +{ + return QModelIndex(); +} diff --git a/apps/opencs/model/world/nestedtablemodel.hpp b/apps/opencs/model/world/nestedtablemodel.hpp index acab1f851..be29be2ca 100644 --- a/apps/opencs/model/world/nestedtablemodel.hpp +++ b/apps/opencs/model/world/nestedtablemodel.hpp @@ -1,4 +1,3 @@ - #ifndef CSM_WOLRD_NESTEDTABLEMODEL_H #define CSM_WOLRD_NESTEDTABLEMODEL_H @@ -26,16 +25,24 @@ namespace CSMWorld std::string mId; std::vector mHeaderTitle; std::vector mHeaderDisplay; - + public: NestedTableModel(const QModelIndex& parent, ColumnBase::Display displayType, IdTable* parentModel); //parent is the parent of columns to work with. Columnid provides information about the column - + virtual QModelIndex mapFromSource(const QModelIndex& sourceIndex) const; - + virtual QModelIndex mapToSource(const QModelIndex& proxyIndex) const; + + virtual int rowCount(const QModelIndex& parent) const; + + virtual int columnCount(const QModelIndex& parent) const; + + virtual QModelIndex index(int row, int column, const QModelIndex& parent) const; + + virtual QModelIndex parent(const QModelIndex& index) const; }; } diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 08bac8b08..7a0e2efec 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -22,6 +22,7 @@ #include #include +#include "../../model/world/nestedtablemodel.hpp" #include "../../model/world/columnbase.hpp" #include "../../model/world/idtable.hpp" #include "../../model/world/columns.hpp" @@ -324,6 +325,14 @@ CSVWorld::DialogueDelegateDispatcher::~DialogueDelegateDispatcher() =============================================================EditWidget===================================================== */ +CSVWorld::EditWidget::~EditWidget() +{ + for (unsigned i = 0; i < mNestedModels.size(); ++i) + { + delete mNestedModels[i]; + } +} + CSVWorld::EditWidget::EditWidget(QWidget *parent, int row, CSMWorld::IdTable* table, QUndoStack& undoStack, bool createAndDelete) : mDispatcher(this, table, undoStack), QScrollArea(parent), @@ -340,6 +349,11 @@ mTable(table) void CSVWorld::EditWidget::remake(int row) { + for (unsigned i = 0; i < mNestedModels.size(); ++i) + { + delete mNestedModels[i]; + } + if (mMainWidget) { delete mMainWidget; @@ -379,7 +393,7 @@ void CSVWorld::EditWidget::remake(int row) int locked = 0; const int columns = mTable->columnCount(); - for (int i=0; iheaderData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt(); @@ -390,9 +404,12 @@ void CSVWorld::EditWidget::remake(int row) if (mTable->hasChildren(mTable->index(row, i))) { + mNestedModels.push_back(new CSMWorld::NestedTableModel (mTable->index(row, i), display, mTable)); + QTableView* table = new QTableView(); - table->setModel(mTable); - table->setRootIndex(mTable->index(row, i)); + + table->setModel(*(mNestedModels.rbegin())); + tablesLayout->addWidget(table); } else { diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index f36785e88..90a365592 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -21,6 +21,7 @@ class QVBoxLayout; namespace CSMWorld { class IdTable; + class NestedTableModel; } namespace CSMDoc @@ -169,12 +170,15 @@ namespace CSVWorld QWidget* mMainWidget; CSMWorld::IdTable* mTable; QUndoStack& mUndoStack; + std::vector mNestedModels; //Plain, raw C pointers, deleted in the dtor public: EditWidget (QWidget *parent, int row, CSMWorld::IdTable* table, QUndoStack& undoStack, bool createAndDelete = false); + ~EditWidget(); + void remake(int row); signals: From 873cfcf447136b4e442b550c48573d8efc55ad47 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Wed, 18 Jun 2014 17:34:21 +0200 Subject: [PATCH 022/740] implemented basic headerData (still work in progress) --- apps/opencs/model/world/nestedtablemodel.cpp | 44 +++++++++++++++++++- apps/opencs/model/world/nestedtablemodel.hpp | 5 +++ apps/opencs/view/world/dialoguesubview.cpp | 2 +- 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/nestedtablemodel.cpp b/apps/opencs/model/world/nestedtablemodel.cpp index 9a685557e..9ae4bdfd3 100644 --- a/apps/opencs/model/world/nestedtablemodel.cpp +++ b/apps/opencs/model/world/nestedtablemodel.cpp @@ -9,8 +9,12 @@ CSMWorld::NestedTableModel::NestedTableModel(const QModelIndex& parent, : mParentColumn(parent.column()) { const int parentRow = parent.row(); + mId = std::string(parentModel->index(parentRow, 0).data().toString().toUtf8()); + QAbstractProxyModel::setSourceModel(parentModel); + + setupHeaderVectors(columnId); } QModelIndex CSMWorld::NestedTableModel::mapFromSource(const QModelIndex& sourceIndex) const @@ -58,8 +62,8 @@ QModelIndex CSMWorld::NestedTableModel::index(int row, int column, const QModelI CSMWorld::IdTable* table = dynamic_cast(sourceModel()); - unsigned rows = table->rowCount(parent); - usigned columns = table->columnCount(parent); + int rows = table->rowCount(parent); + int columns = table->columnCount(parent); if (row < 0 || row >= rows || @@ -76,3 +80,39 @@ QModelIndex CSMWorld::NestedTableModel::parent(const QModelIndex& index) const { return QModelIndex(); } + +QVariant CSMWorld::NestedTableModel::headerData(int section, + Qt::Orientation orientation, + int role) const +{ + if (orientation==Qt::Vertical) + return QVariant(); + + if (role==Qt::DisplayRole) + return tr (mHeaderTitle[section].c_str()); + + if (role==ColumnBase::Role_Flags) + return QVariant(); //TODO + + if (role==ColumnBase::Role_Display) + return mHeaderDisplay[section]; + + return QVariant(); +} + +void CSMWorld::NestedTableModel::setupHeaderVectors(ColumnBase::Display columnId) +{ + switch(columnId) + { + case ColumnBase::Display_NestedItemList: + mHeaderTitle.push_back("test1"); + mHeaderTitle.push_back("test2"); + + mHeaderDisplay.push_back(ColumnBase::Display_String); + mHeaderDisplay.push_back(ColumnBase::Display_Integer); + break; + + default: + assert(false); + } +} diff --git a/apps/opencs/model/world/nestedtablemodel.hpp b/apps/opencs/model/world/nestedtablemodel.hpp index be29be2ca..80c7f5a8e 100644 --- a/apps/opencs/model/world/nestedtablemodel.hpp +++ b/apps/opencs/model/world/nestedtablemodel.hpp @@ -43,6 +43,11 @@ namespace CSMWorld virtual QModelIndex index(int row, int column, const QModelIndex& parent) const; virtual QModelIndex parent(const QModelIndex& index) const; + + virtual QVariant headerData ( int section, Qt::Orientation orientation, int role ) const; + + private: + void setupHeaderVectors(ColumnBase::Display columnId); }; } diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 7a0e2efec..109f0c3fa 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -393,7 +393,7 @@ void CSVWorld::EditWidget::remake(int row) int locked = 0; const int columns = mTable->columnCount(); - for (unsigned i=0; iheaderData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt(); From 256b075914b97194e408d208c6db7b6fe5300f76 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Thu, 19 Jun 2014 16:11:31 +0200 Subject: [PATCH 023/740] getting rid of not needed abstract class --- apps/opencs/model/world/columnbase.hpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 9761b95aa..164ca4302 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -130,12 +130,6 @@ namespace CSMWorld throw std::logic_error ("Column " + getTitle() + " is not editable"); } }; - - template - struct NestedColumn - { - virtual QVariant getNested(const Record& record, int subColumn, int subSow) const = 0; - }; } #endif From a076798f8febb9034b9dc0944c7899230d867b16 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Thu, 19 Jun 2014 18:46:09 +0200 Subject: [PATCH 024/740] Quick and dirty prototype of actual nested header data implementation --- apps/opencs/model/world/columnbase.cpp | 14 +++++ apps/opencs/model/world/columnbase.hpp | 6 ++ apps/opencs/model/world/columns.cpp | 15 +++++ apps/opencs/model/world/columns.hpp | 4 ++ apps/opencs/model/world/idtable.cpp | 21 +++++++ apps/opencs/model/world/idtable.hpp | 2 + apps/opencs/model/world/nestedtablemodel.cpp | 58 ++++---------------- apps/opencs/model/world/nestedtablemodel.hpp | 3 +- apps/opencs/model/world/refidcollection.cpp | 2 + 9 files changed, 76 insertions(+), 49 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index e81943843..c0a264a1f 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -3,6 +3,8 @@ #include "columns.hpp" +#include + CSMWorld::ColumnBase::ColumnBase (int columnId, Display displayType, int flags, bool canNest) : mColumnId (columnId), mDisplayType (displayType), mFlags (flags), mCanNest(canNest) {} @@ -28,3 +30,15 @@ bool CSMWorld::ColumnBase::canHaveNestedColumns() const { return mCanNest; } + +std::string CSMWorld::ColumnBase::getNestedColumnTitle(int columnNumber) const +{ + return Columns::getName (mDisplayType, columnNumber); +} + +void CSMWorld::ColumnBase::addNestedColumnDisplay(CSMWorld::ColumnBase::Display displayDefinition) +{ + assert (canHaveNestedColumns()); + + mNestedDisplayType.push_back(displayDefinition); +} diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 164ca4302..0cd1f722f 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -2,6 +2,7 @@ #define CSM_WOLRD_COLUMNBASE_H #include +#include #include #include @@ -97,6 +98,7 @@ namespace CSMWorld int mColumnId; int mFlags; Display mDisplayType; + std::vector mNestedDisplayType; const bool mCanNest; ColumnBase (int columnId, Display displayType, int flag, bool canNest = false); @@ -110,6 +112,10 @@ namespace CSMWorld virtual std::string getTitle() const; + std::string getNestedColumnTitle(int columnNumber) const; + + virtual void addNestedColumnDisplay(Display displayDefinition); + virtual int getId() const; bool canHaveNestedColumns() const; diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 7410780e0..e39badeb5 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -216,6 +216,21 @@ std::string CSMWorld::Columns::getName (ColumnId column) return ""; } +std::string CSMWorld::Columns::getName(CSMWorld::ColumnBase::Display displayType, int columnNumber) +{ +//TODO, this is just temporary solution + switch (displayType) + { + case CSMWorld::ColumnBase::Display_NestedItemList: + if (columnNumber == 0) + return "ID"; + + if (columnNumber == 1) + return "Count"; + } + return "Do yourself a favor and take a look at the columns.cpp"; +} + int CSMWorld::Columns::getId (const std::string& name) { std::string name2 = Misc::StringUtils::lowerCase (name); diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index e824c4392..436ca1334 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -4,6 +4,8 @@ #include #include +#include "columnbase.hpp" + namespace CSMWorld { namespace Columns @@ -208,6 +210,8 @@ namespace CSMWorld std::string getName (ColumnId column); + std::string getName (ColumnBase::Display displayType, int columnNumber); + int getId (const std::string& name); ///< Will return -1 for an invalid name. diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 6aba322c1..fd2547ecf 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -1,5 +1,7 @@ #include "idtable.hpp" +#include + #include "collectionbase.hpp" #include "columnbase.hpp" @@ -70,6 +72,25 @@ QVariant CSMWorld::IdTable::headerData (int section, return QVariant(); } +QVariant CSMWorld::IdTable::nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role) const +{ + assert(mIdCollection->getColumn(section).canHaveNestedColumns()); + + if (orientation==Qt::Vertical) + return QVariant(); + + if (role==Qt::DisplayRole) + return tr (mIdCollection->getColumn(section).getNestedColumnTitle(subSection).c_str()); + + if (role==ColumnBase::Role_Flags) + return mIdCollection->getColumn (section).mFlags; + + if (role==ColumnBase::Role_Display) + return mIdCollection->getColumn (section).mNestedDisplayType.at(subSection); + + return QVariant(); +} + bool CSMWorld::IdTable::setData (const QModelIndex &index, const QVariant &value, int role) { if (mIdCollection->getColumn (index.column()).isEditable() && role==Qt::EditRole) diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index 6dc6f3e33..29d1f134a 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -72,6 +72,8 @@ namespace CSMWorld virtual QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + QVariant nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + virtual bool setData ( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); virtual Qt::ItemFlags flags (const QModelIndex & index) const; diff --git a/apps/opencs/model/world/nestedtablemodel.cpp b/apps/opencs/model/world/nestedtablemodel.cpp index 9ae4bdfd3..534ec5d10 100644 --- a/apps/opencs/model/world/nestedtablemodel.cpp +++ b/apps/opencs/model/world/nestedtablemodel.cpp @@ -6,21 +6,20 @@ CSMWorld::NestedTableModel::NestedTableModel(const QModelIndex& parent, ColumnBase::Display columnId, CSMWorld::IdTable* parentModel) - : mParentColumn(parent.column()) + : mParentColumn(parent.column()), + mMainModel(parentModel) { const int parentRow = parent.row(); mId = std::string(parentModel->index(parentRow, 0).data().toString().toUtf8()); QAbstractProxyModel::setSourceModel(parentModel); - - setupHeaderVectors(columnId); } QModelIndex CSMWorld::NestedTableModel::mapFromSource(const QModelIndex& sourceIndex) const { - const QModelIndex& testedParent = sourceModel()->parent(sourceIndex); - const QModelIndex& parent = dynamic_cast(sourceModel())->getModelIndex (mId, mParentColumn); + const QModelIndex& testedParent = mMainModel->parent(sourceIndex); + const QModelIndex& parent = mMainModel->getModelIndex (mId, mParentColumn); if (testedParent == parent) { return createIndex(sourceIndex.row(), sourceIndex.column()); @@ -34,36 +33,30 @@ QModelIndex CSMWorld::NestedTableModel::mapFromSource(const QModelIndex& sourceI QModelIndex CSMWorld::NestedTableModel::mapToSource(const QModelIndex& proxyIndex) const { - const QModelIndex& parent = dynamic_cast(sourceModel())->getModelIndex (mId, mParentColumn); - return sourceModel()->index(proxyIndex.row(), proxyIndex.column(), parent); + const QModelIndex& parent = mMainModel->getModelIndex (mId, mParentColumn); + return mMainModel->index(proxyIndex.row(), proxyIndex.column(), parent); } int CSMWorld::NestedTableModel::rowCount(const QModelIndex& index) const { assert (!index.isValid()); - CSMWorld::IdTable* table = dynamic_cast(sourceModel()); - - return table->rowCount(table->getModelIndex(mId, mParentColumn)); + return mMainModel->rowCount(mMainModel->getModelIndex(mId, mParentColumn)); } int CSMWorld::NestedTableModel::columnCount(const QModelIndex& parent) const { assert (!parent.isValid()); - CSMWorld::IdTable* table = dynamic_cast(sourceModel()); - - return table->columnCount(table->getModelIndex(mId, mParentColumn)); + return mMainModel->columnCount(mMainModel->getModelIndex(mId, mParentColumn)); } QModelIndex CSMWorld::NestedTableModel::index(int row, int column, const QModelIndex& parent) const { assert (!parent.isValid()); - CSMWorld::IdTable* table = dynamic_cast(sourceModel()); - - int rows = table->rowCount(parent); - int columns = table->columnCount(parent); + int rows = mMainModel->rowCount(parent); + int columns = mMainModel->columnCount(parent); if (row < 0 || row >= rows || @@ -85,34 +78,5 @@ QVariant CSMWorld::NestedTableModel::headerData(int section, Qt::Orientation orientation, int role) const { - if (orientation==Qt::Vertical) - return QVariant(); - - if (role==Qt::DisplayRole) - return tr (mHeaderTitle[section].c_str()); - - if (role==ColumnBase::Role_Flags) - return QVariant(); //TODO - - if (role==ColumnBase::Role_Display) - return mHeaderDisplay[section]; - - return QVariant(); -} - -void CSMWorld::NestedTableModel::setupHeaderVectors(ColumnBase::Display columnId) -{ - switch(columnId) - { - case ColumnBase::Display_NestedItemList: - mHeaderTitle.push_back("test1"); - mHeaderTitle.push_back("test2"); - - mHeaderDisplay.push_back(ColumnBase::Display_String); - mHeaderDisplay.push_back(ColumnBase::Display_Integer); - break; - - default: - assert(false); - } + return mMainModel->nestedHeaderData(mParentColumn, section, orientation, role); } diff --git a/apps/opencs/model/world/nestedtablemodel.hpp b/apps/opencs/model/world/nestedtablemodel.hpp index 80c7f5a8e..404051efc 100644 --- a/apps/opencs/model/world/nestedtablemodel.hpp +++ b/apps/opencs/model/world/nestedtablemodel.hpp @@ -22,9 +22,8 @@ namespace CSMWorld class NestedTableModel : public QAbstractProxyModel { const int mParentColumn; + IdTable* mMainModel; std::string mId; - std::vector mHeaderTitle; - std::vector mHeaderDisplay; public: NestedTableModel(const QModelIndex& parent, diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index a8fac216b..47c8ec800 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -168,6 +168,8 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue, true, true, true)); const RefIdColumn *content = &mColumns.back(); + (&mColumns.back())->addNestedColumnDisplay(CSMWorld::ColumnBase::Display_String); + (&mColumns.back())->addNestedColumnDisplay(CSMWorld::ColumnBase::Display_Integer); CreatureColumns creatureColumns (actorsColumns); From 894c98ee89479294fff69a674030a51d93353493 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Fri, 20 Jun 2014 13:40:54 +0200 Subject: [PATCH 025/740] Added extra columnid type to use for ID of the inventory item --- apps/opencs/model/world/columnbase.cpp | 16 ++++++++++++---- apps/opencs/model/world/columnbase.hpp | 12 ++++++++---- apps/opencs/model/world/columns.cpp | 17 ++--------------- apps/opencs/model/world/columns.hpp | 3 +-- apps/opencs/model/world/refidcollection.cpp | 2 ++ 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index c0a264a1f..59ee39126 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -1,4 +1,3 @@ - #include "columnbase.hpp" #include "columns.hpp" @@ -33,12 +32,21 @@ bool CSMWorld::ColumnBase::canHaveNestedColumns() const std::string CSMWorld::ColumnBase::getNestedColumnTitle(int columnNumber) const { - return Columns::getName (mDisplayType, columnNumber); + assert (mCanNest); + + return Columns::getName(static_cast(mNestedColumnId[columnNumber])); } void CSMWorld::ColumnBase::addNestedColumnDisplay(CSMWorld::ColumnBase::Display displayDefinition) { - assert (canHaveNestedColumns()); - + assert (mCanNest); + mNestedDisplayType.push_back(displayDefinition); } + +void CSMWorld::ColumnBase::addNestedColumnId(int columnId) +{ + assert (mCanNest); + + mNestedColumnId.push_back(columnId); +} diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 0cd1f722f..1cc45780f 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -31,7 +31,7 @@ namespace CSMWorld Display_String, Display_LongString, - //CONCRETE TYPES STARTS HERE + //CONCRETE TYPES STARTS HERE (for drag and drop) Display_Skill, Display_Class, Display_Faction, @@ -92,13 +92,15 @@ namespace CSMWorld Display_QuestStatusType, Display_Gender, + //Those are top level columns that nest other columns Display_NestedItemList }; int mColumnId; int mFlags; Display mDisplayType; - std::vector mNestedDisplayType; + std::vector mNestedDisplayType; //used only for the columns that actually nest other columns + std::vector mNestedColumnId; //used only for the columns that actually nest other columns const bool mCanNest; ColumnBase (int columnId, Display displayType, int flag, bool canNest = false); @@ -113,8 +115,10 @@ namespace CSMWorld virtual std::string getTitle() const; std::string getNestedColumnTitle(int columnNumber) const; - - virtual void addNestedColumnDisplay(Display displayDefinition); + + void addNestedColumnDisplay(Display displayDefinition); + + void addNestedColumnId(int columnId); virtual int getId() const; diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index e39badeb5..1898277a5 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -174,6 +174,8 @@ namespace CSMWorld { ColumnId_PcRank, "PC Rank" }, { ColumnId_Scope, "Scope" }, { ColumnId_ReferenceableId, "Referenceable ID" }, + { ColumnId_InventoryItemId, "ID"}, + { ColumnId_ItemCount, "Count"}, { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, @@ -216,21 +218,6 @@ std::string CSMWorld::Columns::getName (ColumnId column) return ""; } -std::string CSMWorld::Columns::getName(CSMWorld::ColumnBase::Display displayType, int columnNumber) -{ -//TODO, this is just temporary solution - switch (displayType) - { - case CSMWorld::ColumnBase::Display_NestedItemList: - if (columnNumber == 0) - return "ID"; - - if (columnNumber == 1) - return "Count"; - } - return "Do yourself a favor and take a look at the columns.cpp"; -} - int CSMWorld::Columns::getId (const std::string& name) { std::string name2 = Misc::StringUtils::lowerCase (name); diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 436ca1334..5d8ddb87d 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -171,6 +171,7 @@ namespace CSMWorld ColumnId_ReferenceableId = 156, ColumnId_ContainerContent = 157, ColumnId_ItemCount = 158, + ColumnId_InventoryItemId = 159, // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. @@ -210,8 +211,6 @@ namespace CSMWorld std::string getName (ColumnId column); - std::string getName (ColumnBase::Display displayType, int columnNumber); - int getId (const std::string& name); ///< Will return -1 for an invalid name. diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 47c8ec800..9fe42af96 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -170,6 +170,8 @@ CSMWorld::RefIdCollection::RefIdCollection() const RefIdColumn *content = &mColumns.back(); (&mColumns.back())->addNestedColumnDisplay(CSMWorld::ColumnBase::Display_String); (&mColumns.back())->addNestedColumnDisplay(CSMWorld::ColumnBase::Display_Integer); + (&mColumns.back())->addNestedColumnId(Columns::ColumnId_InventoryItemId); + (&mColumns.back())->addNestedColumnId(Columns::ColumnId_ItemCount); CreatureColumns creatureColumns (actorsColumns); From 88c5288eafb5a7260e616c0943eba3f6935f3daf Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 24 Jun 2014 10:22:42 +0200 Subject: [PATCH 026/740] Create removeNestedRow (for deleting rows of nested columns) --- apps/opencs/model/world/refidadapter.hpp | 2 + apps/opencs/model/world/refidadapterimp.cpp | 52 ++++++++++++--------- apps/opencs/model/world/refidadapterimp.hpp | 3 ++ 3 files changed, 35 insertions(+), 22 deletions(-) diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index 039f44a5e..928c0eaab 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -51,6 +51,8 @@ namespace CSMWorld virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const = 0; virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const = 0; + + virtual void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, unsigned rowToRemove) const = 0; }; } diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 19b8b06b8..6377db040 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -1,7 +1,6 @@ - #include "refidadapterimp.hpp" -#include +#include CSMWorld::PotionRefIdAdapter::PotionRefIdAdapter (const InventoryColumns& columns, const RefIdColumn *autoCalc) @@ -182,26 +181,21 @@ CSMWorld::ContainerRefIdAdapter::ContainerRefIdAdapter (const NameColumns& colum int CSMWorld::ContainerRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const { - if (column==mContent) - { - return 2; - } else { - throw "Trying to obtain nested columns count, but column does not have nested columns!"; - } + assert(column==mContent); + + return 2; } int CSMWorld::ContainerRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const { + assert(column==mContent); + const Record& record = static_cast&> ( data.getRecord(RefIdData::LocalIndex (index, UniversalId::Type_Container))); - if (column==mContent) - { - return record.get().mInventory.mList.size(); - } else { - throw "Trying to obtain nested rows count, but column does not have nested columns!"; - } + return record.get().mInventory.mList.size(); } + QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, int index) const { @@ -223,6 +217,18 @@ QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, co return NameRefIdAdapter::getData (column, data, index); } +void CSMWorld::ContainerRefIdAdapter::removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, unsigned rowToRemove) const +{ + assert(column==mContent); + + std::vector& list = static_cast&> ( + data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))).get().mInventory.mList; + + list.erase (list.begin () + rowToRemove); +} + + + void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const { @@ -249,17 +255,19 @@ void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdD NameRefIdAdapter::setData (column, data, index, value); } -void CSMWorld::ContainerRefIdAdapter::setNestedData(const RefIdColumn *column, RefIdData& data, - int index, - const QVariant& value, - int subRowIndex, - int subColIndex) const +void CSMWorld::ContainerRefIdAdapter::setNestedData(const RefIdColumn *column, + RefIdData& data, + int index, + const QVariant& value, + int subRowIndex, + int subColIndex) const { - Record& record = static_cast&> ( - data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); if (column==mContent) { + Record& record = static_cast&> ( + data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); + switch (subColIndex) { case 0: @@ -275,7 +283,7 @@ void CSMWorld::ContainerRefIdAdapter::setNestedData(const RefIdColumn *column, R } } else { - throw "This column does not hold multiple values."; + assert(false); } } diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index a01e59371..eeb859d84 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -633,6 +633,9 @@ namespace CSMWorld virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const; virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; + + + virtual void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, unsigned rowToRemove) const; }; struct CreatureColumns : public ActorColumns From c45061614b22fc9244a59ec34109866759cb8416 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 24 Jun 2014 12:21:40 +0200 Subject: [PATCH 027/740] Added code to delete nestedRows --- apps/opencs/model/world/collectionbase.cpp | 5 +++++ apps/opencs/model/world/collectionbase.hpp | 2 ++ apps/opencs/model/world/idtable.cpp | 8 +++++++- apps/opencs/model/world/refidadapter.hpp | 2 +- apps/opencs/model/world/refidadapterimp.cpp | 4 +--- apps/opencs/model/world/refidadapterimp.hpp | 3 +-- apps/opencs/model/world/refidcollection.cpp | 9 +++++++++ apps/opencs/model/world/refidcollection.hpp | 2 ++ apps/opencs/model/world/refiddata.hpp | 4 ++-- 9 files changed, 30 insertions(+), 9 deletions(-) diff --git a/apps/opencs/model/world/collectionbase.cpp b/apps/opencs/model/world/collectionbase.cpp index 7ea25770a..70f1fdf9f 100644 --- a/apps/opencs/model/world/collectionbase.cpp +++ b/apps/opencs/model/world/collectionbase.cpp @@ -47,3 +47,8 @@ int CSMWorld::CollectionBase::getNestedRowsCount(int row, int column) const assert(false); //TODO, make pure abstract return 0; } + +void CSMWorld::CollectionBase::removeNestedRows(int row, int column, int subRow) +{ + assert(false); //todo, make pure abstract +} diff --git a/apps/opencs/model/world/collectionbase.hpp b/apps/opencs/model/world/collectionbase.hpp index b6aad7eff..01fde1c8c 100644 --- a/apps/opencs/model/world/collectionbase.hpp +++ b/apps/opencs/model/world/collectionbase.hpp @@ -64,6 +64,8 @@ namespace CSMWorld virtual void removeRows (int index, int count) = 0; + virtual void removeNestedRows(int row, int column, int subRow); + virtual void appendBlankRecord (const std::string& id, UniversalId::Type type = UniversalId::Type_None) = 0; ///< \param type Will be ignored, unless the collection supports multiple record types diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index fd2547ecf..6e43cfeac 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -126,7 +126,13 @@ Qt::ItemFlags CSMWorld::IdTable::flags (const QModelIndex & index) const bool CSMWorld::IdTable::removeRows (int row, int count, const QModelIndex& parent) { if (parent.isValid()) - return false; + { + for (int i = 0; i < count; ++i) + { + mIdCollection->removeNestedRows(parent.row(), parent.column(), row+i); + } + return true; + } beginRemoveRows (parent, row, row+count-1); diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index 928c0eaab..fddb073a2 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -52,7 +52,7 @@ namespace CSMWorld virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const = 0; - virtual void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, unsigned rowToRemove) const = 0; + virtual void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const = 0; }; } diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 6377db040..01652ea7e 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -217,7 +217,7 @@ QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, co return NameRefIdAdapter::getData (column, data, index); } -void CSMWorld::ContainerRefIdAdapter::removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, unsigned rowToRemove) const +void CSMWorld::ContainerRefIdAdapter::removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const { assert(column==mContent); @@ -227,8 +227,6 @@ void CSMWorld::ContainerRefIdAdapter::removeNestedRow (const RefIdColumn *column list.erase (list.begin () + rowToRemove); } - - void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const { diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index eeb859d84..1f3a07dc0 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -633,9 +633,8 @@ namespace CSMWorld virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const; virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; - - virtual void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, unsigned rowToRemove) const; + virtual void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const; }; struct CreatureColumns : public ActorColumns diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 9fe42af96..47e52289f 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -463,6 +463,15 @@ void CSMWorld::RefIdCollection::removeRows (int index, int count) mData.erase (index, count); } +void CSMWorld::RefIdCollection::removeNestedRows(int row, int column, int subRow) +{ + RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + + const RefIdAdapter& adaptor = findAdaptor (localIndex.second); + + dynamic_cast(adaptor).removeNestedRow(&mColumns.at (column), mData, localIndex.first, subRow); +} + void CSMWorld::RefIdCollection::appendBlankRecord (const std::string& id, UniversalId::Type type) { mData.appendRecord (type, id, false); diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index fec621ac1..08fb410a5 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -76,6 +76,8 @@ namespace CSMWorld virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn); virtual void removeRows (int index, int count); + + virtual void removeNestedRows(int row, int column, int subRow); virtual void cloneRecord(const std::string& origin, const std::string& destination, diff --git a/apps/opencs/model/world/refiddata.hpp b/apps/opencs/model/world/refiddata.hpp index 535e914ee..bfdd4f9ee 100644 --- a/apps/opencs/model/world/refiddata.hpp +++ b/apps/opencs/model/world/refiddata.hpp @@ -52,7 +52,7 @@ namespace CSMWorld virtual void load (int index, ESM::ESMReader& reader, bool base) = 0; virtual void erase (int index, int count) = 0; - + virtual std::string getId (int index) const = 0; virtual void save (int index, ESM::ESMWriter& writer) const = 0; @@ -134,7 +134,7 @@ namespace CSMWorld throw std::runtime_error ("invalid RefIdDataContainer index"); mContainer.erase (mContainer.begin()+index, mContainer.begin()+index+count); - } + } template std::string RefIdDataContainer::getId (int index) const From 7430e1e1bbc2232cb3656bc50303f51819b2394b Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 24 Jun 2014 12:35:26 +0200 Subject: [PATCH 028/740] Added delete nested rows command (undo still needs to be done) --- apps/opencs/model/world/commands.cpp | 43 ++++++++++++++++++++++++++-- apps/opencs/model/world/commands.hpp | 26 +++++++++++++++-- 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index b60ffeb29..019a3d397 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -1,4 +1,3 @@ - #include "commands.hpp" #include @@ -171,4 +170,44 @@ void CSMWorld::CloneCommand::redo() void CSMWorld::CloneCommand::undo() { mModel.removeRow (mModel.getModelIndex (mIdDestination, 0).row()); -} \ No newline at end of file +} + +CSMWorld::DeleteNestedCommand::DeleteNestedCommand (IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent) + : mId(id), + mModel(model), + mParentColumn(parentColumn), + QUndoCommand(parent), + mNestedRow(nestedRow) +{ + setText (("Delete nested row in " + mId).c_str()); + + const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); + + const int columnsCount = mModel.columnCount(parentIndex); + + for (int i = 0; i < columnsCount; ++i) + { + const QModelIndex& childIndex = mModel.index(nestedRow, i, parentIndex); + + QVariant data = childIndex.data(); + if (!data.isValid()) + { + data = childIndex.data(Qt::DisplayRole); + } + + mOld.push_back(data); + } +} + +void CSMWorld::DeleteNestedCommand::redo() +{ + const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); + + mModel.removeRows (mNestedRow, 1, parentIndex); +} + + +void CSMWorld::DeleteNestedCommand::undo() +{ + //TODO +} diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index ec6350658..192b161ef 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include "universalid.hpp" @@ -49,7 +50,7 @@ namespace CSMWorld public: - CloneCommand (IdTable& model, const std::string& idOrigin, + CloneCommand (IdTable& model, const std::string& idOrigin, const std::string& IdDestination, const UniversalId::Type type, QUndoCommand* parent = 0); @@ -135,6 +136,27 @@ namespace CSMWorld virtual void undo(); }; + + class DeleteNestedCommand : public QUndoCommand + { + IdTable& mModel; + + std::string mId; + + std::vector mOld; + + int mParentColumn; + + int mNestedRow; + + public: + + DeleteNestedCommand (IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent); + + virtual void redo(); + + virtual void undo(); + }; } -#endif \ No newline at end of file +#endif From befdeb18897d5e9da0b0678de74e49b45d2658a0 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 24 Jun 2014 12:42:49 +0200 Subject: [PATCH 029/740] use beginRemovRow when removing nested row. --- apps/opencs/model/world/idtable.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 6e43cfeac..90d7e35b5 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -127,10 +127,12 @@ bool CSMWorld::IdTable::removeRows (int row, int count, const QModelIndex& paren { if (parent.isValid()) { + beginRemoveRows(parent, row, row+count-1); for (int i = 0; i < count; ++i) { mIdCollection->removeNestedRows(parent.row(), parent.column(), row+i); } + endRemoveRows(); return true; } From 7b5bf637abd3cf884dcb7fcb49cad8c64b5e876c Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 24 Jun 2014 19:03:29 +0200 Subject: [PATCH 030/740] Changes needed to add new nested row. --- apps/opencs/model/world/collectionbase.cpp | 5 +++++ apps/opencs/model/world/collectionbase.hpp | 2 ++ apps/opencs/model/world/idtable.cpp | 7 +++++++ apps/opencs/model/world/idtable.hpp | 2 ++ apps/opencs/model/world/refidadapter.hpp | 2 ++ apps/opencs/model/world/refidadapterimp.cpp | 19 +++++++++++++++++++ apps/opencs/model/world/refidadapterimp.hpp | 2 ++ apps/opencs/model/world/refidcollection.cpp | 9 +++++++++ apps/opencs/model/world/refidcollection.hpp | 2 ++ 9 files changed, 50 insertions(+) diff --git a/apps/opencs/model/world/collectionbase.cpp b/apps/opencs/model/world/collectionbase.cpp index 70f1fdf9f..a1f4f4a70 100644 --- a/apps/opencs/model/world/collectionbase.cpp +++ b/apps/opencs/model/world/collectionbase.cpp @@ -52,3 +52,8 @@ void CSMWorld::CollectionBase::removeNestedRows(int row, int column, int subRow) { assert(false); //todo, make pure abstract } + +void CSMWorld::CollectionBase::addNestedRow(int row, int col, int position) +{ + assert(false); +} diff --git a/apps/opencs/model/world/collectionbase.hpp b/apps/opencs/model/world/collectionbase.hpp index 01fde1c8c..aad40d36b 100644 --- a/apps/opencs/model/world/collectionbase.hpp +++ b/apps/opencs/model/world/collectionbase.hpp @@ -66,6 +66,8 @@ namespace CSMWorld virtual void removeNestedRows(int row, int column, int subRow); + virtual void addNestedRow(int row, int col, int position); + virtual void appendBlankRecord (const std::string& id, UniversalId::Type type = UniversalId::Type_None) = 0; ///< \param type Will be ignored, unless the collection supports multiple record types diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 90d7e35b5..a4e4972b4 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -145,6 +145,13 @@ bool CSMWorld::IdTable::removeRows (int row, int count, const QModelIndex& paren return true; } +void CSMWorld::IdTable::addNestedRow(const QModelIndex& parent, int position) +{ + assert(parent.isValid()); + + mIdCollection->addNestedRow(parent.row(), parent.column(), position); +} + QModelIndex CSMWorld::IdTable::index (int row, int column, const QModelIndex& parent) const { unsigned int encodedId = 0; diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index 29d1f134a..bf72b8026 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -80,6 +80,8 @@ namespace CSMWorld virtual bool removeRows (int row, int count, const QModelIndex& parent = QModelIndex()); + void addNestedRow (const QModelIndex& parent, int position); + virtual QModelIndex index (int row, int column, const QModelIndex& parent = QModelIndex()) const; diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index fddb073a2..068347fda 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -53,6 +53,8 @@ namespace CSMWorld virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const = 0; virtual void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const = 0; + + virtual void addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const = 0; }; } diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 01652ea7e..5b92ae941 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -227,6 +227,25 @@ void CSMWorld::ContainerRefIdAdapter::removeNestedRow (const RefIdColumn *column list.erase (list.begin () + rowToRemove); } +void CSMWorld::ContainerRefIdAdapter::addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const +{ + assert(column==mContent); + + std::vector& list = static_cast&> ( + data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))).get().mInventory.mList; + + ESM::ContItem newRow = {0, ""}; + if (position >= (int)list.size()) + { + list.push_back(newRow); + return; + } + + list.insert(list.begin()+position, newRow); + + return; +} + void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const { diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 1f3a07dc0..6fc56271b 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -635,6 +635,8 @@ namespace CSMWorld virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; virtual void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const; + + virtual void addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const; }; struct CreatureColumns : public ActorColumns diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 47e52289f..57a42d9fb 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -625,3 +625,12 @@ int CSMWorld::RefIdCollection::getNestedColumnsCount(int row, int column) const return adaptor.getNestedColumnsCount(&mColumns.at(column), mData); } + +void CSMWorld::RefIdCollection::addNestedRow(int row, int col, int position) +{ + RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + + const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdaptor (localIndex.second)); + + adaptor.addNestedRow(&mColumns.at(col), mData, localIndex.first, position); +} diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index 08fb410a5..7801811ff 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -79,6 +79,8 @@ namespace CSMWorld virtual void removeNestedRows(int row, int column, int subRow); + virtual void addNestedRow(int row, int col, int position); + virtual void cloneRecord(const std::string& origin, const std::string& destination, const UniversalId::Type type); From d73f4cbd7bf3829ee277caaadcc0bd609f32fa4b Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 24 Jun 2014 19:19:40 +0200 Subject: [PATCH 031/740] added add nested command --- apps/opencs/model/world/commands.cpp | 24 ++++++++++++++++++++++++ apps/opencs/model/world/commands.hpp | 19 +++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 019a3d397..42a5a7f7e 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -211,3 +211,27 @@ void CSMWorld::DeleteNestedCommand::undo() { //TODO } + +CSMWorld::AddNestedCommand::AddNestedCommand(IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent) + : mModel(model), + mId(id), + mNewRow(nestedRow), + mParentColumn(parentColumn), + QUndoCommand(parent) +{ + setText (("Added nested row in " + mId).c_str()); +} + +void CSMWorld::AddNestedCommand::redo() +{ + const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); + + mModel.addNestedRow (parentIndex, mNewRow); +} + +void CSMWorld::AddNestedCommand::undo() +{ + const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); + + mModel.removeRows(mNewRow, 1, parentIndex); +} diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index 192b161ef..9cfc0b293 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -157,6 +157,25 @@ namespace CSMWorld virtual void undo(); }; + + class AddNestedCommand : public QUndoCommand + { + IdTable& mModel; + + std::string mId; + + int mNewRow; + + int mParentColumn; + + public: + + AddNestedCommand(IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent); + + virtual void redo(); + + virtual void undo(); + }; } #endif From a0146e2e28cc58c409962c719f3047529327fa32 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 24 Jun 2014 19:34:02 +0200 Subject: [PATCH 032/740] Added undo for delete command --- apps/opencs/model/world/commands.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 42a5a7f7e..012736697 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -209,7 +209,16 @@ void CSMWorld::DeleteNestedCommand::redo() void CSMWorld::DeleteNestedCommand::undo() { - //TODO + const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); + + mModel.addNestedRow(parentIndex, mNestedRow); + + for (int i = 0; i < mModel.columnCount(parentIndex); ++i) + { + const QModelIndex& current = mModel.index(mNestedRow, i, parentIndex); + + mModel.setData(current, mOld[i]); + } } CSMWorld::AddNestedCommand::AddNestedCommand(IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent) From 8c6a0d9a4f1b2729dd078c51d4c51697945aaf39 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Sun, 29 Jun 2014 21:12:31 +0200 Subject: [PATCH 033/740] created new files --- apps/opencs/view/world/dialoguesubview.hpp | 2 +- apps/opencs/view/world/nestedtable.cpp | 20 +++++++++++++ apps/opencs/view/world/nestedtable.hpp | 34 ++++++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/view/world/nestedtable.cpp create mode 100644 apps/opencs/view/world/nestedtable.hpp diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 90a365592..a6b944d7a 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -170,7 +170,7 @@ namespace CSVWorld QWidget* mMainWidget; CSMWorld::IdTable* mTable; QUndoStack& mUndoStack; - std::vector mNestedModels; //Plain, raw C pointers, deleted in the dtor + std::vector mNestedModels; //Plain, raw C pointers, deleted in the dtor public: diff --git a/apps/opencs/view/world/nestedtable.cpp b/apps/opencs/view/world/nestedtable.cpp new file mode 100644 index 000000000..beeafed90 --- /dev/null +++ b/apps/opencs/view/world/nestedtable.cpp @@ -0,0 +1,20 @@ +#include "nestedtable.hpp" + +NestedTable::NestedTable(CSMDoc::Document& document, CSMWorld::NestedTableModel* model, const CSMWorld::UniversalId& id, QWidget* parent) + : QTableView(parent) +{ + QTableView::setModel(model); + setAcceptDrops(true); + + int columns = mModel->columnCount(); + + for(int i = 0 ; i < columns; ++i) + { + CSMWorld::ColumnBase::Display display = static_cast ( + mModel->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); + + CommandDelegate *delegate = CommandDelegateFactoryCollection::get().makeDelegate(display, + document.getUndoStack(), + this); + } +} diff --git a/apps/opencs/view/world/nestedtable.hpp b/apps/opencs/view/world/nestedtable.hpp new file mode 100644 index 000000000..200a73798 --- /dev/null +++ b/apps/opencs/view/world/nestedtable.hpp @@ -0,0 +1,34 @@ +#ifndef CSV_WORLD_NESTEDTABLE_H +#define CSV_WORLD_TABLE_H + +#include +#include + +class QUndoStack; +class QAction; + +namespace CSMWorld +{ + class NestedTableModel; +} + +namespace CSVWorld +{ + class NestedTable : public QTableView + { + Q_OBJECT + + std::vector mDelegates; + QAction *mAddNewRowAction; + QAction *mRemoveRowAction; + CSMWorld::CommandDispatcher *mDispatcher; + + public: + NestedTable(CSMDoc::Document& document, CSMWorld::NestedTableModel* model, const CSMWorld::UniversalId& id, QWidget* parent = NULL); + + protected: + void dragEnterEvent(QDragEnterEvent *event); + + void dragMoveEvent(QDragMoveEvent *event); + }; +} From 5eac32e3d3d2af1f4378a3bdcbd87d0fbbcc93ea Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 30 Jun 2014 13:09:10 +0200 Subject: [PATCH 034/740] added nestedtable for displaying nested content. --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/world/dialoguesubview.cpp | 6 ++---- apps/opencs/view/world/nestedtable.cpp | 25 +++++++++++++++++----- apps/opencs/view/world/nestedtable.hpp | 16 ++++++++++---- 4 files changed, 35 insertions(+), 14 deletions(-) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index e76e64610..eec1b653d 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -61,7 +61,7 @@ opencs_hdrs_noqt (view/doc opencs_units (view/world table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator cellcreator referenceablecreator referencecreator scenesubview scenetoolbar scenetool - scenetoolmode infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable + scenetoolmode infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable ) opencs_units (view/render diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 109f0c3fa..122b173e6 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -19,7 +19,6 @@ #include #include #include -#include #include #include "../../model/world/nestedtablemodel.hpp" @@ -34,6 +33,7 @@ #include "recordstatusdelegate.hpp" #include "util.hpp" #include "tablebottombox.hpp" +#include "nestedtable.hpp" /* ==============================NotEditableSubDelegate========================================== */ @@ -406,9 +406,7 @@ void CSVWorld::EditWidget::remake(int row) { mNestedModels.push_back(new CSMWorld::NestedTableModel (mTable->index(row, i), display, mTable)); - QTableView* table = new QTableView(); - - table->setModel(*(mNestedModels.rbegin())); + NestedTable* table = new NestedTable(mUndoStack, *(mNestedModels.rbegin()), this); tablesLayout->addWidget(table); } else diff --git a/apps/opencs/view/world/nestedtable.cpp b/apps/opencs/view/world/nestedtable.cpp index beeafed90..bfadfc08c 100644 --- a/apps/opencs/view/world/nestedtable.cpp +++ b/apps/opencs/view/world/nestedtable.cpp @@ -1,20 +1,35 @@ #include "nestedtable.hpp" +#include "../../model/world/nestedtablemodel.hpp" +#include "../../model/world/universalid.hpp" +#include "util.hpp" -NestedTable::NestedTable(CSMDoc::Document& document, CSMWorld::NestedTableModel* model, const CSMWorld::UniversalId& id, QWidget* parent) +CSVWorld::NestedTable::NestedTable(QUndoStack& undoStack, + CSMWorld::NestedTableModel* model, + QWidget* parent) : QTableView(parent) { - QTableView::setModel(model); + setModel(model); setAcceptDrops(true); - int columns = mModel->columnCount(); + int columns = model->columnCount(QModelIndex()); for(int i = 0 ; i < columns; ++i) { CSMWorld::ColumnBase::Display display = static_cast ( - mModel->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); + model->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); CommandDelegate *delegate = CommandDelegateFactoryCollection::get().makeDelegate(display, - document.getUndoStack(), + undoStack, this); + + setItemDelegateForColumn(i, delegate); } } + +void CSVWorld::NestedTable::dragEnterEvent(QDragEnterEvent *event) +{ +} + +void CSVWorld::NestedTable::dragMoveEvent(QDragMoveEvent *event) +{ +} diff --git a/apps/opencs/view/world/nestedtable.hpp b/apps/opencs/view/world/nestedtable.hpp index 200a73798..fe6214151 100644 --- a/apps/opencs/view/world/nestedtable.hpp +++ b/apps/opencs/view/world/nestedtable.hpp @@ -1,5 +1,5 @@ #ifndef CSV_WORLD_NESTEDTABLE_H -#define CSV_WORLD_TABLE_H +#define CSV_WORLD_NESTEDTABLE_H #include #include @@ -10,6 +10,12 @@ class QAction; namespace CSMWorld { class NestedTableModel; + class UniversalId; +} + +namespace CSMDoc +{ + class Document; } namespace CSVWorld @@ -18,13 +24,13 @@ namespace CSVWorld { Q_OBJECT - std::vector mDelegates; QAction *mAddNewRowAction; QAction *mRemoveRowAction; - CSMWorld::CommandDispatcher *mDispatcher; public: - NestedTable(CSMDoc::Document& document, CSMWorld::NestedTableModel* model, const CSMWorld::UniversalId& id, QWidget* parent = NULL); + NestedTable(QUndoStack& undoStack, + CSMWorld::NestedTableModel* model, + QWidget* parent = NULL); protected: void dragEnterEvent(QDragEnterEvent *event); @@ -32,3 +38,5 @@ namespace CSVWorld void dragMoveEvent(QDragMoveEvent *event); }; } + +#endif From c96d48fb914923a75d2e979ec1852415200e38ab Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 30 Jun 2014 14:12:57 +0200 Subject: [PATCH 035/740] Nested model supports editing now. --- apps/opencs/model/world/nestedtablemodel.cpp | 11 +++++++++++ apps/opencs/model/world/nestedtablemodel.hpp | 4 ++++ apps/opencs/view/world/nestedtable.cpp | 15 ++++++++++++--- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/nestedtablemodel.cpp b/apps/opencs/model/world/nestedtablemodel.cpp index 534ec5d10..20fbd81e1 100644 --- a/apps/opencs/model/world/nestedtablemodel.cpp +++ b/apps/opencs/model/world/nestedtablemodel.cpp @@ -80,3 +80,14 @@ QVariant CSMWorld::NestedTableModel::headerData(int section, { return mMainModel->nestedHeaderData(mParentColumn, section, orientation, role); } + + +bool CSMWorld::NestedTableModel::setData ( const QModelIndex & index, const QVariant & value, int role) +{ + return mMainModel->setData(mapToSource(index), value, role); +} + +Qt::ItemFlags CSMWorld::NestedTableModel::flags(const QModelIndex& index) const +{ + return mMainModel->flags(mMainModel->index(0, mParentColumn)); +} diff --git a/apps/opencs/model/world/nestedtablemodel.hpp b/apps/opencs/model/world/nestedtablemodel.hpp index 404051efc..0af261f4d 100644 --- a/apps/opencs/model/world/nestedtablemodel.hpp +++ b/apps/opencs/model/world/nestedtablemodel.hpp @@ -45,6 +45,10 @@ namespace CSMWorld virtual QVariant headerData ( int section, Qt::Orientation orientation, int role ) const; + virtual bool setData ( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole ); + + virtual Qt::ItemFlags flags(const QModelIndex& index) const; + private: void setupHeaderVectors(ColumnBase::Display columnId); }; diff --git a/apps/opencs/view/world/nestedtable.cpp b/apps/opencs/view/world/nestedtable.cpp index bfadfc08c..b4bb63f3a 100644 --- a/apps/opencs/view/world/nestedtable.cpp +++ b/apps/opencs/view/world/nestedtable.cpp @@ -3,13 +3,19 @@ #include "../../model/world/universalid.hpp" #include "util.hpp" +#include + CSVWorld::NestedTable::NestedTable(QUndoStack& undoStack, CSMWorld::NestedTableModel* model, QWidget* parent) : QTableView(parent) { - setModel(model); - setAcceptDrops(true); + + setSelectionBehavior (QAbstractItemView::SelectRows); + setSelectionMode (QAbstractItemView::ExtendedSelection); + + horizontalHeader()->setResizeMode (QHeaderView::Interactive); + verticalHeader()->hide(); int columns = model->columnCount(QModelIndex()); @@ -17,13 +23,16 @@ CSVWorld::NestedTable::NestedTable(QUndoStack& undoStack, { CSMWorld::ColumnBase::Display display = static_cast ( model->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); - + CommandDelegate *delegate = CommandDelegateFactoryCollection::get().makeDelegate(display, undoStack, this); setItemDelegateForColumn(i, delegate); } + + setModel(model); + setAcceptDrops(true); } void CSVWorld::NestedTable::dragEnterEvent(QDragEnterEvent *event) From 6dc199743c489ea5ae8d5586131bf39298e71280 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 30 Jun 2014 16:03:38 +0200 Subject: [PATCH 036/740] store undoStack in the nestedtable --- apps/opencs/view/world/nestedtable.cpp | 3 ++- apps/opencs/view/world/nestedtable.hpp | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/nestedtable.cpp b/apps/opencs/view/world/nestedtable.cpp index b4bb63f3a..ec5d01bbe 100644 --- a/apps/opencs/view/world/nestedtable.cpp +++ b/apps/opencs/view/world/nestedtable.cpp @@ -8,7 +8,8 @@ CSVWorld::NestedTable::NestedTable(QUndoStack& undoStack, CSMWorld::NestedTableModel* model, QWidget* parent) - : QTableView(parent) + : QTableView(parent), + mUndoStack(undoStack) { setSelectionBehavior (QAbstractItemView::SelectRows); diff --git a/apps/opencs/view/world/nestedtable.hpp b/apps/opencs/view/world/nestedtable.hpp index fe6214151..14a46480e 100644 --- a/apps/opencs/view/world/nestedtable.hpp +++ b/apps/opencs/view/world/nestedtable.hpp @@ -26,6 +26,7 @@ namespace CSVWorld QAction *mAddNewRowAction; QAction *mRemoveRowAction; + QUndoStack& mUndoStack; public: NestedTable(QUndoStack& undoStack, From 3ebc469f04d5c9ab03b942fdc683b0194a090ebf Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 30 Jun 2014 20:06:18 +0200 Subject: [PATCH 037/740] prepering for merge --- apps/opencs/view/world/nestedtable.cpp | 6 ++++++ apps/opencs/view/world/nestedtable.hpp | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/apps/opencs/view/world/nestedtable.cpp b/apps/opencs/view/world/nestedtable.cpp index ec5d01bbe..ffb1aaa47 100644 --- a/apps/opencs/view/world/nestedtable.cpp +++ b/apps/opencs/view/world/nestedtable.cpp @@ -4,6 +4,7 @@ #include "util.hpp" #include +#include CSVWorld::NestedTable::NestedTable(QUndoStack& undoStack, CSMWorld::NestedTableModel* model, @@ -43,3 +44,8 @@ void CSVWorld::NestedTable::dragEnterEvent(QDragEnterEvent *event) void CSVWorld::NestedTable::dragMoveEvent(QDragMoveEvent *event) { } + +void CSVWorld::NestedTable::contextMenuEvent (QContextMenuEvent *event) +{ + QModelIndexList selectedRows = selectionModel()->selectedRows(); +} diff --git a/apps/opencs/view/world/nestedtable.hpp b/apps/opencs/view/world/nestedtable.hpp index 14a46480e..bdd3db3fa 100644 --- a/apps/opencs/view/world/nestedtable.hpp +++ b/apps/opencs/view/world/nestedtable.hpp @@ -6,6 +6,7 @@ class QUndoStack; class QAction; +class QContextMenuEvent; namespace CSMWorld { @@ -37,6 +38,9 @@ namespace CSVWorld void dragEnterEvent(QDragEnterEvent *event); void dragMoveEvent(QDragMoveEvent *event); + + private: + void contextMenuEvent (QContextMenuEvent *event); }; } From fcd082c6a53ea2b2d69167a25cc0f8d0992e0830 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 1 Jul 2014 20:52:27 +0200 Subject: [PATCH 038/740] added option to add or remove rows --- apps/opencs/model/world/commands.hpp | 4 +- apps/opencs/model/world/nestedtablemodel.cpp | 15 +++++++ apps/opencs/model/world/nestedtablemodel.hpp | 6 +++ apps/opencs/view/world/nestedtable.cpp | 41 +++++++++++++++++++- apps/opencs/view/world/nestedtable.hpp | 11 ++++++ 5 files changed, 74 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index 9cfc0b293..e6f2d9724 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -151,7 +151,7 @@ namespace CSMWorld public: - DeleteNestedCommand (IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent); + DeleteNestedCommand (IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0); virtual void redo(); @@ -170,7 +170,7 @@ namespace CSMWorld public: - AddNestedCommand(IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent); + AddNestedCommand(IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0); virtual void redo(); diff --git a/apps/opencs/model/world/nestedtablemodel.cpp b/apps/opencs/model/world/nestedtablemodel.cpp index 20fbd81e1..133520d1d 100644 --- a/apps/opencs/model/world/nestedtablemodel.cpp +++ b/apps/opencs/model/world/nestedtablemodel.cpp @@ -91,3 +91,18 @@ Qt::ItemFlags CSMWorld::NestedTableModel::flags(const QModelIndex& index) const { return mMainModel->flags(mMainModel->index(0, mParentColumn)); } + +std::string CSMWorld::NestedTableModel::getParentId() const +{ + return mId; +} + +int CSMWorld::NestedTableModel::getParentColumn() const +{ + return mParentColumn; +} + +CSMWorld::IdTable* CSMWorld::NestedTableModel::model() const +{ + return mMainModel; +} diff --git a/apps/opencs/model/world/nestedtablemodel.hpp b/apps/opencs/model/world/nestedtablemodel.hpp index 0af261f4d..18563b389 100644 --- a/apps/opencs/model/world/nestedtablemodel.hpp +++ b/apps/opencs/model/world/nestedtablemodel.hpp @@ -31,6 +31,12 @@ namespace CSMWorld IdTable* parentModel); //parent is the parent of columns to work with. Columnid provides information about the column + std::string getParentId() const; + + int getParentColumn() const; + + CSMWorld::IdTable* model() const; + virtual QModelIndex mapFromSource(const QModelIndex& sourceIndex) const; virtual QModelIndex mapToSource(const QModelIndex& proxyIndex) const; diff --git a/apps/opencs/view/world/nestedtable.cpp b/apps/opencs/view/world/nestedtable.cpp index ffb1aaa47..ebcce15d5 100644 --- a/apps/opencs/view/world/nestedtable.cpp +++ b/apps/opencs/view/world/nestedtable.cpp @@ -1,16 +1,19 @@ #include "nestedtable.hpp" #include "../../model/world/nestedtablemodel.hpp" #include "../../model/world/universalid.hpp" +#include "../../model/world/commands.hpp" #include "util.hpp" #include #include +#include CSVWorld::NestedTable::NestedTable(QUndoStack& undoStack, CSMWorld::NestedTableModel* model, QWidget* parent) : QTableView(parent), - mUndoStack(undoStack) + mUndoStack(undoStack), + mModel(model) { setSelectionBehavior (QAbstractItemView::SelectRows); @@ -34,7 +37,16 @@ CSVWorld::NestedTable::NestedTable(QUndoStack& undoStack, } setModel(model); + setAcceptDrops(true); + + mAddNewRowAction = new QAction (tr ("Add new row"), this); + connect(mAddNewRowAction, SIGNAL(triggered()), + this, SLOT(addNewRowActionTriggered())); + + mRemoveRowAction = new QAction (tr ("Remove row"), this); + connect(mRemoveRowAction, SIGNAL(triggered()), + this, SLOT(removeRowActionTriggered())); } void CSVWorld::NestedTable::dragEnterEvent(QDragEnterEvent *event) @@ -48,4 +60,31 @@ void CSVWorld::NestedTable::dragMoveEvent(QDragMoveEvent *event) void CSVWorld::NestedTable::contextMenuEvent (QContextMenuEvent *event) { QModelIndexList selectedRows = selectionModel()->selectedRows(); + + QMenu menu(this); + + if (selectionModel()->selectedRows().size() == 1) + menu.addAction(mRemoveRowAction); + + menu.addAction(mAddNewRowAction); + + menu.exec (event->globalPos()); +} + +void CSVWorld::NestedTable::removeRowActionTriggered() +{ + mUndoStack.push(new CSMWorld::DeleteNestedCommand(*(mModel->model()), + mModel->getParentId(), + selectionModel()->selectedRows().begin()->row(), + mModel->getParentColumn())); + +} + +void CSVWorld::NestedTable::addNewRowActionTriggered() +{ + mUndoStack.push(new CSMWorld::AddNestedCommand(*(mModel->model()), + mModel->getParentId(), + selectionModel()->selectedRows().size(), + mModel->getParentColumn())); + } diff --git a/apps/opencs/view/world/nestedtable.hpp b/apps/opencs/view/world/nestedtable.hpp index bdd3db3fa..eb73cd885 100644 --- a/apps/opencs/view/world/nestedtable.hpp +++ b/apps/opencs/view/world/nestedtable.hpp @@ -28,6 +28,7 @@ namespace CSVWorld QAction *mAddNewRowAction; QAction *mRemoveRowAction; QUndoStack& mUndoStack; + CSMWorld::NestedTableModel* mModel; public: NestedTable(QUndoStack& undoStack, @@ -41,6 +42,16 @@ namespace CSVWorld private: void contextMenuEvent (QContextMenuEvent *event); + + private slots: + void removeRowActionTriggered(); + + void addNewRowActionTriggered(); + + signals: + void addNewRow(); + + void removeRow(int row); }; } From c50cecdc642eec35cffa39c404b4ffd334d42c5e Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 1 Jul 2014 21:13:27 +0200 Subject: [PATCH 039/740] Small cleanup --- apps/opencs/model/world/idtable.cpp | 8 +++++--- apps/opencs/view/world/nestedtable.cpp | 2 -- apps/opencs/view/world/nestedtable.hpp | 5 ----- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index a4e4972b4..29d2a543e 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -127,12 +127,10 @@ bool CSMWorld::IdTable::removeRows (int row, int count, const QModelIndex& paren { if (parent.isValid()) { - beginRemoveRows(parent, row, row+count-1); for (int i = 0; i < count; ++i) { mIdCollection->removeNestedRows(parent.row(), parent.column(), row+i); } - endRemoveRows(); return true; } @@ -149,7 +147,11 @@ void CSMWorld::IdTable::addNestedRow(const QModelIndex& parent, int position) { assert(parent.isValid()); - mIdCollection->addNestedRow(parent.row(), parent.column(), position); + int row = parent.row(); + mIdCollection->addNestedRow(row, parent.column(), position); + + emit dataChanged (CSMWorld::IdTable::index (row, 0), + CSMWorld::IdTable::index (row, mIdCollection->getColumns()-1)); } QModelIndex CSMWorld::IdTable::index (int row, int column, const QModelIndex& parent) const diff --git a/apps/opencs/view/world/nestedtable.cpp b/apps/opencs/view/world/nestedtable.cpp index ebcce15d5..2eef2e915 100644 --- a/apps/opencs/view/world/nestedtable.cpp +++ b/apps/opencs/view/world/nestedtable.cpp @@ -77,7 +77,6 @@ void CSVWorld::NestedTable::removeRowActionTriggered() mModel->getParentId(), selectionModel()->selectedRows().begin()->row(), mModel->getParentColumn())); - } void CSVWorld::NestedTable::addNewRowActionTriggered() @@ -86,5 +85,4 @@ void CSVWorld::NestedTable::addNewRowActionTriggered() mModel->getParentId(), selectionModel()->selectedRows().size(), mModel->getParentColumn())); - } diff --git a/apps/opencs/view/world/nestedtable.hpp b/apps/opencs/view/world/nestedtable.hpp index eb73cd885..35fa22494 100644 --- a/apps/opencs/view/world/nestedtable.hpp +++ b/apps/opencs/view/world/nestedtable.hpp @@ -47,11 +47,6 @@ namespace CSVWorld void removeRowActionTriggered(); void addNewRowActionTriggered(); - - signals: - void addNewRow(); - - void removeRow(int row); }; } From 77afb754e5d972489e028bd3146bd46ec561ceab Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Wed, 2 Jul 2014 13:13:03 +0200 Subject: [PATCH 040/740] adding new rows works --- apps/opencs/model/world/idtable.cpp | 4 +++ apps/opencs/model/world/nestedtablemodel.cpp | 36 ++++++++++++++++++++ apps/opencs/model/world/nestedtablemodel.hpp | 9 +++++ apps/opencs/view/world/nestedtable.cpp | 22 ++++++------ 4 files changed, 61 insertions(+), 10 deletions(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 29d2a543e..f71c367f0 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -148,10 +148,14 @@ void CSMWorld::IdTable::addNestedRow(const QModelIndex& parent, int position) assert(parent.isValid()); int row = parent.row(); + + beginInsertRows(parent, position, position); mIdCollection->addNestedRow(row, parent.column(), position); emit dataChanged (CSMWorld::IdTable::index (row, 0), CSMWorld::IdTable::index (row, mIdCollection->getColumns()-1)); + + endInsertRows(); } QModelIndex CSMWorld::IdTable::index (int row, int column, const QModelIndex& parent) const diff --git a/apps/opencs/model/world/nestedtablemodel.cpp b/apps/opencs/model/world/nestedtablemodel.cpp index 133520d1d..17bf7b30c 100644 --- a/apps/opencs/model/world/nestedtablemodel.cpp +++ b/apps/opencs/model/world/nestedtablemodel.cpp @@ -2,6 +2,7 @@ #include #include "./idtable.hpp" +#include CSMWorld::NestedTableModel::NestedTableModel(const QModelIndex& parent, ColumnBase::Display columnId, @@ -14,6 +15,13 @@ CSMWorld::NestedTableModel::NestedTableModel(const QModelIndex& parent, mId = std::string(parentModel->index(parentRow, 0).data().toString().toUtf8()); QAbstractProxyModel::setSourceModel(parentModel); + + connect(mMainModel, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)), + this, SLOT(forwardRowsAboutToInserted(const QModelIndex &, int, int))); + + connect(mMainModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)), + this, SLOT(forwardRowsInserted(const QModelIndex &, int, int))); + } QModelIndex CSMWorld::NestedTableModel::mapFromSource(const QModelIndex& sourceIndex) const @@ -106,3 +114,31 @@ CSMWorld::IdTable* CSMWorld::NestedTableModel::model() const { return mMainModel; } + +void CSMWorld::NestedTableModel::forwardRowsAboutToInserted(const QModelIndex& parent, int first, int last) +{ + if (indexIsParent(parent)) + { + qDebug()<<"Adding new rows "<< first<<":"<data(mMainModel->index(index.row(), 0)).toString().toUtf8().constData() == mId); +} diff --git a/apps/opencs/model/world/nestedtablemodel.hpp b/apps/opencs/model/world/nestedtablemodel.hpp index 18563b389..2263524cf 100644 --- a/apps/opencs/model/world/nestedtablemodel.hpp +++ b/apps/opencs/model/world/nestedtablemodel.hpp @@ -21,6 +21,8 @@ namespace CSMWorld class NestedTableModel : public QAbstractProxyModel { + Q_OBJECT + const int mParentColumn; IdTable* mMainModel; std::string mId; @@ -57,6 +59,13 @@ namespace CSMWorld private: void setupHeaderVectors(ColumnBase::Display columnId); + + bool indexIsParent(const QModelIndex& index); + + private slots: + void forwardRowsAboutToInserted(const QModelIndex & parent, int first, int last); + + void forwardRowsInserted(const QModelIndex & parent, int first, int last); }; } diff --git a/apps/opencs/view/world/nestedtable.cpp b/apps/opencs/view/world/nestedtable.cpp index 2eef2e915..a185fc7ce 100644 --- a/apps/opencs/view/world/nestedtable.cpp +++ b/apps/opencs/view/world/nestedtable.cpp @@ -28,23 +28,25 @@ CSVWorld::NestedTable::NestedTable(QUndoStack& undoStack, { CSMWorld::ColumnBase::Display display = static_cast ( model->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); - + CommandDelegate *delegate = CommandDelegateFactoryCollection::get().makeDelegate(display, undoStack, this); - + setItemDelegateForColumn(i, delegate); } setModel(model); setAcceptDrops(true); - + mAddNewRowAction = new QAction (tr ("Add new row"), this); - connect(mAddNewRowAction, SIGNAL(triggered()), + + connect(mAddNewRowAction, SIGNAL(triggered()), this, SLOT(addNewRowActionTriggered())); - + mRemoveRowAction = new QAction (tr ("Remove row"), this); + connect(mRemoveRowAction, SIGNAL(triggered()), this, SLOT(removeRowActionTriggered())); } @@ -60,21 +62,21 @@ void CSVWorld::NestedTable::dragMoveEvent(QDragMoveEvent *event) void CSVWorld::NestedTable::contextMenuEvent (QContextMenuEvent *event) { QModelIndexList selectedRows = selectionModel()->selectedRows(); - + QMenu menu(this); if (selectionModel()->selectedRows().size() == 1) menu.addAction(mRemoveRowAction); menu.addAction(mAddNewRowAction); - + menu.exec (event->globalPos()); } void CSVWorld::NestedTable::removeRowActionTriggered() { - mUndoStack.push(new CSMWorld::DeleteNestedCommand(*(mModel->model()), - mModel->getParentId(), + mUndoStack.push(new CSMWorld::DeleteNestedCommand(*(mModel->model()), + mModel->getParentId(), selectionModel()->selectedRows().begin()->row(), mModel->getParentColumn())); } @@ -82,7 +84,7 @@ void CSVWorld::NestedTable::removeRowActionTriggered() void CSVWorld::NestedTable::addNewRowActionTriggered() { mUndoStack.push(new CSMWorld::AddNestedCommand(*(mModel->model()), - mModel->getParentId(), + mModel->getParentId(), selectionModel()->selectedRows().size(), mModel->getParentColumn())); } From bb675ff41d1a7a5f38d8a18d6f6d5fd188c9c074 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Wed, 2 Jul 2014 13:29:25 +0200 Subject: [PATCH 041/740] Removing rows and undo works --- apps/opencs/model/world/idtable.cpp | 11 ++++++---- apps/opencs/model/world/nestedtablemodel.cpp | 21 ++++++++++++++++++++ apps/opencs/model/world/nestedtablemodel.hpp | 4 ++++ 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index f71c367f0..a74bd629b 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -125,18 +125,21 @@ Qt::ItemFlags CSMWorld::IdTable::flags (const QModelIndex & index) const bool CSMWorld::IdTable::removeRows (int row, int count, const QModelIndex& parent) { + beginRemoveRows (parent, row, row+count-1); + if (parent.isValid()) { for (int i = 0; i < count; ++i) { mIdCollection->removeNestedRows(parent.row(), parent.column(), row+i); } - return true; - } + } else + { - beginRemoveRows (parent, row, row+count-1); + beginRemoveRows (parent, row, row+count-1); - mIdCollection->removeRows (row, count); + mIdCollection->removeRows (row, count); + } endRemoveRows(); diff --git a/apps/opencs/model/world/nestedtablemodel.cpp b/apps/opencs/model/world/nestedtablemodel.cpp index 17bf7b30c..6d6618590 100644 --- a/apps/opencs/model/world/nestedtablemodel.cpp +++ b/apps/opencs/model/world/nestedtablemodel.cpp @@ -22,6 +22,11 @@ CSMWorld::NestedTableModel::NestedTableModel(const QModelIndex& parent, connect(mMainModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)), this, SLOT(forwardRowsInserted(const QModelIndex &, int, int))); + connect(mMainModel, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)), + this, SLOT(forwardRowsAboutToRemoved(const QModelIndex &, int, int))); + + connect(mMainModel, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), + this, SLOT(forwardRowsRemoved(const QModelIndex &, int, int))); } QModelIndex CSMWorld::NestedTableModel::mapFromSource(const QModelIndex& sourceIndex) const @@ -142,3 +147,19 @@ bool CSMWorld::NestedTableModel::indexIsParent(const QModelIndex& index) index.column() == mParentColumn && mMainModel->data(mMainModel->index(index.row(), 0)).toString().toUtf8().constData() == mId); } + +void CSMWorld::NestedTableModel::forwardRowsAboutToRemoved(const QModelIndex& parent, int first, int last) +{ + if (indexIsParent(parent)) + { + beginRemoveRows(QModelIndex(), first, last); + } +} + +void CSMWorld::NestedTableModel::forwardRowsRemoved(const QModelIndex& parent, int first, int last) +{ + if (indexIsParent(parent)) + { + endRemoveRows(); + } +} diff --git a/apps/opencs/model/world/nestedtablemodel.hpp b/apps/opencs/model/world/nestedtablemodel.hpp index 2263524cf..dfb231124 100644 --- a/apps/opencs/model/world/nestedtablemodel.hpp +++ b/apps/opencs/model/world/nestedtablemodel.hpp @@ -66,6 +66,10 @@ namespace CSMWorld void forwardRowsAboutToInserted(const QModelIndex & parent, int first, int last); void forwardRowsInserted(const QModelIndex & parent, int first, int last); + + void forwardRowsAboutToRemoved(const QModelIndex & parent, int first, int last); + + void forwardRowsRemoved(const QModelIndex & parent, int first, int last); }; } From 0bfc408ea2653c0d455f6239aa2cce21ea8b964c Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Wed, 2 Jul 2014 14:10:11 +0200 Subject: [PATCH 042/740] removed debug code --- apps/opencs/model/world/nestedtablemodel.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/apps/opencs/model/world/nestedtablemodel.cpp b/apps/opencs/model/world/nestedtablemodel.cpp index 6d6618590..cb7943f5e 100644 --- a/apps/opencs/model/world/nestedtablemodel.cpp +++ b/apps/opencs/model/world/nestedtablemodel.cpp @@ -2,7 +2,6 @@ #include #include "./idtable.hpp" -#include CSMWorld::NestedTableModel::NestedTableModel(const QModelIndex& parent, ColumnBase::Display columnId, @@ -140,9 +139,6 @@ void CSMWorld::NestedTableModel::forwardRowsInserted(const QModelIndex& parent, bool CSMWorld::NestedTableModel::indexIsParent(const QModelIndex& index) { - qDebug()<<"Testing for parenty"; - qDebug()<data(mMainModel->index(index.row(), 0)).toString().toUtf8().constData() == mId); From 851d2f061b45ce8f758cdb22242d34af8567f675 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Thu, 3 Jul 2014 11:14:51 +0200 Subject: [PATCH 043/740] Removed qdebug calls (forgot about those). --- apps/opencs/model/world/nestedtablemodel.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/opencs/model/world/nestedtablemodel.cpp b/apps/opencs/model/world/nestedtablemodel.cpp index cb7943f5e..d0648e5e9 100644 --- a/apps/opencs/model/world/nestedtablemodel.cpp +++ b/apps/opencs/model/world/nestedtablemodel.cpp @@ -123,7 +123,6 @@ void CSMWorld::NestedTableModel::forwardRowsAboutToInserted(const QModelIndex& p { if (indexIsParent(parent)) { - qDebug()<<"Adding new rows "<< first<<":"< Date: Mon, 7 Jul 2014 10:23:40 +0200 Subject: [PATCH 044/740] fixed segfault --- apps/opencs/view/world/dialoguesubview.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 122b173e6..673d3573f 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -353,6 +353,7 @@ void CSVWorld::EditWidget::remake(int row) { delete mNestedModels[i]; } + mNestedModels.clear(); if (mMainWidget) { From 3262f8d774ae3503944345c28c4caf0cea1553b4 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 7 Jul 2014 10:27:48 +0200 Subject: [PATCH 045/740] make dtor virtual --- apps/opencs/view/world/dialoguesubview.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index a6b944d7a..c1bc96211 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -177,7 +177,7 @@ namespace CSVWorld EditWidget (QWidget *parent, int row, CSMWorld::IdTable* table, QUndoStack& undoStack, bool createAndDelete = false); - ~EditWidget(); + virtual ~EditWidget(); void remake(int row); From d221486a140cd81233b8f1f5b7897b59bd7bcc90 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 7 Jul 2014 12:07:29 +0200 Subject: [PATCH 046/740] Fixed problem in the idtable. --- apps/opencs/model/world/idtable.cpp | 38 +++++++++++++++++--------- apps/opencs/view/world/nestedtable.cpp | 3 +- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index a74bd629b..c2eb32fa5 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -1,4 +1,5 @@ #include "idtable.hpp" +#include #include @@ -93,23 +94,34 @@ QVariant CSMWorld::IdTable::nestedHeaderData(int section, int subSection, Qt::Or bool CSMWorld::IdTable::setData (const QModelIndex &index, const QVariant &value, int role) { - if (mIdCollection->getColumn (index.column()).isEditable() && role==Qt::EditRole) + if (index.internalId() != 0) { - if (index.internalId() == 0) - { - mIdCollection->setData (index.row(), index.column(), value); - - emit dataChanged (CSMWorld::IdTable::index (index.row(), 0), - CSMWorld::IdTable::index (index.row(), mIdCollection->getColumns()-1)); - } else + if (mIdCollection->getColumn(parent(index).column()).isEditable() && role==Qt::EditRole) { const std::pair& parentAdress(unfoldIndexAdress(index.internalId())); mIdCollection->setNestedData(parentAdress.first, parentAdress.second, value, index.row(), index.column()); + + emit dataChanged (CSMWorld::IdTable::index (parentAdress.first, 0), + CSMWorld::IdTable::index (parentAdress.second, mIdCollection->getColumns()-1)); + + return true; + } else + { + return false; } - return true; } - + + if (mIdCollection->getColumn (index.column()).isEditable() && role==Qt::EditRole) + { + mIdCollection->setData (index.row(), index.column(), value); + + emit dataChanged (CSMWorld::IdTable::index (index.row(), 0), + CSMWorld::IdTable::index (index.row(), mIdCollection->getColumns()-1)); + + return true; + } + return false; } @@ -131,9 +143,9 @@ bool CSMWorld::IdTable::removeRows (int row, int count, const QModelIndex& paren { for (int i = 0; i < count; ++i) { - mIdCollection->removeNestedRows(parent.row(), parent.column(), row+i); + mIdCollection->removeNestedRows(parent.row(), parent.column(), row+i); } - } else + } else { beginRemoveRows (parent, row, row+count-1); @@ -157,7 +169,7 @@ void CSMWorld::IdTable::addNestedRow(const QModelIndex& parent, int position) emit dataChanged (CSMWorld::IdTable::index (row, 0), CSMWorld::IdTable::index (row, mIdCollection->getColumns()-1)); - + endInsertRows(); } diff --git a/apps/opencs/view/world/nestedtable.cpp b/apps/opencs/view/world/nestedtable.cpp index a185fc7ce..21bef504b 100644 --- a/apps/opencs/view/world/nestedtable.cpp +++ b/apps/opencs/view/world/nestedtable.cpp @@ -7,6 +7,7 @@ #include #include #include +#include CSVWorld::NestedTable::NestedTable(QUndoStack& undoStack, CSMWorld::NestedTableModel* model, @@ -32,7 +33,7 @@ CSVWorld::NestedTable::NestedTable(QUndoStack& undoStack, CommandDelegate *delegate = CommandDelegateFactoryCollection::get().makeDelegate(display, undoStack, this); - + setItemDelegateForColumn(i, delegate); } From 72392ad68c025ea634fcfc2ec280e9611969e0b4 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 7 Jul 2014 12:22:04 +0200 Subject: [PATCH 047/740] emit data changed signal when adding and removing the nested row --- apps/opencs/model/world/idtable.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index c2eb32fa5..0b5f9c5a3 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -155,6 +155,9 @@ bool CSMWorld::IdTable::removeRows (int row, int count, const QModelIndex& paren endRemoveRows(); + emit dataChanged (CSMWorld::IdTable::index (parent.row(), 0), + CSMWorld::IdTable::index (parent.row(), mIdCollection->getColumns()-1)); + return true; } @@ -167,10 +170,10 @@ void CSMWorld::IdTable::addNestedRow(const QModelIndex& parent, int position) beginInsertRows(parent, position, position); mIdCollection->addNestedRow(row, parent.column(), position); + endInsertRows(); + emit dataChanged (CSMWorld::IdTable::index (row, 0), CSMWorld::IdTable::index (row, mIdCollection->getColumns()-1)); - - endInsertRows(); } QModelIndex CSMWorld::IdTable::index (int row, int column, const QModelIndex& parent) const From 0252d021eba082f6f30736248520b17ca20b7ffc Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Sun, 13 Jul 2014 12:37:05 +0200 Subject: [PATCH 048/740] removed pointless member field --- apps/opencs/model/world/columnbase.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 3f9e7e1a3..bf03ab563 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -93,6 +93,7 @@ namespace CSMWorld //Those are top level columns that nest other columns Display_NestedItemList, + Display_EnchantmentType, Display_BodyPartType, Display_MeshType, @@ -138,8 +139,6 @@ namespace CSMWorld template struct Column : public ColumnBase { - int mFlags; - Column (int columnId, Display displayType, int flags = Flag_Table | Flag_Dialogue, bool canNest = false) : ColumnBase (columnId, displayType, flags, canNest) {} From f0c6ef185eb8f2735e17470d836c5475c9388544 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Wed, 16 Jul 2014 13:13:22 +0200 Subject: [PATCH 049/740] Nest columns directly, created NestedColumn class and NestColumn. --- apps/opencs/model/world/columnbase.cpp | 40 +++++++++++++-------- apps/opencs/model/world/columnbase.hpp | 37 ++++++++++++++----- apps/opencs/model/world/idtable.cpp | 8 ++--- apps/opencs/model/world/refidadapterimp.cpp | 7 ++-- apps/opencs/model/world/refidcollection.cpp | 8 ++--- apps/opencs/model/world/refidcollection.hpp | 2 +- 6 files changed, 66 insertions(+), 36 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 59ee39126..60e201ba4 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -2,8 +2,6 @@ #include "columns.hpp" -#include - CSMWorld::ColumnBase::ColumnBase (int columnId, Display displayType, int flags, bool canNest) : mColumnId (columnId), mDisplayType (displayType), mFlags (flags), mCanNest(canNest) {} @@ -25,28 +23,42 @@ int CSMWorld::ColumnBase::getId() const return mColumnId; } -bool CSMWorld::ColumnBase::canHaveNestedColumns() const +bool CSMWorld::NestColumn::canHaveNestedColumns() const { return mCanNest; } -std::string CSMWorld::ColumnBase::getNestedColumnTitle(int columnNumber) const +void CSMWorld::NestColumn::addNestedColumn(int columnId, Display displayType) { - assert (mCanNest); - - return Columns::getName(static_cast(mNestedColumnId[columnNumber])); + if (!mCanNest) + throw std::logic_error("Tried to nest inside of the non-nest column"); + + mNestedColumns.push_back(CSMWorld::NestedColumn(columnId, displayType, mFlags, this)); } -void CSMWorld::ColumnBase::addNestedColumnDisplay(CSMWorld::ColumnBase::Display displayDefinition) +const CSMWorld::ColumnBase& CSMWorld::NestColumn::nestedColumn(int subColumn) const { - assert (mCanNest); - - mNestedDisplayType.push_back(displayDefinition); + if (!mCanNest) + throw std::logic_error("Tried to access nested column of the non-nest column"); + + return mNestedColumns.at(subColumn); } -void CSMWorld::ColumnBase::addNestedColumnId(int columnId) +int CSMWorld::NestColumn::nestedColumnCount() const { - assert (mCanNest); + if (!mCanNest) + throw std::logic_error("Tried to access number of the subcolumns in the non-nest column"); + + return mNestedColumns.size(); +} - mNestedColumnId.push_back(columnId); +CSMWorld::NestColumn::NestColumn(int columnId, Display displayType, int flags, bool canNest) + : CSMWorld::ColumnBase(columnId, displayType, flags, canNest) {} + +CSMWorld::NestedColumn::NestedColumn(int columnId, Display displayType, int flag, const CSMWorld::NestColumn* parent) + : mParent(parent), CSMWorld::ColumnBase(columnId, displayType, flag) {} + +bool CSMWorld::NestedColumn::isEditable() const +{ + return mParent->isEditable(); } diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index bf03ab563..096491f1e 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -110,9 +111,7 @@ namespace CSMWorld int mColumnId; int mFlags; Display mDisplayType; - std::vector mNestedDisplayType; //used only for the columns that actually nest other columns - std::vector mNestedColumnId; //used only for the columns that actually nest other columns - const bool mCanNest; + bool mCanNest; ColumnBase (int columnId, Display displayType, int flag, bool canNest = false); @@ -125,22 +124,42 @@ namespace CSMWorld virtual std::string getTitle() const; - std::string getNestedColumnTitle(int columnNumber) const; + virtual int getId() const; + }; - void addNestedColumnDisplay(Display displayDefinition); + class NestedColumn; - void addNestedColumnId(int columnId); + class NestColumn : public ColumnBase + { + std::vector mNestedColumns; - virtual int getId() const; + public: + NestColumn(int columnId, Display displayType, int flags, bool canNest); + + void addNestedColumn(int columnId, Display displayType); bool canHaveNestedColumns() const; + + const ColumnBase& nestedColumn(int subColumn) const; + + int nestedColumnCount() const; }; + class NestedColumn : public ColumnBase + { + const ColumnBase* mParent; + + public: + NestedColumn(int columnId, Display displayType, int flag, const NestColumn* parent); + + virtual bool isEditable() const; + }; + template - struct Column : public ColumnBase + struct Column : public NestColumn { Column (int columnId, Display displayType, int flags = Flag_Table | Flag_Dialogue, bool canNest = false) - : ColumnBase (columnId, displayType, flags, canNest) {} + : NestColumn (columnId, displayType, canNest, flags) {} virtual QVariant get (const Record& record) const = 0; diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 00cfbd145..a3435180c 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -75,19 +75,19 @@ QVariant CSMWorld::IdTable::headerData (int section, QVariant CSMWorld::IdTable::nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role) const { - assert(mIdCollection->getColumn(section).canHaveNestedColumns()); + const NestColumn& parentColumn = dynamic_cast(mIdCollection->getColumn(section)); if (orientation==Qt::Vertical) return QVariant(); if (role==Qt::DisplayRole) - return tr (mIdCollection->getColumn(section).getNestedColumnTitle(subSection).c_str()); + return tr(parentColumn.nestedColumn(subSection).getTitle().c_str()); if (role==ColumnBase::Role_Flags) return mIdCollection->getColumn (section).mFlags; if (role==ColumnBase::Role_Display) - return mIdCollection->getColumn (section).mNestedDisplayType.at(subSection); + return parentColumn.nestedColumn(subSection).mDisplayType; return QVariant(); } @@ -354,6 +354,6 @@ bool CSMWorld::IdTable::hasChildren(const QModelIndex& index) const { return (index.isValid() && index.internalId() == 0 && - mIdCollection->getColumn (index.column()).canHaveNestedColumns() && + mIdCollection->getColumn(index.column()).mCanNest && index.data().isValid()); } diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 7033140ca..8d6ab838d 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -1,6 +1,7 @@ #include "refidadapterimp.hpp" #include +#include CSMWorld::PotionRefIdAdapter::PotionRefIdAdapter (const InventoryColumns& columns, const RefIdColumn *autoCalc) @@ -296,7 +297,7 @@ void CSMWorld::ContainerRefIdAdapter::setNestedData(const RefIdColumn *column, break; default: - throw "Trying to access non-existing column in the nested table!"; + throw std::logic_error("Trying to access non-existing column in the nested table!"); } } else { @@ -326,11 +327,11 @@ QVariant CSMWorld::ContainerRefIdAdapter::getNestedData (const CSMWorld::RefIdCo return content.mCount; default: - throw "Trying to access non-existing column in the nested table!"; + throw std::logic_error("Trying to access non-existing column in the nested table!"); } } else { - throw "This column does not hold multiple values."; + throw std::logic_error("This column does not hold multiple values."); } } diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 7aa1d7753..62daef903 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -13,7 +13,7 @@ CSMWorld::RefIdColumn::RefIdColumn (int columnId, Display displayType, int flag, bool editable, bool userEditable, bool canNest) - : ColumnBase (columnId, displayType, flag, canNest), mEditable (editable), mUserEditable (userEditable) + : NestColumn (columnId, displayType, flag, canNest), mEditable (editable), mUserEditable (userEditable) {} bool CSMWorld::RefIdColumn::isEditable() const @@ -168,10 +168,8 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue, true, true, true)); const RefIdColumn *content = &mColumns.back(); - (&mColumns.back())->addNestedColumnDisplay(CSMWorld::ColumnBase::Display_String); - (&mColumns.back())->addNestedColumnDisplay(CSMWorld::ColumnBase::Display_Integer); - (&mColumns.back())->addNestedColumnId(Columns::ColumnId_InventoryItemId); - (&mColumns.back())->addNestedColumnId(Columns::ColumnId_ItemCount); + (&mColumns.back())->addNestedColumn(Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String); + (&mColumns.back())->addNestedColumn(Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer); CreatureColumns creatureColumns (actorsColumns); diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index 7801811ff..d1bb197e8 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -18,7 +18,7 @@ namespace CSMWorld { class RefIdAdapter; - class RefIdColumn : public ColumnBase + class RefIdColumn : public NestColumn { bool mEditable; bool mUserEditable; From ca73ce3fe23e94fbc9d1fdceb957c9d9c756f94e Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Thu, 17 Jul 2014 12:41:43 +0200 Subject: [PATCH 050/740] trying to fix indending --- apps/opencs/model/world/refidcollection.hpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index d1bb197e8..02b77400b 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -18,7 +18,7 @@ namespace CSMWorld { class RefIdAdapter; - class RefIdColumn : public NestColumn + class RefIdColumn : public NestColumn { bool mEditable; bool mUserEditable; @@ -76,11 +76,11 @@ namespace CSMWorld virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn); virtual void removeRows (int index, int count); - + virtual void removeNestedRows(int row, int column, int subRow); virtual void addNestedRow(int row, int col, int position); - + virtual void cloneRecord(const std::string& origin, const std::string& destination, const UniversalId::Type type); @@ -124,9 +124,8 @@ namespace CSMWorld void save (int index, ESM::ESMWriter& writer) const; - const RefIdData& getDataSet() const; //I can't figure out a better name for this one :( + const RefIdData& getDataSet() const; //I can't figure out a better name for this one :( }; } #endif - From 6e07568b43fea79c1b3acffb07f4b9aa30d1c35c Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Thu, 17 Jul 2014 12:56:51 +0200 Subject: [PATCH 051/740] Corrected syntax. --- apps/opencs/model/world/refidcollection.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 62daef903..1a164d12f 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -168,8 +168,8 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue, true, true, true)); const RefIdColumn *content = &mColumns.back(); - (&mColumns.back())->addNestedColumn(Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String); - (&mColumns.back())->addNestedColumn(Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer); + mColumns.back().addNestedColumn(Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String); + mColumns.back().addNestedColumn(Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer); CreatureColumns creatureColumns (actorsColumns); From 5671a4b8e2b55f48b11fdc4c2a221bb0883a1cdb Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Thu, 17 Jul 2014 12:58:14 +0200 Subject: [PATCH 052/740] corrected include to follow our standards. --- apps/opencs/model/world/nestedtablemodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/nestedtablemodel.cpp b/apps/opencs/model/world/nestedtablemodel.cpp index d0648e5e9..f0b510244 100644 --- a/apps/opencs/model/world/nestedtablemodel.cpp +++ b/apps/opencs/model/world/nestedtablemodel.cpp @@ -1,7 +1,7 @@ #include "nestedtablemodel.hpp" #include -#include "./idtable.hpp" +#include "idtable.hpp" CSMWorld::NestedTableModel::NestedTableModel(const QModelIndex& parent, ColumnBase::Display columnId, From 16292bf23ee73dd1f32332d4af0af1d2ae6d9a03 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Thu, 17 Jul 2014 13:03:53 +0200 Subject: [PATCH 053/740] removed useless todo statments. --- apps/opencs/model/world/collection.hpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 3b39dc6f9..904587eaf 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -73,10 +73,10 @@ namespace CSMWorld ///< Add a new record (modified) virtual int getSize() const; - - virtual int getNestedColumnsCount(int column) const; - virtual int getNestedRowsCount(int row, int column) const; + virtual int getNestedColumnsCount(int column) const; + + virtual int getNestedRowsCount(int row, int column) const; virtual std::string getId (int index) const; @@ -253,19 +253,17 @@ namespace CSMWorld { return mRecords.size(); } - + template int Collection::getNestedRowsCount(int row, int column) const { - //TODO - return 0; + return 0; } template int Collection::getNestedColumnsCount(int column) const { - //TODO - return 0; + return 0; } template @@ -300,7 +298,7 @@ namespace CSMWorld template QVariant Collection::getNestedData(int row, int column, int subRow, int subColumn) const { - return 10; //TODO + return QVariant(); } template From 1ff8abb240e4f235e8d66af9c169cc92735e0c21 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Fri, 18 Jul 2014 18:26:22 +0200 Subject: [PATCH 054/740] store whole container representing the nested table inside of the command Static nature of C++ forced me to use templates. Bit frustraiting. --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/collection.hpp | 18 ++++++++++ apps/opencs/model/world/collectionbase.hpp | 11 ++++-- apps/opencs/model/world/commands.cpp | 36 ++++--------------- apps/opencs/model/world/commands.hpp | 6 +++- apps/opencs/model/world/idtable.cpp | 21 +++++++++++ apps/opencs/model/world/idtable.hpp | 5 +++ .../opencs/model/world/nestedtablewrapper.cpp | 7 ++++ .../opencs/model/world/nestedtablewrapper.hpp | 33 +++++++++++++++++ apps/opencs/model/world/refidadapter.hpp | 9 +++-- apps/opencs/model/world/refidadapterimp.cpp | 23 ++++++++++++ apps/opencs/model/world/refidadapterimp.hpp | 6 ++++ apps/opencs/model/world/refidcollection.cpp | 21 ++++++++++- apps/opencs/model/world/refidcollection.hpp | 7 +++- 14 files changed, 167 insertions(+), 38 deletions(-) create mode 100644 apps/opencs/model/world/nestedtablewrapper.cpp create mode 100644 apps/opencs/model/world/nestedtablewrapper.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 3871a4d5a..bcc64b60a 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -19,7 +19,7 @@ opencs_hdrs_noqt (model/doc opencs_units (model/world idtable idtableproxymodel regionmap data commanddispatcher - idtablebase resourcetable nestedtablemodel + idtablebase resourcetable nestedtablemodel nestedtablewrapper ) diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 904587eaf..ac4351986 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -16,6 +16,8 @@ #include "collectionbase.hpp" +#include "nestedtablewrapper.hpp" + namespace CSMWorld { /// \brief Access to ID field in records @@ -90,6 +92,10 @@ namespace CSMWorld virtual void setData (int index, int column, const QVariant& data); + virtual NestedTableWrapperBase nestedTable(int row, int column) const; + + virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable); + virtual const ColumnBase& getColumn (int column) const; virtual void merge(); @@ -300,6 +306,18 @@ namespace CSMWorld { return QVariant(); } + + template + NestedTableWrapperBase Collection::nestedTable(int row, int column) const + { + return NestedTableWrapperBase(); + } + + template + void Collection::setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable) + { + throw std::logic_error("setNestedTable was not overriden"); + } template void Collection::setData (int index, int column, const QVariant& data) diff --git a/apps/opencs/model/world/collectionbase.hpp b/apps/opencs/model/world/collectionbase.hpp index aad40d36b..62f4079fc 100644 --- a/apps/opencs/model/world/collectionbase.hpp +++ b/apps/opencs/model/world/collectionbase.hpp @@ -13,6 +13,7 @@ namespace CSMWorld { struct ColumnBase; struct RecordBase; + class NestedTableWrapperBase; /// \brief Base class for record collections /// @@ -33,10 +34,10 @@ namespace CSMWorld virtual ~CollectionBase(); virtual int getSize() const = 0; - - virtual int getNestedRowsCount(int row, int column) const; - virtual int getNestedColumnsCount(int row, int column) const; + virtual int getNestedRowsCount(int row, int column) const; + + virtual int getNestedColumnsCount(int row, int column) const; virtual std::string getId (int index) const = 0; @@ -50,6 +51,10 @@ namespace CSMWorld virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const = 0; + virtual NestedTableWrapperBase nestedTable(int row, int column) const = 0; + + virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable) = 0; + virtual void setData (int index, int column, const QVariant& data) = 0; virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn); diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 012736697..5e886bdb4 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -177,26 +177,10 @@ CSMWorld::DeleteNestedCommand::DeleteNestedCommand (IdTable& model, const std::s mModel(model), mParentColumn(parentColumn), QUndoCommand(parent), - mNestedRow(nestedRow) + mNestedRow(nestedRow), + mOld(model.nestedTable(model.getModelIndex(id, parentColumn))) { setText (("Delete nested row in " + mId).c_str()); - - const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); - - const int columnsCount = mModel.columnCount(parentIndex); - - for (int i = 0; i < columnsCount; ++i) - { - const QModelIndex& childIndex = mModel.index(nestedRow, i, parentIndex); - - QVariant data = childIndex.data(); - if (!data.isValid()) - { - data = childIndex.data(Qt::DisplayRole); - } - - mOld.push_back(data); - } } void CSMWorld::DeleteNestedCommand::redo() @@ -211,14 +195,7 @@ void CSMWorld::DeleteNestedCommand::undo() { const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); - mModel.addNestedRow(parentIndex, mNestedRow); - - for (int i = 0; i < mModel.columnCount(parentIndex); ++i) - { - const QModelIndex& current = mModel.index(mNestedRow, i, parentIndex); - - mModel.setData(current, mOld[i]); - } + mModel.setNestedTable(parentIndex, mOld); } CSMWorld::AddNestedCommand::AddNestedCommand(IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent) @@ -226,7 +203,8 @@ CSMWorld::AddNestedCommand::AddNestedCommand(IdTable& model, const std::string& mId(id), mNewRow(nestedRow), mParentColumn(parentColumn), - QUndoCommand(parent) + QUndoCommand(parent), + mOld(model.nestedTable(model.getModelIndex(id, parentColumn))) { setText (("Added nested row in " + mId).c_str()); } @@ -241,6 +219,6 @@ void CSMWorld::AddNestedCommand::redo() void CSMWorld::AddNestedCommand::undo() { const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); - - mModel.removeRows(mNewRow, 1, parentIndex); + + mModel.setNestedTable(parentIndex, mOld); } diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index e6f2d9724..214a5157e 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -13,6 +13,7 @@ #include #include "universalid.hpp" +#include "nestedtablewrapper.hpp" class QModelIndex; class QAbstractItemModel; @@ -22,6 +23,7 @@ namespace CSMWorld class IdTable; class IdTable; class RecordBase; + class NestedTableWrapperBase; class ModifyCommand : public QUndoCommand { @@ -143,7 +145,7 @@ namespace CSMWorld std::string mId; - std::vector mOld; + NestedTableWrapperBase mOld; int mParentColumn; @@ -164,6 +166,8 @@ namespace CSMWorld std::string mId; + NestedTableWrapperBase mOld; + int mNewRow; int mParentColumn; diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index a3435180c..df0f4546d 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -2,6 +2,7 @@ #include #include +#include "nestedtablewrapper.hpp" #include "collectionbase.hpp" #include "columnbase.hpp" @@ -357,3 +358,23 @@ bool CSMWorld::IdTable::hasChildren(const QModelIndex& index) const mIdCollection->getColumn(index.column()).mCanNest && index.data().isValid()); } + +void CSMWorld::IdTable::setNestedTable(const QModelIndex& index, const CSMWorld::NestedTableWrapperBase& nestedTable) +{ + if (!hasChildren(index)) + { + throw std::logic_error("Tried to set nested table, but index has no children"); + } + + mIdCollection->setNestedTable(index.row(), index.column(), nestedTable); +} + +CSMWorld::NestedTableWrapperBase CSMWorld::IdTable::nestedTable(const QModelIndex& index) const +{ + if (!hasChildren(index)) + { + throw std::logic_error("Tried to retrive nested table, but index has no children"); + } + + return mIdCollection->nestedTable(index.row(), index.column()); +} diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index fcb87c8b2..fd3f699ba 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -20,6 +20,7 @@ namespace CSMWorld { class CollectionBase; class RecordBase; + class NestedTableWrapperBase; class IdTable : public IdTableBase { @@ -51,6 +52,10 @@ namespace CSMWorld virtual QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; QVariant nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + + NestedTableWrapperBase nestedTable(const QModelIndex &index) const; + + void setNestedTable(const QModelIndex &index, const NestedTableWrapperBase& nestedTable); virtual bool setData ( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); diff --git a/apps/opencs/model/world/nestedtablewrapper.cpp b/apps/opencs/model/world/nestedtablewrapper.cpp new file mode 100644 index 000000000..387bc6e7b --- /dev/null +++ b/apps/opencs/model/world/nestedtablewrapper.cpp @@ -0,0 +1,7 @@ +#include "nestedtablewrapper.hpp" + +CSMWorld::NestedTableWrapperBase::NestedTableWrapperBase() +{} + +CSMWorld::NestedTableWrapperBase::~NestedTableWrapperBase() +{} diff --git a/apps/opencs/model/world/nestedtablewrapper.hpp b/apps/opencs/model/world/nestedtablewrapper.hpp new file mode 100644 index 000000000..9fc21f8e0 --- /dev/null +++ b/apps/opencs/model/world/nestedtablewrapper.hpp @@ -0,0 +1,33 @@ +#ifndef CSM_WOLRD_NESTEDTABLEWRAPPER_H +#define CSM_WOLRD_NESTEDTABLEWRAPPER_H + +#include + +#include +namespace CSMWorld +{ + struct NestedTableWrapperBase + { + virtual ~NestedTableWrapperBase(); + + NestedTableWrapperBase(); + }; + + template + class NestedTableWrapper : public NestedTableWrapperBase + { + NestedTable mNestedTable; + + public: + + NestedTableWrapper(const NestedTable& nestedTable) {} + + NestedTable getNestedTable() const + { + return mNestedTable; + } + + virtual ~NestedTableWrapper() {} + }; +} +#endif diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index 068347fda..f4aa769fd 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -10,6 +10,7 @@ namespace CSMWorld class RefIdColumn; class RefIdData; class RecordBase; + class NestedTableWrapperBase; class RefIdAdapter { @@ -41,7 +42,7 @@ namespace CSMWorld NestedRefIdAdapter(); virtual ~NestedRefIdAdapter(); - + virtual void setNestedData (const RefIdColumn *column, RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const = 0; @@ -53,8 +54,12 @@ namespace CSMWorld virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const = 0; virtual void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const = 0; - + virtual void addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const = 0; + + virtual void setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) = 0; + + virtual NestedTableWrapperBase nestedTable (const RefIdColumn * column, const RefIdData& data, int index) const = 0; }; } diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 8d6ab838d..cb078ab74 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -1,7 +1,9 @@ #include "refidadapterimp.hpp" +#include "nestedtablewrapper.hpp" #include #include +#include CSMWorld::PotionRefIdAdapter::PotionRefIdAdapter (const InventoryColumns& columns, const RefIdColumn *autoCalc) @@ -305,6 +307,27 @@ void CSMWorld::ContainerRefIdAdapter::setNestedData(const RefIdColumn *column, } } +void CSMWorld::ContainerRefIdAdapter::setNestedTable(const RefIdColumn* column, + RefIdData& data, + int index, + const NestedTableWrapperBase& nestedTable) +{ + Record& record = dynamic_cast&> ( + data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); + + record.get().mInventory.mList = dynamic_cast >&>(nestedTable).getNestedTable(); +} + +CSMWorld::NestedTableWrapperBase CSMWorld::ContainerRefIdAdapter::nestedTable (const RefIdColumn* column, + const RefIdData& data, + int index) const +{ + const Record& record = dynamic_cast&> ( + data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); + + return NestedTableWrapper >(record.get().mInventory.mList); +} + QVariant CSMWorld::ContainerRefIdAdapter::getNestedData (const CSMWorld::RefIdColumn* column, const CSMWorld::RefIdData& data, int index, diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 500b18ef8..4198fb367 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -15,6 +15,8 @@ namespace CSMWorld { + class NestedTableWrapperBase; + struct BaseColumns { const RefIdColumn *mId; @@ -637,6 +639,10 @@ namespace CSMWorld virtual void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const; virtual void addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const; + + virtual NestedTableWrapperBase nestedTable (const RefIdColumn * column, const RefIdData& data, int index) const; + + virtual void setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable); }; struct CreatureColumns : public ActorColumns diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 1a164d12f..6ff0df802 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -10,6 +10,7 @@ #include "refidadapter.hpp" #include "refidadapterimp.hpp" #include "columns.hpp" +#include "nestedtablewrapper.hpp" CSMWorld::RefIdColumn::RefIdColumn (int columnId, Display displayType, int flag, bool editable, bool userEditable, bool canNest) @@ -27,7 +28,7 @@ bool CSMWorld::RefIdColumn::isUserEditable() const } -const CSMWorld::RefIdAdapter& CSMWorld::RefIdCollection::findAdaptor (UniversalId::Type type) const +CSMWorld::RefIdAdapter& CSMWorld::RefIdCollection::findAdaptor (UniversalId::Type type) const { std::map::const_iterator iter = mAdapters.find (type); @@ -641,3 +642,21 @@ void CSMWorld::RefIdCollection::addNestedRow(int row, int col, int position) adaptor.addNestedRow(&mColumns.at(col), mData, localIndex.first, position); } + +void CSMWorld::RefIdCollection::setNestedTable(int row, int column, const CSMWorld::NestedTableWrapperBase& nestedTable) +{ + RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + + CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdaptor (localIndex.second)); + + adaptor.setNestedTable(&mColumns.at(column), mData, localIndex.first, nestedTable); +} + +CSMWorld::NestedTableWrapperBase CSMWorld::RefIdCollection::nestedTable(int row, int column) const +{ + RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + + const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdaptor (localIndex.second)); + + return adaptor.nestedTable(&mColumns.at(column), mData, localIndex.first); +} diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index 02b77400b..927331c93 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -17,6 +17,7 @@ namespace ESM namespace CSMWorld { class RefIdAdapter; + class NestedTableWrapperBase; class RefIdColumn : public NestColumn { @@ -44,7 +45,7 @@ namespace CSMWorld private: - const RefIdAdapter& findAdaptor (UniversalId::Type) const; + RefIdAdapter& findAdaptor (UniversalId::Type) const; ///< Throws an exception if no adaptor for \a Type can be found. public: @@ -70,6 +71,10 @@ namespace CSMWorld virtual QVariant getData (int index, int column) const; virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const; + + virtual NestedTableWrapperBase nestedTable(int row, int column) const; + + virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable); virtual void setData (int index, int column, const QVariant& data); From 0017fc68ef719135cdf82060fbf19e1df4582377 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Sat, 19 Jul 2014 13:08:28 +0200 Subject: [PATCH 055/740] fixed ctor of nestedwrapper (missing initialization of member data field) --- apps/opencs/model/world/nestedtablewrapper.hpp | 3 ++- apps/opencs/model/world/refidadapterimp.cpp | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/nestedtablewrapper.hpp b/apps/opencs/model/world/nestedtablewrapper.hpp index 9fc21f8e0..c13a12c62 100644 --- a/apps/opencs/model/world/nestedtablewrapper.hpp +++ b/apps/opencs/model/world/nestedtablewrapper.hpp @@ -20,7 +20,8 @@ namespace CSMWorld public: - NestedTableWrapper(const NestedTable& nestedTable) {} + NestedTableWrapper(const NestedTable& nestedTable) + : mNestedTable(nestedTable) {} NestedTable getNestedTable() const { diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index cb078ab74..d669a369c 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -1,9 +1,10 @@ #include "refidadapterimp.hpp" -#include "nestedtablewrapper.hpp" #include #include + #include +#include "nestedtablewrapper.hpp" CSMWorld::PotionRefIdAdapter::PotionRefIdAdapter (const InventoryColumns& columns, const RefIdColumn *autoCalc) @@ -315,7 +316,7 @@ void CSMWorld::ContainerRefIdAdapter::setNestedTable(const RefIdColumn* column, Record& record = dynamic_cast&> ( data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); - record.get().mInventory.mList = dynamic_cast >&>(nestedTable).getNestedTable(); + record.get().mInventory.mList = (dynamic_cast >&>(nestedTable)).getNestedTable(); } CSMWorld::NestedTableWrapperBase CSMWorld::ContainerRefIdAdapter::nestedTable (const RefIdColumn* column, From 4d79034dbfa1f5c19e05c56045b779430919cf59 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Sun, 20 Jul 2014 18:52:35 +0200 Subject: [PATCH 056/740] correctly handling the nestedTable for undo (but removing and adding rows in proper QT way is still TODO) --- apps/opencs/model/world/collection.hpp | 8 +++++--- apps/opencs/model/world/collectionbase.hpp | 2 +- apps/opencs/model/world/commands.cpp | 19 +++++++++++++++---- apps/opencs/model/world/commands.hpp | 8 ++++++-- apps/opencs/model/world/idtable.cpp | 5 ++++- apps/opencs/model/world/idtable.hpp | 2 +- .../opencs/model/world/nestedtablewrapper.hpp | 14 ++------------ apps/opencs/model/world/refidadapter.hpp | 2 +- apps/opencs/model/world/refidadapterimp.cpp | 18 +++++++++--------- apps/opencs/model/world/refidadapterimp.hpp | 2 +- apps/opencs/model/world/refidcollection.cpp | 2 +- apps/opencs/model/world/refidcollection.hpp | 2 +- 12 files changed, 47 insertions(+), 37 deletions(-) diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index ac4351986..591074372 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include @@ -92,7 +93,7 @@ namespace CSMWorld virtual void setData (int index, int column, const QVariant& data); - virtual NestedTableWrapperBase nestedTable(int row, int column) const; + virtual NestedTableWrapperBase* nestedTable(int row, int column) const; virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable); @@ -308,9 +309,10 @@ namespace CSMWorld } template - NestedTableWrapperBase Collection::nestedTable(int row, int column) const + NestedTableWrapperBase* Collection::nestedTable(int row, int column) const { - return NestedTableWrapperBase(); + assert(false); + return new NestedTableWrapperBase(); } template diff --git a/apps/opencs/model/world/collectionbase.hpp b/apps/opencs/model/world/collectionbase.hpp index 62f4079fc..a6ee34e56 100644 --- a/apps/opencs/model/world/collectionbase.hpp +++ b/apps/opencs/model/world/collectionbase.hpp @@ -51,7 +51,7 @@ namespace CSMWorld virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const = 0; - virtual NestedTableWrapperBase nestedTable(int row, int column) const = 0; + virtual NestedTableWrapperBase* nestedTable(int row, int column) const = 0; virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable) = 0; diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 5e886bdb4..f464d75c8 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -4,6 +4,7 @@ #include "idtable.hpp" #include +#include "nestedtablewrapper.hpp" CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelIndex& index, const QVariant& new_, QUndoCommand* parent) @@ -178,7 +179,7 @@ CSMWorld::DeleteNestedCommand::DeleteNestedCommand (IdTable& model, const std::s mParentColumn(parentColumn), QUndoCommand(parent), mNestedRow(nestedRow), - mOld(model.nestedTable(model.getModelIndex(id, parentColumn))) + mOld (model.nestedTable(model.getModelIndex(id, parentColumn))) { setText (("Delete nested row in " + mId).c_str()); } @@ -195,7 +196,12 @@ void CSMWorld::DeleteNestedCommand::undo() { const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); - mModel.setNestedTable(parentIndex, mOld); + mModel.setNestedTable(parentIndex, *mOld); +} + +CSMWorld::DeleteNestedCommand::~DeleteNestedCommand() +{ + delete mOld; } CSMWorld::AddNestedCommand::AddNestedCommand(IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent) @@ -204,7 +210,7 @@ CSMWorld::AddNestedCommand::AddNestedCommand(IdTable& model, const std::string& mNewRow(nestedRow), mParentColumn(parentColumn), QUndoCommand(parent), - mOld(model.nestedTable(model.getModelIndex(id, parentColumn))) + mOld (model.nestedTable(model.getModelIndex(id, parentColumn))) { setText (("Added nested row in " + mId).c_str()); } @@ -220,5 +226,10 @@ void CSMWorld::AddNestedCommand::undo() { const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); - mModel.setNestedTable(parentIndex, mOld); + mModel.setNestedTable(parentIndex, *mOld); +} + +CSMWorld::AddNestedCommand::~AddNestedCommand() +{ + delete mOld; } diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index 214a5157e..d45ec1e36 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -145,7 +145,7 @@ namespace CSMWorld std::string mId; - NestedTableWrapperBase mOld; + NestedTableWrapperBase* mOld; int mParentColumn; @@ -155,6 +155,8 @@ namespace CSMWorld DeleteNestedCommand (IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0); + ~DeleteNestedCommand(); + virtual void redo(); virtual void undo(); @@ -166,7 +168,7 @@ namespace CSMWorld std::string mId; - NestedTableWrapperBase mOld; + NestedTableWrapperBase* mOld; int mNewRow; @@ -175,6 +177,8 @@ namespace CSMWorld public: AddNestedCommand(IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0); + + ~AddNestedCommand(); virtual void redo(); diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index df0f4546d..dd045cb78 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -367,9 +367,12 @@ void CSMWorld::IdTable::setNestedTable(const QModelIndex& index, const CSMWorld: } mIdCollection->setNestedTable(index.row(), index.column(), nestedTable); + + emit dataChanged (CSMWorld::IdTable::index (index.row(), 0), + CSMWorld::IdTable::index (index.row(), mIdCollection->getColumns()-1)); } -CSMWorld::NestedTableWrapperBase CSMWorld::IdTable::nestedTable(const QModelIndex& index) const +CSMWorld::NestedTableWrapperBase* CSMWorld::IdTable::nestedTable(const QModelIndex& index) const { if (!hasChildren(index)) { diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index fd3f699ba..b7ba8c342 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -53,7 +53,7 @@ namespace CSMWorld QVariant nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role = Qt::DisplayRole) const; - NestedTableWrapperBase nestedTable(const QModelIndex &index) const; + NestedTableWrapperBase* nestedTable(const QModelIndex &index) const; void setNestedTable(const QModelIndex &index, const NestedTableWrapperBase& nestedTable); diff --git a/apps/opencs/model/world/nestedtablewrapper.hpp b/apps/opencs/model/world/nestedtablewrapper.hpp index c13a12c62..70e35f68a 100644 --- a/apps/opencs/model/world/nestedtablewrapper.hpp +++ b/apps/opencs/model/world/nestedtablewrapper.hpp @@ -1,9 +1,6 @@ #ifndef CSM_WOLRD_NESTEDTABLEWRAPPER_H #define CSM_WOLRD_NESTEDTABLEWRAPPER_H -#include - -#include namespace CSMWorld { struct NestedTableWrapperBase @@ -14,20 +11,13 @@ namespace CSMWorld }; template - class NestedTableWrapper : public NestedTableWrapperBase + struct NestedTableWrapper : public NestedTableWrapperBase { NestedTable mNestedTable; - public: - - NestedTableWrapper(const NestedTable& nestedTable) + NestedTableWrapper(const NestedTable& nestedTable) : mNestedTable(nestedTable) {} - NestedTable getNestedTable() const - { - return mNestedTable; - } - virtual ~NestedTableWrapper() {} }; } diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index f4aa769fd..f7064ab66 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -59,7 +59,7 @@ namespace CSMWorld virtual void setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) = 0; - virtual NestedTableWrapperBase nestedTable (const RefIdColumn * column, const RefIdData& data, int index) const = 0; + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, const RefIdData& data, int index) const = 0; }; } diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index d669a369c..173e89f56 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -227,24 +227,24 @@ void CSMWorld::ContainerRefIdAdapter::removeNestedRow (const RefIdColumn *column std::vector& list = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))).get().mInventory.mList; - + list.erase (list.begin () + rowToRemove); } void CSMWorld::ContainerRefIdAdapter::addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const { assert(column==mContent); - + std::vector& list = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))).get().mInventory.mList; - + ESM::ContItem newRow = {0, ""}; if (position >= (int)list.size()) { list.push_back(newRow); return; } - + list.insert(list.begin()+position, newRow); return; @@ -310,23 +310,23 @@ void CSMWorld::ContainerRefIdAdapter::setNestedData(const RefIdColumn *column, void CSMWorld::ContainerRefIdAdapter::setNestedTable(const RefIdColumn* column, RefIdData& data, - int index, + int index, const NestedTableWrapperBase& nestedTable) { Record& record = dynamic_cast&> ( data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); - record.get().mInventory.mList = (dynamic_cast >&>(nestedTable)).getNestedTable(); + record.get().mInventory.mList = (static_cast >&>(nestedTable)).mNestedTable; } -CSMWorld::NestedTableWrapperBase CSMWorld::ContainerRefIdAdapter::nestedTable (const RefIdColumn* column, - const RefIdData& data, +CSMWorld::NestedTableWrapperBase* CSMWorld::ContainerRefIdAdapter::nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const { const Record& record = dynamic_cast&> ( data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); - return NestedTableWrapper >(record.get().mInventory.mList); + return new NestedTableWrapper >(record.get().mInventory.mList); } QVariant CSMWorld::ContainerRefIdAdapter::getNestedData (const CSMWorld::RefIdColumn* column, diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 4198fb367..ab05cfbc5 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -640,7 +640,7 @@ namespace CSMWorld virtual void addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const; - virtual NestedTableWrapperBase nestedTable (const RefIdColumn * column, const RefIdData& data, int index) const; + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn * column, const RefIdData& data, int index) const; virtual void setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable); }; diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 6ff0df802..80ac1cc3b 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -652,7 +652,7 @@ void CSMWorld::RefIdCollection::setNestedTable(int row, int column, const CSMWor adaptor.setNestedTable(&mColumns.at(column), mData, localIndex.first, nestedTable); } -CSMWorld::NestedTableWrapperBase CSMWorld::RefIdCollection::nestedTable(int row, int column) const +CSMWorld::NestedTableWrapperBase* CSMWorld::RefIdCollection::nestedTable(int row, int column) const { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index 927331c93..cc7609a58 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -72,7 +72,7 @@ namespace CSMWorld virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const; - virtual NestedTableWrapperBase nestedTable(int row, int column) const; + virtual NestedTableWrapperBase* nestedTable(int row, int column) const; virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable); From 87eed066c24ddd10095b8c680fe730103718a164 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Sun, 20 Jul 2014 22:39:39 +0200 Subject: [PATCH 057/740] undo works now --- apps/opencs/CMakeLists.txt | 4 ++-- apps/opencs/model/world/idtable.cpp | 12 ++++++++++++ apps/opencs/model/world/idtable.hpp | 9 +++++++-- apps/opencs/model/world/nestedtablemodel.cpp | 18 ++++++++++++++++++ apps/opencs/model/world/nestedtablemodel.hpp | 4 ++++ apps/opencs/model/world/nestedtablewrapper.cpp | 5 +++++ apps/opencs/model/world/nestedtablewrapper.hpp | 9 ++++++++- 7 files changed, 56 insertions(+), 5 deletions(-) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index bcc64b60a..a9c56f9fa 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -19,12 +19,12 @@ opencs_hdrs_noqt (model/doc opencs_units (model/world idtable idtableproxymodel regionmap data commanddispatcher - idtablebase resourcetable nestedtablemodel nestedtablewrapper + idtablebase resourcetable nestedtablemodel ) opencs_units_noqt (model/world - universalid record commands columnbase scriptcontext cell refidcollection + nestedtablewrapper universalid record commands columnbase scriptcontext cell refidcollection refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager ) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index dd045cb78..be31d0503 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -366,10 +366,22 @@ void CSMWorld::IdTable::setNestedTable(const QModelIndex& index, const CSMWorld: throw std::logic_error("Tried to set nested table, but index has no children"); } + bool removeRowsMode = false; + if (nestedTable.size() != this->nestedTable(index)->size()) + { + emit resetStart(this->index(index.row(), 0).data().toString()); + removeRowsMode = true; + } + mIdCollection->setNestedTable(index.row(), index.column(), nestedTable); emit dataChanged (CSMWorld::IdTable::index (index.row(), 0), CSMWorld::IdTable::index (index.row(), mIdCollection->getColumns()-1)); + + if (removeRowsMode) + { + emit resetEnd(this->index(index.row(), 0).data().toString()); + } } CSMWorld::NestedTableWrapperBase* CSMWorld::IdTable::nestedTable(const QModelIndex& index) const diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index b7ba8c342..d755822b5 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -52,9 +52,9 @@ namespace CSMWorld virtual QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; QVariant nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role = Qt::DisplayRole) const; - + NestedTableWrapperBase* nestedTable(const QModelIndex &index) const; - + void setNestedTable(const QModelIndex &index, const NestedTableWrapperBase& nestedTable); virtual bool setData ( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); @@ -105,6 +105,11 @@ namespace CSMWorld virtual bool isDeleted (const std::string& id) const; int getColumnId(int column) const; + + signals: + void resetStart(const QString& id); + + void resetEnd(const QString& id); }; } diff --git a/apps/opencs/model/world/nestedtablemodel.cpp b/apps/opencs/model/world/nestedtablemodel.cpp index f0b510244..734047b8d 100644 --- a/apps/opencs/model/world/nestedtablemodel.cpp +++ b/apps/opencs/model/world/nestedtablemodel.cpp @@ -26,6 +26,12 @@ CSMWorld::NestedTableModel::NestedTableModel(const QModelIndex& parent, connect(mMainModel, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), this, SLOT(forwardRowsRemoved(const QModelIndex &, int, int))); + + connect(mMainModel, SIGNAL(resetStart(const QString&)), + this, SLOT(forwardResetStart(const QString&))); + + connect(mMainModel, SIGNAL(resetEnd(const QString&)), + this, SLOT(forwardResetEnd(const QString&))); } QModelIndex CSMWorld::NestedTableModel::mapFromSource(const QModelIndex& sourceIndex) const @@ -157,3 +163,15 @@ void CSMWorld::NestedTableModel::forwardRowsRemoved(const QModelIndex& parent, i endRemoveRows(); } } + +void CSMWorld::NestedTableModel::forwardResetStart(const QString& id) +{ + if (id.toUtf8() == mId.c_str()) + beginResetModel(); +} + +void CSMWorld::NestedTableModel::forwardResetEnd(const QString& id) +{ + if (id.toUtf8() == mId.c_str()) + endResetModel(); +} diff --git a/apps/opencs/model/world/nestedtablemodel.hpp b/apps/opencs/model/world/nestedtablemodel.hpp index dfb231124..5fea5c006 100644 --- a/apps/opencs/model/world/nestedtablemodel.hpp +++ b/apps/opencs/model/world/nestedtablemodel.hpp @@ -70,6 +70,10 @@ namespace CSMWorld void forwardRowsAboutToRemoved(const QModelIndex & parent, int first, int last); void forwardRowsRemoved(const QModelIndex & parent, int first, int last); + + void forwardResetStart(const QString& id); + + void forwardResetEnd(const QString& id); }; } diff --git a/apps/opencs/model/world/nestedtablewrapper.cpp b/apps/opencs/model/world/nestedtablewrapper.cpp index 387bc6e7b..3966dbc57 100644 --- a/apps/opencs/model/world/nestedtablewrapper.cpp +++ b/apps/opencs/model/world/nestedtablewrapper.cpp @@ -5,3 +5,8 @@ CSMWorld::NestedTableWrapperBase::NestedTableWrapperBase() CSMWorld::NestedTableWrapperBase::~NestedTableWrapperBase() {} + +int CSMWorld::NestedTableWrapperBase::size() const +{ + return -5; +} diff --git a/apps/opencs/model/world/nestedtablewrapper.hpp b/apps/opencs/model/world/nestedtablewrapper.hpp index 70e35f68a..f0ca00dbe 100644 --- a/apps/opencs/model/world/nestedtablewrapper.hpp +++ b/apps/opencs/model/world/nestedtablewrapper.hpp @@ -7,9 +7,11 @@ namespace CSMWorld { virtual ~NestedTableWrapperBase(); + virtual int size() const; + NestedTableWrapperBase(); }; - + template struct NestedTableWrapper : public NestedTableWrapperBase { @@ -19,6 +21,11 @@ namespace CSMWorld : mNestedTable(nestedTable) {} virtual ~NestedTableWrapper() {} + + virtual int size() const + { + return mNestedTable.size(); //i hope that this will be enough + } }; } #endif From 3dd2ca15da9228f1463d59800b71dfc54a31f95d Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 21 Jul 2014 09:52:09 +0200 Subject: [PATCH 058/740] Reduced code duplication through new common base class --- apps/opencs/model/world/commands.cpp | 23 +++++++++++++---------- apps/opencs/model/world/commands.hpp | 26 ++++++++++++++++---------- 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index f464d75c8..0d9f6c773 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -179,7 +179,7 @@ CSMWorld::DeleteNestedCommand::DeleteNestedCommand (IdTable& model, const std::s mParentColumn(parentColumn), QUndoCommand(parent), mNestedRow(nestedRow), - mOld (model.nestedTable(model.getModelIndex(id, parentColumn))) + NestedTableStoring(model, id, parentColumn) { setText (("Delete nested row in " + mId).c_str()); } @@ -196,12 +196,7 @@ void CSMWorld::DeleteNestedCommand::undo() { const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); - mModel.setNestedTable(parentIndex, *mOld); -} - -CSMWorld::DeleteNestedCommand::~DeleteNestedCommand() -{ - delete mOld; + mModel.setNestedTable(parentIndex, getOld()); } CSMWorld::AddNestedCommand::AddNestedCommand(IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent) @@ -210,7 +205,7 @@ CSMWorld::AddNestedCommand::AddNestedCommand(IdTable& model, const std::string& mNewRow(nestedRow), mParentColumn(parentColumn), QUndoCommand(parent), - mOld (model.nestedTable(model.getModelIndex(id, parentColumn))) + NestedTableStoring(model, id, parentColumn) { setText (("Added nested row in " + mId).c_str()); } @@ -226,10 +221,18 @@ void CSMWorld::AddNestedCommand::undo() { const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); - mModel.setNestedTable(parentIndex, *mOld); + mModel.setNestedTable(parentIndex, getOld()); } -CSMWorld::AddNestedCommand::~AddNestedCommand() +CSMWorld::NestedTableStoring::NestedTableStoring(const IdTable& model, const std::string& id, int parentColumn) + : mOld(model.nestedTable(model.getModelIndex(id, parentColumn))) {} + +CSMWorld::NestedTableStoring::~NestedTableStoring() { delete mOld; } + +const CSMWorld::NestedTableWrapperBase& CSMWorld::NestedTableStoring::getOld() const +{ + return *mOld; +} diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index d45ec1e36..d868ccf46 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -139,14 +139,26 @@ namespace CSMWorld virtual void undo(); }; - class DeleteNestedCommand : public QUndoCommand + class NestedTableStoring + { + NestedTableWrapperBase* mOld; + + public: + NestedTableStoring(const IdTable& model, const std::string& id, int parentColumn); + + ~NestedTableStoring(); + + protected: + + const NestedTableWrapperBase& getOld() const; + }; + + class DeleteNestedCommand : public QUndoCommand, private NestedTableStoring { IdTable& mModel; std::string mId; - NestedTableWrapperBase* mOld; - int mParentColumn; int mNestedRow; @@ -155,21 +167,17 @@ namespace CSMWorld DeleteNestedCommand (IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0); - ~DeleteNestedCommand(); - virtual void redo(); virtual void undo(); }; - class AddNestedCommand : public QUndoCommand + class AddNestedCommand : public QUndoCommand, private NestedTableStoring { IdTable& mModel; std::string mId; - NestedTableWrapperBase* mOld; - int mNewRow; int mParentColumn; @@ -177,8 +185,6 @@ namespace CSMWorld public: AddNestedCommand(IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0); - - ~AddNestedCommand(); virtual void redo(); From c4598d6200e21de1df91234dad7637a04c62f36d Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 21 Jul 2014 14:09:00 +0200 Subject: [PATCH 059/740] added inventory helper (since npc and containers share same way of handling items) --- apps/opencs/CMakeLists.txt | 3 +- apps/opencs/model/world/nestedadaptors.cpp | 1 + apps/opencs/model/world/nestedadaptors.hpp | 56 +++++++++++++++++++++ apps/opencs/model/world/refidadapterimp.cpp | 12 ++--- apps/opencs/model/world/refidadapterimp.hpp | 3 ++ 5 files changed, 65 insertions(+), 10 deletions(-) create mode 100644 apps/opencs/model/world/nestedadaptors.cpp create mode 100644 apps/opencs/model/world/nestedadaptors.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index a9c56f9fa..08c105c92 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -25,7 +25,8 @@ opencs_units (model/world opencs_units_noqt (model/world nestedtablewrapper universalid record commands columnbase scriptcontext cell refidcollection - refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager + refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection + tablemimedata cellcoordinates cellselection resources resourcesmanager nestedadaptors ) opencs_hdrs_noqt (model/world diff --git a/apps/opencs/model/world/nestedadaptors.cpp b/apps/opencs/model/world/nestedadaptors.cpp new file mode 100644 index 000000000..8ed1819b8 --- /dev/null +++ b/apps/opencs/model/world/nestedadaptors.cpp @@ -0,0 +1 @@ +#include "nestedadaptors.hpp" diff --git a/apps/opencs/model/world/nestedadaptors.hpp b/apps/opencs/model/world/nestedadaptors.hpp new file mode 100644 index 000000000..c0ca9744c --- /dev/null +++ b/apps/opencs/model/world/nestedadaptors.hpp @@ -0,0 +1,56 @@ +#ifndef CSM_WORLD_NESTEDADAPTORS_H +#define CSM_WORLD_NESTEDADAPTORS_H + +#include + +#include "universalid.hpp" +#include "nestedtablewrapper.hpp" +#include +#include "record.hpp" +#include "refiddata.hpp" +#include "refidadapter.hpp" + +namespace CSMWorld +{ + template + class InventoryHelper + { + CSMWorld::UniversalId::Type mType; + + public: + + InventoryHelper(CSMWorld::UniversalId::Type type) : mType(type) {}; + + void setNestedTable(const RefIdColumn* column, + RefIdData& data, + int index, + const NestedTableWrapperBase& nestedTable) + { + getRecord(data, index).get().mInventory.mList = + (static_cast >&>(nestedTable)).mNestedTable; + } + + NestedTableWrapperBase* nestedTable(const RefIdColumn* column, + const RefIdData& data, + int index) const + { + return new NestedTableWrapper >(getRecord(data, index).get().mInventory.mList); + } + + private: + + const Record& getRecord(const RefIdData& data, int index) const + { + return dynamic_cast&> ( + data.getRecord (RefIdData::LocalIndex (index, mType))); + } + + Record& getRecord(RefIdData& data, int index) const + { + return dynamic_cast&> ( + data.getRecord (RefIdData::LocalIndex (index, mType))); + } + }; +} + +#endif diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 173e89f56..08d890957 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -180,7 +180,7 @@ void CSMWorld::ClothingRefIdAdapter::setData (const RefIdColumn *column, RefIdDa CSMWorld::ContainerRefIdAdapter::ContainerRefIdAdapter (const NameColumns& columns, const RefIdColumn *weight, const RefIdColumn *organic, const RefIdColumn *respawn, const RefIdColumn *content) : NameRefIdAdapter (UniversalId::Type_Container, columns), mWeight (weight), - mOrganic (organic), mRespawn (respawn), mContent(content) + mOrganic (organic), mRespawn (respawn), mContent(content), mHelper(InventoryHelper(UniversalId::Type_Container)) {} int CSMWorld::ContainerRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const @@ -313,20 +313,14 @@ void CSMWorld::ContainerRefIdAdapter::setNestedTable(const RefIdColumn* column, int index, const NestedTableWrapperBase& nestedTable) { - Record& record = dynamic_cast&> ( - data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); - - record.get().mInventory.mList = (static_cast >&>(nestedTable)).mNestedTable; + mHelper.setNestedTable(column, data, index, nestedTable); } CSMWorld::NestedTableWrapperBase* CSMWorld::ContainerRefIdAdapter::nestedTable (const RefIdColumn* column, const RefIdData& data, int index) const { - const Record& record = dynamic_cast&> ( - data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); - - return new NestedTableWrapper >(record.get().mInventory.mList); + return mHelper.nestedTable(column, data, index); } QVariant CSMWorld::ContainerRefIdAdapter::getNestedData (const CSMWorld::RefIdColumn* column, diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index ab05cfbc5..aac2ba807 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -12,6 +12,7 @@ #include "refiddata.hpp" #include "universalid.hpp" #include "refidadapter.hpp" +#include "nestedadaptors.hpp" namespace CSMWorld { @@ -614,6 +615,8 @@ namespace CSMWorld const RefIdColumn *mOrganic; const RefIdColumn *mRespawn; const RefIdColumn *mContent; + + InventoryHelper mHelper; public: From 6573e3f319e27d7bbcdc3e209f941fae9fb257df Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 21 Jul 2014 14:24:54 +0200 Subject: [PATCH 060/740] moved responsibility for getNestedData to the inventory helper --- apps/opencs/model/world/nestedadaptors.hpp | 23 +++++++++++++++++++++ apps/opencs/model/world/refidadapterimp.cpp | 17 +-------------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/apps/opencs/model/world/nestedadaptors.hpp b/apps/opencs/model/world/nestedadaptors.hpp index c0ca9744c..d5edf3358 100644 --- a/apps/opencs/model/world/nestedadaptors.hpp +++ b/apps/opencs/model/world/nestedadaptors.hpp @@ -10,6 +10,8 @@ #include "refiddata.hpp" #include "refidadapter.hpp" +#include + namespace CSMWorld { template @@ -37,6 +39,27 @@ namespace CSMWorld return new NestedTableWrapper >(getRecord(data, index).get().mInventory.mList); } + QVariant getNestedData(const CSMWorld::RefIdColumn* column, + const CSMWorld::RefIdData& data, + int index, + int subRowIndex, + int subColIndex) const + { + const ESM::ContItem& content = getRecord(data, index).get().mInventory.mList.at(subRowIndex); + + switch (subColIndex) + { + case 0: + return QString::fromUtf8(content.mItem.toString().c_str()); + + case 1: + return content.mCount; + + default: + throw std::logic_error("Trying to access non-existing column in the nested table!"); + } + } + private: const Record& getRecord(const RefIdData& data, int index) const diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 08d890957..3622c77af 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -329,24 +329,9 @@ QVariant CSMWorld::ContainerRefIdAdapter::getNestedData (const CSMWorld::RefIdCo int subRowIndex, int subColIndex) const { - const Record& record = static_cast&> ( - data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); - if (column==mContent) { - const ESM::ContItem& content = record.get().mInventory.mList.at(subRowIndex); - - switch (subColIndex) - { - case 0: - return QString::fromUtf8(content.mItem.toString().c_str()); - - case 1: - return content.mCount; - - default: - throw std::logic_error("Trying to access non-existing column in the nested table!"); - } + return mHelper.getNestedData(column, data, index, subRowIndex, subColIndex); } else { throw std::logic_error("This column does not hold multiple values."); From cb004936e03cc802211d31ee165f3670fcbe1989 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 21 Jul 2014 14:34:48 +0200 Subject: [PATCH 061/740] moved setNestedData to the helper as well --- apps/opencs/model/world/nestedadaptors.hpp | 23 +++++++++++++++++++++ apps/opencs/model/world/refidadapterimp.cpp | 19 ++--------------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/apps/opencs/model/world/nestedadaptors.hpp b/apps/opencs/model/world/nestedadaptors.hpp index d5edf3358..8f82482d8 100644 --- a/apps/opencs/model/world/nestedadaptors.hpp +++ b/apps/opencs/model/world/nestedadaptors.hpp @@ -2,6 +2,7 @@ #define CSM_WORLD_NESTEDADAPTORS_H #include +#include #include "universalid.hpp" #include "nestedtablewrapper.hpp" @@ -59,6 +60,28 @@ namespace CSMWorld throw std::logic_error("Trying to access non-existing column in the nested table!"); } } + + void setNestedData (const RefIdColumn *column, + RefIdData& data, + int index, + const QVariant& value, + int subRowIndex, + int subColIndex) const + { + switch(subColIndex) + { + case 0: + getRecord(data, index).get().mInventory.mList.at(subRowIndex).mItem.assign(std::string(value.toString().toUtf8().constData())); + break; + + case 1: + getRecord(data, index).get().mInventory.mList.at(subRowIndex).mCount = value.toInt(); + break; + + default: + throw std::logic_error("Trying to access non-existing column in the nested table!"); + } + } private: diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 3622c77af..3600562d3 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -285,23 +285,8 @@ void CSMWorld::ContainerRefIdAdapter::setNestedData(const RefIdColumn *column, { if (column==mContent) - { - Record& record = static_cast&> ( - data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); - - switch (subColIndex) - { - case 0: - record.get().mInventory.mList.at(subRowIndex).mItem.assign(std::string(value.toString().toUtf8().constData())); - break; - - case 1: - record.get().mInventory.mList.at(subRowIndex).mCount = value.toInt(); - break; - - default: - throw std::logic_error("Trying to access non-existing column in the nested table!"); - } + { + mHelper.setNestedData(column, data, index, value, subRowIndex, subColIndex); } else { assert(false); From c018ca43ac1f00b4ece1215f0776b069941f71ce Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 21 Jul 2014 14:44:48 +0200 Subject: [PATCH 062/740] getting rid of the asserts --- apps/opencs/model/world/refidadapterimp.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 3600562d3..f85138d97 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -223,7 +223,10 @@ QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, co void CSMWorld::ContainerRefIdAdapter::removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const { - assert(column==mContent); + if(column!=mContent) + { + throw std::logic_error("This column does not hold multiple values."); + } std::vector& list = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))).get().mInventory.mList; @@ -289,7 +292,7 @@ void CSMWorld::ContainerRefIdAdapter::setNestedData(const RefIdColumn *column, mHelper.setNestedData(column, data, index, value, subRowIndex, subColIndex); } else { - assert(false); + throw std::logic_error("This column do not nest other columns"); } } @@ -319,7 +322,7 @@ QVariant CSMWorld::ContainerRefIdAdapter::getNestedData (const CSMWorld::RefIdCo return mHelper.getNestedData(column, data, index, subRowIndex, subColIndex); } else { - throw std::logic_error("This column does not hold multiple values."); + throw std::logic_error("This column do not nest other columns"); } } From 427d6efd1904a1b574f2566114c32e6147468871 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 21 Jul 2014 14:49:47 +0200 Subject: [PATCH 063/740] Moved removeNestedRow responsibility to the helper. --- apps/opencs/model/world/nestedadaptors.hpp | 7 +++++++ apps/opencs/model/world/refidadapterimp.cpp | 6 +----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/opencs/model/world/nestedadaptors.hpp b/apps/opencs/model/world/nestedadaptors.hpp index 8f82482d8..a961d19e4 100644 --- a/apps/opencs/model/world/nestedadaptors.hpp +++ b/apps/opencs/model/world/nestedadaptors.hpp @@ -61,6 +61,13 @@ namespace CSMWorld } } + void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const + { + std::vector& list = getRecord(data, index).get().mInventory.mList; + + list.erase (list.begin () + rowToRemove); + } + void setNestedData (const RefIdColumn *column, RefIdData& data, int index, diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index f85138d97..2a8fec01d 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -227,11 +227,7 @@ void CSMWorld::ContainerRefIdAdapter::removeNestedRow (const RefIdColumn *column { throw std::logic_error("This column does not hold multiple values."); } - - std::vector& list = static_cast&> ( - data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))).get().mInventory.mList; - - list.erase (list.begin () + rowToRemove); + mHelper.removeNestedRow(column, data, index, rowToRemove); } void CSMWorld::ContainerRefIdAdapter::addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const From dcd90faaef82820d738f34976f7a57daf0907056 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 21 Jul 2014 14:58:45 +0200 Subject: [PATCH 064/740] moved add nested to the helper --- apps/opencs/model/world/nestedadaptors.hpp | 14 ++++++++++++++ apps/opencs/model/world/refidadapterimp.cpp | 15 +++------------ 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/apps/opencs/model/world/nestedadaptors.hpp b/apps/opencs/model/world/nestedadaptors.hpp index a961d19e4..9e747164a 100644 --- a/apps/opencs/model/world/nestedadaptors.hpp +++ b/apps/opencs/model/world/nestedadaptors.hpp @@ -90,6 +90,20 @@ namespace CSMWorld } } + void addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const + { + std::vector& list = getRecord(data, index).get().mInventory.mList; + + ESM::ContItem newRow = {0, ""}; + if (position >= (int)list.size()) + { + list.push_back(newRow); + return; + } + + list.insert(list.begin()+position, newRow); + } + private: const Record& getRecord(const RefIdData& data, int index) const diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 2a8fec01d..5681b8bae 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -232,21 +232,12 @@ void CSMWorld::ContainerRefIdAdapter::removeNestedRow (const RefIdColumn *column void CSMWorld::ContainerRefIdAdapter::addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const { - assert(column==mContent); - - std::vector& list = static_cast&> ( - data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))).get().mInventory.mList; - - ESM::ContItem newRow = {0, ""}; - if (position >= (int)list.size()) + if(column!=mContent) { - list.push_back(newRow); - return; + throw std::logic_error("This column does not hold multiple values."); } - list.insert(list.begin()+position, newRow); - - return; + mHelper.addNestedRow(column, data, index, position); } void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index, From 24eb034ba357f6aa93f944d38a0f948e0bb1d4ad Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 22 Jul 2014 10:27:45 +0200 Subject: [PATCH 065/740] major refactorisation --- apps/opencs/model/world/nestedadaptors.cpp | 7 ++ apps/opencs/model/world/nestedadaptors.hpp | 93 ++++++++++++++++----- apps/opencs/model/world/refidadapter.cpp | 84 ++++++++++++++++++- apps/opencs/model/world/refidadapter.hpp | 45 +++++++++- apps/opencs/model/world/refidadapterimp.cpp | 93 ++------------------- apps/opencs/model/world/refidadapterimp.hpp | 20 ----- 6 files changed, 210 insertions(+), 132 deletions(-) diff --git a/apps/opencs/model/world/nestedadaptors.cpp b/apps/opencs/model/world/nestedadaptors.cpp index 8ed1819b8..1e8425229 100644 --- a/apps/opencs/model/world/nestedadaptors.cpp +++ b/apps/opencs/model/world/nestedadaptors.cpp @@ -1 +1,8 @@ #include "nestedadaptors.hpp" + +CSMWorld::HelperBase::HelperBase(CSMWorld::UniversalId::Type type) + : mType(type) +{} + +CSMWorld::HelperBase::~HelperBase() +{} diff --git a/apps/opencs/model/world/nestedadaptors.hpp b/apps/opencs/model/world/nestedadaptors.hpp index 9e747164a..806dc587d 100644 --- a/apps/opencs/model/world/nestedadaptors.hpp +++ b/apps/opencs/model/world/nestedadaptors.hpp @@ -6,45 +6,85 @@ #include "universalid.hpp" #include "nestedtablewrapper.hpp" -#include #include "record.hpp" #include "refiddata.hpp" #include "refidadapter.hpp" +#include #include namespace CSMWorld { - template - class InventoryHelper + class RefIdColumn; + + class HelperBase { - CSMWorld::UniversalId::Type mType; + protected: + const CSMWorld::UniversalId::Type mType; public: + HelperBase(CSMWorld::UniversalId::Type type); + + virtual ~HelperBase(); + + virtual void setNestedTable(RefIdData& data, + int index, + const NestedTableWrapperBase& nestedTable) = 0; + + virtual NestedTableWrapperBase* nestedTable(const RefIdData& data, + int index) const = 0; + + virtual QVariant getNestedData(const CSMWorld::RefIdData& data, + int index, + int subRowIndex, + int subColIndex) const = 0; + + virtual void removeNestedRow (RefIdData& data, + int index, + int rowToRemove) const = 0; + + virtual void setNestedData (RefIdData& data, + int index, + const QVariant& value, + int subRowIndex, + int subColIndex) const = 0; + + virtual void addNestedRow (RefIdData& data, + int index, + int position) const = 0; - InventoryHelper(CSMWorld::UniversalId::Type type) : mType(type) {}; + virtual int getNestedColumnsCount(const RefIdData& data) const = 0; - void setNestedTable(const RefIdColumn* column, - RefIdData& data, - int index, - const NestedTableWrapperBase& nestedTable) + virtual int getNestedRowsCount(const RefIdData& data, + int index) const = 0; + }; + + template + class InventoryHelper : public HelperBase + { + public: + + InventoryHelper(CSMWorld::UniversalId::Type type) + : HelperBase(type) {} + + virtual void setNestedTable(RefIdData& data, + int index, + const NestedTableWrapperBase& nestedTable) { getRecord(data, index).get().mInventory.mList = (static_cast >&>(nestedTable)).mNestedTable; } - NestedTableWrapperBase* nestedTable(const RefIdColumn* column, - const RefIdData& data, - int index) const + virtual NestedTableWrapperBase* nestedTable(const RefIdData& data, + int index) const { return new NestedTableWrapper >(getRecord(data, index).get().mInventory.mList); } - QVariant getNestedData(const CSMWorld::RefIdColumn* column, - const CSMWorld::RefIdData& data, - int index, - int subRowIndex, - int subColIndex) const + virtual QVariant getNestedData(const CSMWorld::RefIdData& data, + int index, + int subRowIndex, + int subColIndex) const { const ESM::ContItem& content = getRecord(data, index).get().mInventory.mList.at(subRowIndex); @@ -61,15 +101,14 @@ namespace CSMWorld } } - void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const + virtual void removeNestedRow (RefIdData& data, int index, int rowToRemove) const { std::vector& list = getRecord(data, index).get().mInventory.mList; list.erase (list.begin () + rowToRemove); } - void setNestedData (const RefIdColumn *column, - RefIdData& data, + void setNestedData (RefIdData& data, int index, const QVariant& value, int subRowIndex, @@ -90,7 +129,7 @@ namespace CSMWorld } } - void addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const + virtual void addNestedRow (RefIdData& data, int index, int position) const { std::vector& list = getRecord(data, index).get().mInventory.mList; @@ -104,6 +143,18 @@ namespace CSMWorld list.insert(list.begin()+position, newRow); } + virtual int getNestedColumnsCount(const RefIdData& data) const + { + return 2; + } + + + virtual int getNestedRowsCount(const RefIdData& data, + int index) const + { + return getRecord(data, index).get().mInventory.mList.size(); + } + private: const Record& getRecord(const RefIdData& data, int index) const diff --git a/apps/opencs/model/world/refidadapter.cpp b/apps/opencs/model/world/refidadapter.cpp index 50314e7a2..631c192fd 100644 --- a/apps/opencs/model/world/refidadapter.cpp +++ b/apps/opencs/model/world/refidadapter.cpp @@ -1,13 +1,89 @@ - #include "refidadapter.hpp" -#include "cassert" +#include "nestedtablewrapper.hpp" + #include CSMWorld::RefIdAdapter::RefIdAdapter() {} CSMWorld::RefIdAdapter::~RefIdAdapter() {} -CSMWorld::NestedRefIdAdapter::NestedRefIdAdapter() {} +CSMWorld::NestedRefIdAdapterBase::NestedRefIdAdapterBase() {} + +CSMWorld::NestedRefIdAdapterBase::~NestedRefIdAdapterBase() {} + +CSMWorld::NestedRefIdAdapter::NestedRefIdAdapter() +{} + +CSMWorld::NestedRefIdAdapter::~NestedRefIdAdapter() +{ + for (unsigned i = 0; i < mAssociatedColumns.size(); ++i) + { + delete mAssociatedColumns[i].second; + } +} + +void CSMWorld::NestedRefIdAdapter::setNestedData (const RefIdColumn *column, RefIdData& data, int row, + const QVariant& value, int subRowIndex, int subColIndex) const +{ + getHelper(column)->setNestedData(data, row, value, subRowIndex, subColIndex); +} + +QVariant CSMWorld::NestedRefIdAdapter::getNestedData(const RefIdColumn *column, const RefIdData& data, + int index, int subRowIndex, int subColIndex) const +{ + return getHelper(column)->getNestedData(data, index, subRowIndex, subColIndex); +} + +int CSMWorld::NestedRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const +{ + return getHelper(column)->getNestedColumnsCount(data); +} + + +int CSMWorld::NestedRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const +{ + return getHelper(column)->getNestedRowsCount(data, index); +} + + +void CSMWorld::NestedRefIdAdapter::removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const +{ + getHelper(column)->removeNestedRow(data, index, rowToRemove); +} + +void CSMWorld::NestedRefIdAdapter::addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const +{ + getHelper(column)->addNestedRow(data, index, position); //This code grows more boring and boring. I would love some macros. +} + +void CSMWorld::NestedRefIdAdapter::setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) +{ + getHelper(column)->setNestedTable(data, index, nestedTable); +} + + +CSMWorld::NestedTableWrapperBase* CSMWorld::NestedRefIdAdapter::nestedTable (const RefIdColumn* column, const RefIdData& data, int index) const +{ + return getHelper(column)->nestedTable(data, index); +} + +CSMWorld::HelperBase* CSMWorld::NestedRefIdAdapter::getHelper(const RefIdColumn *column) const +{ + for (unsigned i = 0; i < mAssociatedColumns.size(); ++i) + { + if (mAssociatedColumns[i].first == column) + { + return mAssociatedColumns[i].second; + } + } + + throw std::logic_error("No such column in the nestedrefidadapter"); + + return NULL; +} -CSMWorld::NestedRefIdAdapter::~NestedRefIdAdapter() {} \ No newline at end of file +void CSMWorld::NestedRefIdAdapter::setAssocColumns(const std::vector >& assocColumns) +{ + mAssociatedColumns = assocColumns; +} diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index f7064ab66..dd2248e92 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -2,6 +2,9 @@ #define CSM_WOLRD_REFIDADAPTER_H #include +#include + +#include "nestedadaptors.hpp" class QVariant; @@ -11,6 +14,7 @@ namespace CSMWorld class RefIdData; class RecordBase; class NestedTableWrapperBase; + class HelperBase; class RefIdAdapter { @@ -36,12 +40,12 @@ namespace CSMWorld virtual void setId(RecordBase& record, const std::string& id) = 0; }; - class NestedRefIdAdapter + class NestedRefIdAdapterBase { public: - NestedRefIdAdapter(); + NestedRefIdAdapterBase(); - virtual ~NestedRefIdAdapter(); + virtual ~NestedRefIdAdapterBase(); virtual void setNestedData (const RefIdColumn *column, RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const = 0; @@ -61,6 +65,41 @@ namespace CSMWorld virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, const RefIdData& data, int index) const = 0; }; + + class NestedRefIdAdapter : public NestedRefIdAdapterBase + { + std::vector > mAssociatedColumns; //basicly, i wanted map, but with pointer key + + public: + NestedRefIdAdapter(); + + virtual ~NestedRefIdAdapter(); + + virtual void setNestedData (const RefIdColumn *column, RefIdData& data, int row, + const QVariant& value, int subRowIndex, int subColIndex) const; + + virtual QVariant getNestedData (const RefIdColumn *column, const RefIdData& data, + int index, int subRowIndex, int subColIndex) const; + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const; + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; + + virtual void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const; + + virtual void addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const; + + virtual void setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable); + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, const RefIdData& data, int index) const; + + protected: + void setAssocColumns(const std::vector >& assocColumns); + + private: + + HelperBase* getHelper(const RefIdColumn *column) const; + }; } #endif diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 5681b8bae..18287d596 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include "nestedtablewrapper.hpp" @@ -180,28 +181,18 @@ void CSMWorld::ClothingRefIdAdapter::setData (const RefIdColumn *column, RefIdDa CSMWorld::ContainerRefIdAdapter::ContainerRefIdAdapter (const NameColumns& columns, const RefIdColumn *weight, const RefIdColumn *organic, const RefIdColumn *respawn, const RefIdColumn *content) : NameRefIdAdapter (UniversalId::Type_Container, columns), mWeight (weight), - mOrganic (organic), mRespawn (respawn), mContent(content), mHelper(InventoryHelper(UniversalId::Type_Container)) -{} - -int CSMWorld::ContainerRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const -{ - assert(column==mContent); - - return 2; -} - -int CSMWorld::ContainerRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const + mOrganic (organic), mRespawn (respawn), mContent(content) { - assert(column==mContent); - - const Record& record = static_cast&> ( - data.getRecord(RefIdData::LocalIndex (index, UniversalId::Type_Container))); + std::vector > assoCol; - return record.get().mInventory.mList.size(); + assoCol.push_back(std::make_pair(content, new InventoryHelper(UniversalId::Type_Container))); + + setAssocColumns(assoCol); } -QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, - int index) const +QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, + const RefIdData& data, + int index) const { const Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); @@ -221,24 +212,6 @@ QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, co return NameRefIdAdapter::getData (column, data, index); } -void CSMWorld::ContainerRefIdAdapter::removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const -{ - if(column!=mContent) - { - throw std::logic_error("This column does not hold multiple values."); - } - mHelper.removeNestedRow(column, data, index, rowToRemove); -} - -void CSMWorld::ContainerRefIdAdapter::addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const -{ - if(column!=mContent) - { - throw std::logic_error("This column does not hold multiple values."); - } - - mHelper.addNestedRow(column, data, index, position); -} void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const @@ -266,54 +239,6 @@ void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdD NameRefIdAdapter::setData (column, data, index, value); } -void CSMWorld::ContainerRefIdAdapter::setNestedData(const RefIdColumn *column, - RefIdData& data, - int index, - const QVariant& value, - int subRowIndex, - int subColIndex) const -{ - - if (column==mContent) - { - mHelper.setNestedData(column, data, index, value, subRowIndex, subColIndex); - } else - { - throw std::logic_error("This column do not nest other columns"); - } -} - -void CSMWorld::ContainerRefIdAdapter::setNestedTable(const RefIdColumn* column, - RefIdData& data, - int index, - const NestedTableWrapperBase& nestedTable) -{ - mHelper.setNestedTable(column, data, index, nestedTable); -} - -CSMWorld::NestedTableWrapperBase* CSMWorld::ContainerRefIdAdapter::nestedTable (const RefIdColumn* column, - const RefIdData& data, - int index) const -{ - return mHelper.nestedTable(column, data, index); -} - -QVariant CSMWorld::ContainerRefIdAdapter::getNestedData (const CSMWorld::RefIdColumn* column, - const CSMWorld::RefIdData& data, - int index, - int subRowIndex, - int subColIndex) const -{ - if (column==mContent) - { - return mHelper.getNestedData(column, data, index, subRowIndex, subColIndex); - } else - { - throw std::logic_error("This column do not nest other columns"); - } -} - - CSMWorld::CreatureColumns::CreatureColumns (const ActorColumns& actorColumns) : ActorColumns (actorColumns) {} diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index aac2ba807..ee069dd38 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -616,36 +616,16 @@ namespace CSMWorld const RefIdColumn *mRespawn; const RefIdColumn *mContent; - InventoryHelper mHelper; - public: ContainerRefIdAdapter (const NameColumns& columns, const RefIdColumn *weight, const RefIdColumn *organic, const RefIdColumn *respawn, const RefIdColumn *content); - virtual QVariant getNestedData (const RefIdColumn *column, const RefIdData& data, int index, - int subRowIndex, int subColIndex) const; - virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; - virtual void setNestedData (const RefIdColumn *column, RefIdData& data, int index, - const QVariant& value, int subRowIndex, int subColIndex) const; - virtual void setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const; ///< If the data type does not match an exception is thrown. - - virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const; - - virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; - - virtual void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const; - - virtual void addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const; - - virtual NestedTableWrapperBase* nestedTable (const RefIdColumn * column, const RefIdData& data, int index) const; - - virtual void setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable); }; struct CreatureColumns : public ActorColumns From 9defb188ea83a9de4edba735f688a15dc1329e65 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 22 Jul 2014 13:08:32 +0200 Subject: [PATCH 066/740] handle inventory in the actors --- apps/opencs/model/world/columns.hpp | 1 + apps/opencs/model/world/refidadapterimp.hpp | 14 ++++++++++++-- apps/opencs/model/world/refidcollection.cpp | 4 ++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 283e15db7..6812bbae9 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -179,6 +179,7 @@ namespace CSMWorld ColumnId_Vampire = 164, ColumnId_BodyPartType = 165, ColumnId_MeshType = 166, + ColumnId_ActorInventory = 167, // 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/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index ee069dd38..6fe479150 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -445,6 +445,7 @@ namespace CSMWorld const RefIdColumn *mFlee; const RefIdColumn *mFight; const RefIdColumn *mAlarm; + const RefIdColumn *mInventory; std::map mServices; ActorColumns (const NameColumns& base) : NameColumns (base) {} @@ -452,7 +453,7 @@ namespace CSMWorld /// \brief Adapter for actor IDs (handles common AI functionality) template - class ActorRefIdAdapter : public NameRefIdAdapter + class ActorRefIdAdapter : public NameRefIdAdapter, public NestedRefIdAdapter { ActorColumns mActors; @@ -472,7 +473,13 @@ namespace CSMWorld ActorRefIdAdapter::ActorRefIdAdapter (UniversalId::Type type, const ActorColumns& columns) : NameRefIdAdapter (type, columns), mActors (columns) - {} + { + std::vector > assoCol; + + assoCol.push_back(std::make_pair(mActors.mInventory, new InventoryHelper(type))); + + setAssocColumns(assoCol); + } template QVariant ActorRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, @@ -496,6 +503,9 @@ namespace CSMWorld if (column==mActors.mAlarm) return record.get().mAiData.mAlarm; + if (column==mActors.mInventory) + return true; + std::map::const_iterator iter = mActors.mServices.find (column); diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 80ac1cc3b..493b716eb 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -99,6 +99,10 @@ CSMWorld::RefIdCollection::RefIdCollection() actorsColumns.mFight = &mColumns.back(); mColumns.push_back (RefIdColumn (Columns::ColumnId_AiAlarm, ColumnBase::Display_Integer)); actorsColumns.mAlarm = &mColumns.back(); + mColumns.push_back(RefIdColumn (Columns::ColumnId_ActorInventory, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue, true, true, true)); + actorsColumns.mInventory = &mColumns.back(); + mColumns.back().addNestedColumn(Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String); + mColumns.back().addNestedColumn(Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer); static const struct { From 72b129b90e662c10df1d756ea0875197bb517523 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 22 Jul 2014 17:44:56 +0200 Subject: [PATCH 067/740] Code shuffling. Created CastableHelper to store actually usefull function. --- apps/opencs/model/world/nestedadaptors.hpp | 55 +++++++++++++--------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/apps/opencs/model/world/nestedadaptors.hpp b/apps/opencs/model/world/nestedadaptors.hpp index 806dc587d..3807f0219 100644 --- a/apps/opencs/model/world/nestedadaptors.hpp +++ b/apps/opencs/model/world/nestedadaptors.hpp @@ -60,25 +60,47 @@ namespace CSMWorld }; template - class InventoryHelper : public HelperBase + class CastableHelper : public HelperBase + { + + public: + CastableHelper(CSMWorld::UniversalId::Type type) + : HelperBase(type) {} + + protected: + const Record& getRecord(const RefIdData& data, int index) const + { + return dynamic_cast&> ( + data.getRecord (RefIdData::LocalIndex (index, mType))); + } + + Record& getRecord(RefIdData& data, int index) const + { + return dynamic_cast&> ( + data.getRecord (RefIdData::LocalIndex (index, mType))); + } + }; + + template + class InventoryHelper : public CastableHelper { public: InventoryHelper(CSMWorld::UniversalId::Type type) - : HelperBase(type) {} + : CastableHelper(type) {} virtual void setNestedTable(RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) { - getRecord(data, index).get().mInventory.mList = + CastableHelper::getRecord(data, index).get().mInventory.mList = (static_cast >&>(nestedTable)).mNestedTable; } virtual NestedTableWrapperBase* nestedTable(const RefIdData& data, int index) const { - return new NestedTableWrapper >(getRecord(data, index).get().mInventory.mList); + return new NestedTableWrapper >(CastableHelper::getRecord(data, index).get().mInventory.mList); } virtual QVariant getNestedData(const CSMWorld::RefIdData& data, @@ -86,7 +108,7 @@ namespace CSMWorld int subRowIndex, int subColIndex) const { - const ESM::ContItem& content = getRecord(data, index).get().mInventory.mList.at(subRowIndex); + const ESM::ContItem& content = CastableHelper::getRecord(data, index).get().mInventory.mList.at(subRowIndex); switch (subColIndex) { @@ -103,7 +125,7 @@ namespace CSMWorld virtual void removeNestedRow (RefIdData& data, int index, int rowToRemove) const { - std::vector& list = getRecord(data, index).get().mInventory.mList; + std::vector& list = CastableHelper::getRecord(data, index).get().mInventory.mList; list.erase (list.begin () + rowToRemove); } @@ -117,11 +139,11 @@ namespace CSMWorld switch(subColIndex) { case 0: - getRecord(data, index).get().mInventory.mList.at(subRowIndex).mItem.assign(std::string(value.toString().toUtf8().constData())); + CastableHelper::getRecord(data, index).get().mInventory.mList.at(subRowIndex).mItem.assign(std::string(value.toString().toUtf8().constData())); break; case 1: - getRecord(data, index).get().mInventory.mList.at(subRowIndex).mCount = value.toInt(); + CastableHelper::getRecord(data, index).get().mInventory.mList.at(subRowIndex).mCount = value.toInt(); break; default: @@ -131,7 +153,7 @@ namespace CSMWorld virtual void addNestedRow (RefIdData& data, int index, int position) const { - std::vector& list = getRecord(data, index).get().mInventory.mList; + std::vector& list = CastableHelper::getRecord(data, index).get().mInventory.mList; ESM::ContItem newRow = {0, ""}; if (position >= (int)list.size()) @@ -152,22 +174,9 @@ namespace CSMWorld virtual int getNestedRowsCount(const RefIdData& data, int index) const { - return getRecord(data, index).get().mInventory.mList.size(); - } - - private: - - const Record& getRecord(const RefIdData& data, int index) const - { - return dynamic_cast&> ( - data.getRecord (RefIdData::LocalIndex (index, mType))); + return CastableHelper::getRecord(data, index).get().mInventory.mList.size(); } - Record& getRecord(RefIdData& data, int index) const - { - return dynamic_cast&> ( - data.getRecord (RefIdData::LocalIndex (index, mType))); - } }; } From a676f6bc2cad308e924e2a32b3f51e679d99c4f6 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Wed, 23 Jul 2014 20:33:52 +0200 Subject: [PATCH 068/740] comments added --- apps/opencs/model/world/nestedadaptors.hpp | 4 ++++ apps/opencs/model/world/refidadapter.hpp | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/apps/opencs/model/world/nestedadaptors.hpp b/apps/opencs/model/world/nestedadaptors.hpp index 3807f0219..0bb998316 100644 --- a/apps/opencs/model/world/nestedadaptors.hpp +++ b/apps/opencs/model/world/nestedadaptors.hpp @@ -13,6 +13,10 @@ #include +/*! \brief + * Nested adapter redirects responsibility to the helper class. Helper classes are polymorhpic (vide HelperBase and CastableHelper) and most likely templates. + */ + namespace CSMWorld { class RefIdColumn; diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index dd2248e92..22941fd9f 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -6,6 +6,12 @@ #include "nestedadaptors.hpp" +/*! \brief + * Adaptors acts as indirection layer, abstracting details of the record types (in the wrappers) from the higher levels of model. + * Please notice that nested adaptor uses helper classes for actually performing any actions. Different record types require different helpers (needs to be created in the subclass and then fetched via member function). + * Important point: don't forget to make sure that getData on the nestedColumn returns true (otherwise code will not treat the index pointing to the column as having childs! + */ + class QVariant; namespace CSMWorld @@ -30,6 +36,7 @@ namespace CSMWorld virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int idnex) const = 0; + ///< If called on the nest column, should return QVariant(true). virtual void setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const = 0; @@ -95,6 +102,9 @@ namespace CSMWorld protected: void setAssocColumns(const std::vector >& assocColumns); + ///The ownership of the Helper pointers is transfered. + ///The ownership of the column pointers it not transfered (it is not surprising, since columns are created by collection). + ///You MUST call this method to setup the nested adaptor! private: From 864b93e745fd9072b9810c82c866e7fb3e1210b4 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Fri, 25 Jul 2014 11:25:36 +0200 Subject: [PATCH 069/740] added enums for spells --- apps/opencs/model/world/columns.cpp | 1 + apps/opencs/model/world/columns.hpp | 2 ++ apps/opencs/model/world/refidadapterimp.hpp | 1 + apps/opencs/model/world/refidcollection.cpp | 4 ++++ 4 files changed, 8 insertions(+) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 83d0ccc79..1f13645da 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -175,6 +175,7 @@ namespace CSMWorld { ColumnId_Scope, "Scope" }, { ColumnId_ReferenceableId, "Referenceable ID" }, { ColumnId_InventoryItemId, "ID"}, + { ColumnId_SpellId, "ID"}, { ColumnId_ItemCount, "Count"}, { ColumnId_CombatState, "Combat" }, { ColumnId_MagicState, "Magic" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 6812bbae9..908165e9d 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -180,6 +180,8 @@ namespace CSMWorld ColumnId_BodyPartType = 165, ColumnId_MeshType = 166, ColumnId_ActorInventory = 167, + ColumnId_ActorSpells = 168, + ColumnId_SpellId = 169, // 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/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 6fe479150..ee2a58624 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -446,6 +446,7 @@ namespace CSMWorld const RefIdColumn *mFight; const RefIdColumn *mAlarm; const RefIdColumn *mInventory; + const RefIdColumn *mSpells; std::map mServices; ActorColumns (const NameColumns& base) : NameColumns (base) {} diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 493b716eb..89469feac 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -104,6 +104,10 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.back().addNestedColumn(Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String); mColumns.back().addNestedColumn(Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer); + mColumns.push_back(RefIdColumn (Columns::ColumnId_ActorSpells, ColumnBase::Display_NestedSpellList, ColumnBase::Flag_Dialogue, true, true, true)); + actorsColumns.mSpells = &mColumns.back(); + mColumns.back().addNestedColumn(Columns::ColumnId_SpellId, CSMWorld::ColumnBase::Display_String); + static const struct { int mName; From 39545670a887fb29266964e6c4506dd2a1cc2c02 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Fri, 25 Jul 2014 12:09:25 +0200 Subject: [PATCH 070/740] Added spells table (and it works!) --- apps/opencs/model/world/columnbase.hpp | 1 + apps/opencs/model/world/nestedadaptors.hpp | 87 +++++++++++++++++++++ apps/opencs/model/world/refidadapterimp.hpp | 4 + apps/opencs/model/world/refidcollection.cpp | 4 +- 4 files changed, 94 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 096491f1e..5e4dac3ce 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -94,6 +94,7 @@ namespace CSMWorld //Those are top level columns that nest other columns Display_NestedItemList, + Display_NestedSpellList, Display_EnchantmentType, Display_BodyPartType, diff --git a/apps/opencs/model/world/nestedadaptors.hpp b/apps/opencs/model/world/nestedadaptors.hpp index 0bb998316..095bcdf95 100644 --- a/apps/opencs/model/world/nestedadaptors.hpp +++ b/apps/opencs/model/world/nestedadaptors.hpp @@ -2,6 +2,7 @@ #define CSM_WORLD_NESTEDADAPTORS_H #include +#include #include #include "universalid.hpp" @@ -85,6 +86,92 @@ namespace CSMWorld } }; + template + class SpellsHelper : public CastableHelper + { + public: + + SpellsHelper(CSMWorld::UniversalId::Type type) + : CastableHelper(type) {} + + virtual void setNestedTable(RefIdData& data, + int index, + const NestedTableWrapperBase& nestedTable) + { + CastableHelper::getRecord(data, index).get().mSpells.mList = + (static_cast >&>(nestedTable)).mNestedTable; + } + + virtual NestedTableWrapperBase* nestedTable(const RefIdData& data, + int index) const + { + return new NestedTableWrapper >(CastableHelper::getRecord(data, index).get().mSpells.mList); + } + + virtual QVariant getNestedData(const CSMWorld::RefIdData& data, + int index, + int subRowIndex, + int subColIndex) const + { + const std::string& content = CastableHelper::getRecord(data, index).get().mSpells.mList.at(subRowIndex); + + if (subColIndex == 0) + { + return QString::fromUtf8(content.c_str()); + } + + throw std::logic_error("Trying to access non-existing column in the nested table!"); + } + + virtual void removeNestedRow (RefIdData& data, int index, int rowToRemove) const + { + std::vector& list = CastableHelper::getRecord(data, index).get().mSpells.mList; + + list.erase (list.begin () + rowToRemove); + } + + void setNestedData (RefIdData& data, + int index, + const QVariant& value, + int subRowIndex, + int subColIndex) const + { + if (subColIndex == 0) + { + CastableHelper::getRecord(data, index).get().mSpells.mList.at(subRowIndex) = std::string(value.toString().toUtf8()); + } + + throw std::logic_error("Trying to access non-existing column in the nested table!"); + } + + virtual void addNestedRow (RefIdData& data, int index, int position) const + { + std::vector& list = CastableHelper::getRecord(data, index).get().mSpells.mList; + + std::string newString; + if (position >= (int)list.size()) + { + list.push_back(newString); + return; + } + + list.insert(list.begin()+position, newString); + } + + virtual int getNestedColumnsCount(const RefIdData& data) const + { + return 1; + } + + + virtual int getNestedRowsCount(const RefIdData& data, + int index) const + { + return CastableHelper::getRecord(data, index).get().mSpells.mList.size(); + } + + }; + template class InventoryHelper : public CastableHelper { diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index ee2a58624..4c65da85c 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -478,6 +478,7 @@ namespace CSMWorld std::vector > assoCol; assoCol.push_back(std::make_pair(mActors.mInventory, new InventoryHelper(type))); + assoCol.push_back(std::make_pair(mActors.mSpells, new SpellsHelper(type))); setAssocColumns(assoCol); } @@ -507,6 +508,9 @@ namespace CSMWorld if (column==mActors.mInventory) return true; + if (column==mActors.mSpells) + return true; + std::map::const_iterator iter = mActors.mServices.find (column); diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 89469feac..eb25b277e 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -1,4 +1,3 @@ - #include "refidcollection.hpp" #include @@ -99,6 +98,7 @@ CSMWorld::RefIdCollection::RefIdCollection() actorsColumns.mFight = &mColumns.back(); mColumns.push_back (RefIdColumn (Columns::ColumnId_AiAlarm, ColumnBase::Display_Integer)); actorsColumns.mAlarm = &mColumns.back(); + mColumns.push_back(RefIdColumn (Columns::ColumnId_ActorInventory, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue, true, true, true)); actorsColumns.mInventory = &mColumns.back(); mColumns.back().addNestedColumn(Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String); @@ -665,6 +665,6 @@ CSMWorld::NestedTableWrapperBase* CSMWorld::RefIdCollection::nestedTable(int row RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdaptor (localIndex.second)); - + return adaptor.nestedTable(&mColumns.at(column), mData, localIndex.first); } From ade27293be7cd76163c917602c8d092925623367 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Fri, 25 Jul 2014 17:11:18 +0200 Subject: [PATCH 071/740] handling destination for guides --- apps/opencs/model/world/columnbase.hpp | 1 + apps/opencs/model/world/columns.cpp | 9 ++ apps/opencs/model/world/columns.hpp | 8 ++ apps/opencs/model/world/nestedadaptors.hpp | 145 ++++++++++++++++++++ apps/opencs/model/world/refidadapter.cpp | 5 + apps/opencs/model/world/refidadapter.hpp | 3 + apps/opencs/model/world/refidadapterimp.cpp | 9 +- apps/opencs/model/world/refidadapterimp.hpp | 1 + apps/opencs/model/world/refidcollection.cpp | 10 ++ 9 files changed, 189 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 5e4dac3ce..05fecaec0 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -95,6 +95,7 @@ namespace CSMWorld //Those are top level columns that nest other columns Display_NestedItemList, Display_NestedSpellList, + Display_NestedDestinationsList, Display_EnchantmentType, Display_BodyPartType, diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 1f13645da..212772450 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -174,6 +174,7 @@ namespace CSMWorld { ColumnId_PcRank, "PC Rank" }, { ColumnId_Scope, "Scope" }, { ColumnId_ReferenceableId, "Referenceable ID" }, + { ColumnId_NpcDestinations, "Destinations" }, { ColumnId_InventoryItemId, "ID"}, { ColumnId_SpellId, "ID"}, { ColumnId_ItemCount, "Count"}, @@ -184,6 +185,14 @@ namespace CSMWorld { ColumnId_Vampire, "Vampire" }, { ColumnId_BodyPartType, "Bodypart Type" }, { ColumnId_MeshType, "Mesh Type" }, + + { ColumnId_NpcDestinations, "Cell"}, + { ColumnId_PosX, "X"}, + { ColumnId_PosY, "Y"}, + { ColumnId_PosZ, "Z"}, + { ColumnId_RotX, "Rotation X"}, + { ColumnId_RotY, "Rotation Y"}, + { ColumnId_RotZ, "Rotation Z"}, { 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 908165e9d..7efaf2bd0 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -182,6 +182,14 @@ namespace CSMWorld ColumnId_ActorInventory = 167, ColumnId_ActorSpells = 168, ColumnId_SpellId = 169, + ColumnId_NpcDestinations = 170, + ColumnId_PosX = 171, + ColumnId_PosY = 172, + ColumnId_PosZ = 173, + ColumnId_RotX = 174, + ColumnId_RotY = 175, + ColumnId_RotZ = 176, + ColumnId_DestinationCell = 177, // 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/nestedadaptors.hpp b/apps/opencs/model/world/nestedadaptors.hpp index 095bcdf95..319fe1569 100644 --- a/apps/opencs/model/world/nestedadaptors.hpp +++ b/apps/opencs/model/world/nestedadaptors.hpp @@ -11,6 +11,8 @@ #include "refiddata.hpp" #include "refidadapter.hpp" #include +#include +#include #include @@ -172,6 +174,149 @@ namespace CSMWorld }; + template + class DestinationsHelper : public CastableHelper + { + public: + + DestinationsHelper(CSMWorld::UniversalId::Type type) + : CastableHelper(type) {} + + virtual void setNestedTable(RefIdData& data, + int index, + const NestedTableWrapperBase& nestedTable) + { + CastableHelper::getRecord(data, index).get().mTransport = + (static_cast >&>(nestedTable)).mNestedTable; + } + + virtual NestedTableWrapperBase* nestedTable(const RefIdData& data, + int index) const + { + return new NestedTableWrapper >(CastableHelper::getRecord(data, index).get().mTransport); + } + + virtual QVariant getNestedData(const CSMWorld::RefIdData& data, + int index, + int subRowIndex, + int subColIndex) const + { + const ESM::NPC::Dest& content = CastableHelper::getRecord(data, index).get().mTransport.at(subRowIndex); + + switch (subColIndex) + { + case 0: + return QString::fromUtf8(content.mCellName.c_str()); + + case 1: + return content.mPos.pos[0]; + + case 2: + return content.mPos.pos[1]; + + case 3: + return content.mPos.pos[2]; + + case 4: + return content.mPos.rot[0]; + + case 5: + return content.mPos.rot[1]; + + case 6: + return content.mPos.rot[2]; + + default: + throw std::logic_error("Trying to access non-existing column in the nested table!"); + } + } + + virtual void removeNestedRow (RefIdData& data, int index, int rowToRemove) const + { + std::vector& list = CastableHelper::getRecord(data, index).get().mTransport; + + list.erase (list.begin () + rowToRemove); + } + + void setNestedData (RefIdData& data, + int index, + const QVariant& value, + int subRowIndex, + int subColIndex) const + { + switch(subColIndex) + { + case 0: + CastableHelper::getRecord(data, index).get().mTransport.at(subRowIndex).mCellName = std::string(value.toString().toUtf8().constData()); + break; + + case 1: + CastableHelper::getRecord(data, index).get().mTransport.at(subRowIndex).mPos.pos[0] = value.toFloat(); + break; + + case 2: + CastableHelper::getRecord(data, index).get().mTransport.at(subRowIndex).mPos.pos[1] = value.toFloat(); + break; + + case 3: + CastableHelper::getRecord(data, index).get().mTransport.at(subRowIndex).mPos.pos[2] = value.toFloat(); + break; + + case 4: + CastableHelper::getRecord(data, index).get().mTransport.at(subRowIndex).mPos.rot[0] = value.toFloat(); + break; + + case 5: + CastableHelper::getRecord(data, index).get().mTransport.at(subRowIndex).mPos.rot[1] = value.toFloat(); + break; + + case 6: + CastableHelper::getRecord(data, index).get().mTransport.at(subRowIndex).mPos.rot[2] = value.toFloat(); + break; + + default: + throw std::logic_error("Trying to access non-existing column in the nested table!"); + } + } + + virtual void addNestedRow (RefIdData& data, int index, int position) const + { + std::vector& list = CastableHelper::getRecord(data, index).get().mTransport; + + ESM::Position newPos; + for (unsigned i = 0; i < 3; ++i) + { + newPos.pos[i] = 0; + newPos.rot[i] = 0; + } + + ESM::NPC::Dest newRow; + newRow.mPos = newPos; + newRow.mCellName = ""; + + if (position >= (int)list.size()) + { + list.push_back(newRow); + return; + } + + list.insert(list.begin()+position, newRow); + } + + virtual int getNestedColumnsCount(const RefIdData& data) const + { + return 7; + } + + + virtual int getNestedRowsCount(const RefIdData& data, + int index) const + { + return CastableHelper::getRecord(data, index).get().mTransport.size(); + } + + }; + template class InventoryHelper : public CastableHelper { diff --git a/apps/opencs/model/world/refidadapter.cpp b/apps/opencs/model/world/refidadapter.cpp index 631c192fd..58b775f47 100644 --- a/apps/opencs/model/world/refidadapter.cpp +++ b/apps/opencs/model/world/refidadapter.cpp @@ -87,3 +87,8 @@ void CSMWorld::NestedRefIdAdapter::setAssocColumns(const std::vector& assocColumn) +{ + mAssociatedColumns.push_back(assocColumn); +} diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index 22941fd9f..d18e7f02e 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -106,6 +106,9 @@ namespace CSMWorld ///The ownership of the column pointers it not transfered (it is not surprising, since columns are created by collection). ///You MUST call this method to setup the nested adaptor! + void addAssocColumn(const std::pair & assocColumn); + ///Like setAssocColumn, when it is impossible to set all columns at once + private: HelperBase* getHelper(const RefIdColumn *column) const; diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 18287d596..ac546db51 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -452,7 +452,9 @@ CSMWorld::NpcColumns::NpcColumns (const ActorColumns& actorColumns) : ActorColum CSMWorld::NpcRefIdAdapter::NpcRefIdAdapter (const NpcColumns& columns) : ActorRefIdAdapter (UniversalId::Type_Npc, columns), mColumns (columns) -{} +{ + NestedRefIdAdapter::addAssocColumn(std::make_pair(columns.mDestinations, new DestinationsHelper(UniversalId::Type_Npc))); +} QVariant CSMWorld::NpcRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, int index) const @@ -474,13 +476,16 @@ QVariant CSMWorld::NpcRefIdAdapter::getData (const RefIdColumn *column, const Re if (column==mColumns.mHead) return QString::fromUtf8 (record.get().mHead.c_str()); + + if (column==mColumns.mDestinations) + return true; std::map::const_iterator iter = mColumns.mFlags.find (column); if (iter!=mColumns.mFlags.end()) return (record.get().mFlags & iter->second)!=0; - + return ActorRefIdAdapter::getData (column, data, index); } diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 4c65da85c..6fd42b00e 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -742,6 +742,7 @@ namespace CSMWorld const RefIdColumn *mFaction; const RefIdColumn *mHair; const RefIdColumn *mHead; + const RefIdColumn *mDestinations; NpcColumns (const ActorColumns& actorColumns); }; diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index eb25b277e..d776931f8 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -315,6 +315,16 @@ CSMWorld::RefIdCollection::RefIdCollection() npcColumns.mFlags.insert (std::make_pair (metalBlood, ESM::NPC::Metal)); + mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcDestinations, ColumnBase::Display_NestedDestinationsList, ColumnBase::Flag_Dialogue, true, true, true)); + npcColumns.mDestinations = &mColumns.back(); + mColumns.back().addNestedColumn(Columns::ColumnId_DestinationCell, CSMWorld::ColumnBase::Display_String); + mColumns.back().addNestedColumn(Columns::ColumnId_PosX, CSMWorld::ColumnBase::Display_Float); + mColumns.back().addNestedColumn(Columns::ColumnId_PosY, CSMWorld::ColumnBase::Display_Float); + mColumns.back().addNestedColumn(Columns::ColumnId_PosZ, CSMWorld::ColumnBase::Display_Float); + mColumns.back().addNestedColumn(Columns::ColumnId_RotX, CSMWorld::ColumnBase::Display_Float); + mColumns.back().addNestedColumn(Columns::ColumnId_RotY, CSMWorld::ColumnBase::Display_Float); + mColumns.back().addNestedColumn(Columns::ColumnId_RotZ, CSMWorld::ColumnBase::Display_Float); + WeaponColumns weaponColumns (enchantableColumns); mColumns.push_back (RefIdColumn (Columns::ColumnId_WeaponType, ColumnBase::Display_WeaponType)); From 6a9c7c9f8699e852c0fc712cab5dec4f4ce49fb5 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Mon, 28 Jul 2014 17:33:21 +0200 Subject: [PATCH 072/740] fix for bug 1672 --- apps/opencs/model/doc/document.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 23a47b313..644d32e84 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -1,6 +1,7 @@ #include "document.hpp" #include +#include #include @@ -2217,16 +2218,18 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, if (!boost::filesystem::exists (mProjectPath)) { - boost::filesystem::path locCustomFiltersPath (configuration.getUserDataPath()); - locCustomFiltersPath /= "defaultfilters"; + boost::filesystem::path customFiltersPath (configuration.getUserDataPath()); + customFiltersPath /= "defaultfilters"; + + std::string destinationPath = mProjectPath.string() + "/defaultfilters"; + std::ofstream dst(destinationPath.c_str(), std::ios::binary); - if (boost::filesystem::exists (locCustomFiltersPath)) + if (boost::filesystem::exists (customFiltersPath)) { - boost::filesystem::copy_file (locCustomFiltersPath, mProjectPath); - } - else + dst< Date: Wed, 30 Jul 2014 17:07:11 +0200 Subject: [PATCH 073/740] saving progress --- apps/opencs/model/doc/document.cpp | 4 +- apps/opencs/model/world/columns.cpp | 7 ++ apps/opencs/model/world/columns.hpp | 1 + apps/opencs/model/world/commands.cpp | 18 +-- apps/opencs/model/world/nestedadaptors.hpp | 128 ++++++++++++++++++++- apps/opencs/view/world/enumdelegate.cpp | 1 - 6 files changed, 148 insertions(+), 11 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 644d32e84..eb03be085 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2,6 +2,7 @@ #include #include +#include #include @@ -2221,8 +2222,7 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, boost::filesystem::path customFiltersPath (configuration.getUserDataPath()); customFiltersPath /= "defaultfilters"; - std::string destinationPath = mProjectPath.string() + "/defaultfilters"; - std::ofstream dst(destinationPath.c_str(), std::ios::binary); + std::ofstream dst(mProjectPath.c_str(), std::ios::binary); if (boost::filesystem::exists (customFiltersPath)) { diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 212772450..0c44c2dcb 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -24,6 +24,7 @@ namespace CSMWorld { ColumnId_ValueType, "Value Type" }, { ColumnId_Description, "Description" }, { ColumnId_Specialisation, "Specialisation" }, + { ColumnId_Skill, "Skill" }, { ColumnId_Attribute, "Attribute" }, { ColumnId_Name, "Name" }, { ColumnId_Playable, "Playable" }, @@ -248,6 +249,11 @@ int CSMWorld::Columns::getId (const std::string& name) namespace { + static const char *sSkills[] = + { + "Long Blade" + }; + static const char *sSpecialisations[] = { "Combat", "Magic", "Stealth", 0 @@ -339,6 +345,7 @@ namespace switch (column) { case CSMWorld::Columns::ColumnId_Specialisation: return sSpecialisations; + case CSMWorld::Columns::ColumnId_Skill: return sSkills; case CSMWorld::Columns::ColumnId_Attribute: return sAttributes; case CSMWorld::Columns::ColumnId_SpellType: return sSpellTypes; case CSMWorld::Columns::ColumnId_ApparatusType: return sApparatusTypes; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 7efaf2bd0..b06018dd4 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -190,6 +190,7 @@ namespace CSMWorld ColumnId_RotY = 175, ColumnId_RotZ = 176, ColumnId_DestinationCell = 177, + ColumnId_Skill = 178, // 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/commands.cpp b/apps/opencs/model/world/commands.cpp index 0d9f6c773..30c4bb892 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -173,13 +173,17 @@ void CSMWorld::CloneCommand::undo() mModel.removeRow (mModel.getModelIndex (mIdDestination, 0).row()); } -CSMWorld::DeleteNestedCommand::DeleteNestedCommand (IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent) - : mId(id), - mModel(model), - mParentColumn(parentColumn), - QUndoCommand(parent), - mNestedRow(nestedRow), - NestedTableStoring(model, id, parentColumn) +CSMWorld::DeleteNestedCommand::DeleteNestedCommand (IdTable& model, + const std::string& id, + int nestedRow, + int parentColumn, + QUndoCommand* parent) : + mId(id), + mModel(model), + mParentColumn(parentColumn), + QUndoCommand(parent), + mNestedRow(nestedRow), + NestedTableStoring(model, id, parentColumn) { setText (("Delete nested row in " + mId).c_str()); } diff --git a/apps/opencs/model/world/nestedadaptors.hpp b/apps/opencs/model/world/nestedadaptors.hpp index 319fe1569..6e3d447b2 100644 --- a/apps/opencs/model/world/nestedadaptors.hpp +++ b/apps/opencs/model/world/nestedadaptors.hpp @@ -13,6 +13,9 @@ #include #include #include +#include +#include +#include #include @@ -174,6 +177,129 @@ namespace CSMWorld }; + /* + template + class MagicEffectsHelper : public CastableHelper + { + public: + + MagicEffectsHelper(CSMWorld::UniversalId::Type type) + : CastableHelper(type) {} + + virtual void setNestedTable(RefIdData& data, + int index, + const NestedTableWrapperBase& nestedTable) + { + CastableHelper::getRecord(data, index).get().mEffects = + (static_cast&>(nestedTable)).mNestedTable; + } + + virtual NestedTableWrapperBase* nestedTable(const RefIdData& data, + int index) const + { + return new NestedTableWrapper(CastableHelper::getRecord(data, index).get().mEffects); + } + + virtual QVariant getNestedData(const CSMWorld::RefIdData& data, + int index, + int subRowIndex, + int subColIndex) const + { + const ESM::EffectList& content = CastableHelper::getRecord(data, index).get().mEffects; + + switch (subColIndex) + { + case 0: + return content.at(subRowIndex).mEffectID; + + case 1: + return content.at(subRowIndex).mRange; + + case 2: + return content.at(subRowIndex).mDuration; + + case 3: + return content.at(subRowIndex).mArea; + + case 4: + return content.at(subRowIndex).mMagMin; + + case 5: + return content.at(subRowIndex).mMagMax; + + case 6: + return (int)content.at(rubRowIndex).mSkill; + + case 7: + return (int)content.at(subRowIndex).mAttribute; + + default: + throw std::logic_error("Trying to access non-existing column in the nested table!"); + } + } + + virtual void removeNestedRow (RefIdData& data, int index, int rowToRemove) const + { + ESM::EffectList& list = CastableHelper::getRecord(data, index).get().mEffects; + + list.erase (list.begin () + rowToRemove); + } + + void setNestedData (RefIdData& data, + int index, + const QVariant& value, + int subRowIndex, + int subColIndex) const + { + switch(subColIndex) + { + case 0: + CastableHelper::getRecord(data, index).get().mEffects.at(subRowIndex).mEffectID = value.toInt(); + break; + + default: + throw std::logic_error("Trying to access non-existing column in the nested table!"); + } + } + + virtual void addNestedRow (RefIdData& data, int index, int position) const + { + std::vector& list = CastableHelper::getRecord(data, index).get().mTransport; + + ESM::Position newPos; + for (unsigned i = 0; i < 3; ++i) + { + newPos.pos[i] = 0; + newPos.rot[i] = 0; + } + + ESM::NPC::Dest newRow; + newRow.mPos = newPos; + newRow.mCellName = ""; + + if (position >= (int)list.size()) + { + list.push_back(newRow); + return; + } + + list.insert(list.begin()+position, newRow); + } + + virtual int getNestedColumnsCount(const RefIdData& data) const + { + return 7; + } + + + virtual int getNestedRowsCount(const RefIdData& data, + int index) const + { + return CastableHelper::getRecord(data, index).get().mTransport.size(); + } + + }; + */ template class DestinationsHelper : public CastableHelper { @@ -316,7 +442,7 @@ namespace CSMWorld } }; - + template class InventoryHelper : public CastableHelper { diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp index 377f479bf..16f38938d 100644 --- a/apps/opencs/view/world/enumdelegate.cpp +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -46,7 +46,6 @@ QWidget *CSVWorld::EnumDelegate::createEditor(QWidget *parent, const QModelIndex& index) const { return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_None); - //overloading virtual functions is HARD } QWidget *CSVWorld::EnumDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem& option, From c6194e7ea3352918e41d2bd7118294909651d7e8 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Wed, 30 Jul 2014 22:08:55 +0200 Subject: [PATCH 074/740] inserted additional class for nested collections --- apps/opencs/model/world/collection.hpp | 43 --------------------- apps/opencs/model/world/collectionbase.cpp | 27 ------------- apps/opencs/model/world/collectionbase.hpp | 40 +++++++++++-------- apps/opencs/model/world/idtable.cpp | 30 +++++++------- apps/opencs/model/world/refidcollection.hpp | 2 +- 5 files changed, 40 insertions(+), 102 deletions(-) diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 591074372..252e84c38 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -17,8 +17,6 @@ #include "collectionbase.hpp" -#include "nestedtablewrapper.hpp" - namespace CSMWorld { /// \brief Access to ID field in records @@ -77,10 +75,6 @@ namespace CSMWorld virtual int getSize() const; - virtual int getNestedColumnsCount(int column) const; - - virtual int getNestedRowsCount(int row, int column) const; - virtual std::string getId (int index) const; virtual int getIndex (const std::string& id) const; @@ -89,14 +83,8 @@ namespace CSMWorld virtual QVariant getData (int index, int column) const; - virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const; - virtual void setData (int index, int column, const QVariant& data); - virtual NestedTableWrapperBase* nestedTable(int row, int column) const; - - virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable); - virtual const ColumnBase& getColumn (int column) const; virtual void merge(); @@ -261,18 +249,6 @@ namespace CSMWorld return mRecords.size(); } - template - int Collection::getNestedRowsCount(int row, int column) const - { - return 0; - } - - template - int Collection::getNestedColumnsCount(int column) const - { - return 0; - } - template std::string Collection::getId (int index) const { @@ -302,25 +278,6 @@ namespace CSMWorld return mColumns.at (column)->get (mRecords.at (index)); } - template - QVariant Collection::getNestedData(int row, int column, int subRow, int subColumn) const - { - return QVariant(); - } - - template - NestedTableWrapperBase* Collection::nestedTable(int row, int column) const - { - assert(false); - return new NestedTableWrapperBase(); - } - - template - void Collection::setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable) - { - throw std::logic_error("setNestedTable was not overriden"); - } - template void Collection::setData (int index, int column, const QVariant& data) { diff --git a/apps/opencs/model/world/collectionbase.cpp b/apps/opencs/model/world/collectionbase.cpp index a1f4f4a70..5b0c359c9 100644 --- a/apps/opencs/model/world/collectionbase.cpp +++ b/apps/opencs/model/world/collectionbase.cpp @@ -30,30 +30,3 @@ int CSMWorld::CollectionBase::findColumnIndex (Columns::ColumnId id) const return index; } - -void CSMWorld::CollectionBase::setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn) -{ - assert(false); //TODO remove and make pure abstract -} - -int CSMWorld::CollectionBase::getNestedColumnsCount(int row, int column) const -{ - assert(false); //TODO remove and make pure abstract - return 0; -} - -int CSMWorld::CollectionBase::getNestedRowsCount(int row, int column) const -{ - assert(false); //TODO, make pure abstract - return 0; -} - -void CSMWorld::CollectionBase::removeNestedRows(int row, int column, int subRow) -{ - assert(false); //todo, make pure abstract -} - -void CSMWorld::CollectionBase::addNestedRow(int row, int col, int position) -{ - assert(false); -} diff --git a/apps/opencs/model/world/collectionbase.hpp b/apps/opencs/model/world/collectionbase.hpp index a6ee34e56..29ac33bc8 100644 --- a/apps/opencs/model/world/collectionbase.hpp +++ b/apps/opencs/model/world/collectionbase.hpp @@ -13,7 +13,7 @@ namespace CSMWorld { struct ColumnBase; struct RecordBase; - class NestedTableWrapperBase; + class NestedTableWrapperBase; /// \brief Base class for record collections /// @@ -35,10 +35,6 @@ namespace CSMWorld virtual int getSize() const = 0; - virtual int getNestedRowsCount(int row, int column) const; - - virtual int getNestedColumnsCount(int row, int column) const; - virtual std::string getId (int index) const = 0; virtual int getIndex (const std::string& id) const = 0; @@ -49,16 +45,8 @@ namespace CSMWorld virtual QVariant getData (int index, int column) const = 0; - virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const = 0; - - virtual NestedTableWrapperBase* nestedTable(int row, int column) const = 0; - - virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable) = 0; - virtual void setData (int index, int column, const QVariant& data) = 0; - virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn); - // Not in use. Temporarily removed so that the implementation of RefIdCollection can continue without // these functions for now. // virtual void merge() = 0; @@ -69,10 +57,6 @@ namespace CSMWorld virtual void removeRows (int index, int count) = 0; - virtual void removeNestedRows(int row, int column, int subRow); - - virtual void addNestedRow(int row, int col, int position); - virtual void appendBlankRecord (const std::string& id, UniversalId::Type type = UniversalId::Type_None) = 0; ///< \param type Will be ignored, unless the collection supports multiple record types @@ -121,6 +105,28 @@ namespace CSMWorld ///< Return index of column with the given \a id. If no such column exists, an exception is /// thrown. }; + + class NestedCollection : public CollectionBase + { + public: + virtual void addNestedRow(int row, int col, int position) = 0; + + virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const = 0; + + virtual NestedTableWrapperBase* nestedTable(int row, int column) const = 0; + + virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable) = 0; + + virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn) = 0; + + virtual int getNestedRowsCount(int row, int column) const = 0; + + virtual int getNestedColumnsCount(int row, int column) const = 0; + + virtual void removeNestedRows(int row, int column, int subRow) = 0; + + + }; } #endif diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index be31d0503..4e4ccb1c1 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -18,7 +18,7 @@ int CSMWorld::IdTable::rowCount (const QModelIndex & parent) const { if (hasChildren(parent)) { - return mIdCollection->getNestedRowsCount(parent.row(), parent.column()); + return dynamic_cast(mIdCollection)->getNestedRowsCount(parent.row(), parent.column()); } return mIdCollection->getSize(); @@ -26,10 +26,9 @@ int CSMWorld::IdTable::rowCount (const QModelIndex & parent) const int CSMWorld::IdTable::columnCount (const QModelIndex & parent) const { - if (parent.isValid() && - parent.data().isValid()) + if (hasChildren(parent)) { - return mIdCollection->getNestedColumnsCount(parent.row(), parent.column()); + return dynamic_cast(mIdCollection)->getNestedColumnsCount(parent.row(), parent.column()); } return mIdCollection->getColumns(); @@ -46,10 +45,10 @@ QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const if (index.internalId() != 0) { std::pair parentAdress(unfoldIndexAdress(index.internalId())); - return mIdCollection->getNestedData(parentAdress.first, - parentAdress.second, - index.row(), - index.column()); + return dynamic_cast(mIdCollection)->getNestedData(parentAdress.first, + parentAdress.second, + index.row(), + index.column()); } else { return mIdCollection->getData (index.row(), index.column()); } @@ -101,7 +100,7 @@ bool CSMWorld::IdTable::setData (const QModelIndex &index, const QVariant &value { const std::pair& parentAdress(unfoldIndexAdress(index.internalId())); - mIdCollection->setNestedData(parentAdress.first, parentAdress.second, value, index.row(), index.column()); + dynamic_cast(mIdCollection)->setNestedData(parentAdress.first, parentAdress.second, value, index.row(), index.column()); emit dataChanged (CSMWorld::IdTable::index (parentAdress.first, 0), CSMWorld::IdTable::index (parentAdress.second, mIdCollection->getColumns()-1)); @@ -144,7 +143,7 @@ bool CSMWorld::IdTable::removeRows (int row, int count, const QModelIndex& paren { for (int i = 0; i < count; ++i) { - mIdCollection->removeNestedRows(parent.row(), parent.column(), row+i); + dynamic_cast(mIdCollection)->removeNestedRows(parent.row(), parent.column(), row+i); } } else { @@ -164,12 +163,15 @@ bool CSMWorld::IdTable::removeRows (int row, int count, const QModelIndex& paren void CSMWorld::IdTable::addNestedRow(const QModelIndex& parent, int position) { - assert(parent.isValid()); + if (!hasChildren(parent)) + { + throw std::logic_error("Tried to set nested table, but index has no children"); + } int row = parent.row(); beginInsertRows(parent, position, position); - mIdCollection->addNestedRow(row, parent.column(), position); + dynamic_cast(mIdCollection)->addNestedRow(row, parent.column(), position); endInsertRows(); @@ -373,7 +375,7 @@ void CSMWorld::IdTable::setNestedTable(const QModelIndex& index, const CSMWorld: removeRowsMode = true; } - mIdCollection->setNestedTable(index.row(), index.column(), nestedTable); + dynamic_cast(mIdCollection)->setNestedTable(index.row(), index.column(), nestedTable); emit dataChanged (CSMWorld::IdTable::index (index.row(), 0), CSMWorld::IdTable::index (index.row(), mIdCollection->getColumns()-1)); @@ -391,5 +393,5 @@ CSMWorld::NestedTableWrapperBase* CSMWorld::IdTable::nestedTable(const QModelInd throw std::logic_error("Tried to retrive nested table, but index has no children"); } - return mIdCollection->nestedTable(index.row(), index.column()); + return dynamic_cast(mIdCollection)->nestedTable(index.row(), index.column()); } diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index cc7609a58..62616d369 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -35,7 +35,7 @@ namespace CSMWorld virtual bool isUserEditable() const; }; - class RefIdCollection : public CollectionBase + class RefIdCollection : public NestedCollection { private: From 40edf15ab095f11c5485ff9a36912ac9e6cb7ce2 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Thu, 31 Jul 2014 12:18:24 +0200 Subject: [PATCH 075/740] cleaning up the code --- apps/opencs/model/world/collection.hpp | 1 + apps/opencs/model/world/columnimp.hpp | 1 + apps/opencs/model/world/idtable.cpp | 13 ++++++++----- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 252e84c38..5c32e7716 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -2,6 +2,7 @@ #define CSM_WOLRD_COLLECTION_H #include +#include #include #include #include diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 3fad05f65..e416c332b 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -4,6 +4,7 @@ #include #include +#include #include diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 4e4ccb1c1..410e0d3f0 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "nestedtablewrapper.hpp" #include "collectionbase.hpp" @@ -30,7 +31,7 @@ int CSMWorld::IdTable::columnCount (const QModelIndex & parent) const { return dynamic_cast(mIdCollection)->getNestedColumnsCount(parent.row(), parent.column()); } - + return mIdCollection->getColumns(); } @@ -46,9 +47,9 @@ QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const { std::pair parentAdress(unfoldIndexAdress(index.internalId())); return dynamic_cast(mIdCollection)->getNestedData(parentAdress.first, - parentAdress.second, - index.row(), - index.column()); + parentAdress.second, + index.row(), + index.column()); } else { return mIdCollection->getData (index.row(), index.column()); } @@ -68,8 +69,10 @@ QVariant CSMWorld::IdTable::headerData (int section, return mIdCollection->getColumn (section).mFlags; if (role==ColumnBase::Role_Display) + { return mIdCollection->getColumn (section).mDisplayType; - + } + return QVariant(); } From e413bebe99b0dc2ab1e5f07c8d20b594f6a4c5f4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 16 Oct 2014 15:07:51 +0200 Subject: [PATCH 076/740] Toggle addon files when activated or clicked on checkbox rather than clicked (Fixes #1980) --- apps/opencs/view/doc/filedialog.cpp | 10 +++++++--- apps/opencs/view/doc/filedialog.hpp | 1 + components/contentselector/model/contentmodel.cpp | 4 ++-- components/contentselector/view/contentselector.cpp | 11 +++-------- components/contentselector/view/contentselector.hpp | 6 +++--- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/apps/opencs/view/doc/filedialog.cpp b/apps/opencs/view/doc/filedialog.cpp index 300656f33..c0e5502ec 100644 --- a/apps/opencs/view/doc/filedialog.cpp +++ b/apps/opencs/view/doc/filedialog.cpp @@ -125,13 +125,17 @@ void CSVDoc::FileDialog::buildOpenFileView() if(!mDialogBuilt) { - connect (mSelector, SIGNAL (signalAddonFileSelected (int)), this, SLOT (slotUpdateAcceptButton (int))); - connect (mSelector, SIGNAL (signalAddonFileUnselected (int)), this, SLOT (slotUpdateAcceptButton (int))); + connect (mSelector, SIGNAL (signalAddonDataChanged (const QModelIndex&, const QModelIndex&)), this, SLOT (slotAddonDataChanged(const QModelIndex&, const QModelIndex&))); } connect (ui.projectButtonBox, SIGNAL (accepted()), this, SLOT (slotOpenFile())); } -void CSVDoc::FileDialog::slotUpdateAcceptButton (int) +void CSVDoc::FileDialog::slotAddonDataChanged(const QModelIndex &topleft, const QModelIndex &bottomright) +{ + slotUpdateAcceptButton(0); +} + +void CSVDoc::FileDialog::slotUpdateAcceptButton(int) { QString name = ""; diff --git a/apps/opencs/view/doc/filedialog.hpp b/apps/opencs/view/doc/filedialog.hpp index 111cc0d80..3c23a5cb5 100644 --- a/apps/opencs/view/doc/filedialog.hpp +++ b/apps/opencs/view/doc/filedialog.hpp @@ -70,6 +70,7 @@ namespace CSVDoc void slotUpdateAcceptButton (int); void slotUpdateAcceptButton (const QString &, bool); void slotRejected(); + void slotAddonDataChanged(const QModelIndex& topleft, const QModelIndex& bottomright); }; } #endif // FILEDIALOG_HPP diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 0d4f2365a..fde6223f1 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -106,7 +106,7 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index //game files can always be checked if (file->isGameFile()) - return Qt::ItemIsEnabled | Qt::ItemIsSelectable; + return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable; Qt::ItemFlags returnFlags; bool allDependenciesFound = true; @@ -145,7 +145,7 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index if (gamefileChecked) { if (allDependenciesFound) - returnFlags = returnFlags | Qt::ItemIsEnabled | Qt::ItemIsSelectable | mDragDropFlags; + returnFlags = returnFlags | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | mDragDropFlags; else returnFlags = Qt::ItemIsSelectable; } diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index e9599de49..4508d7bd7 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -58,7 +58,8 @@ void ContentSelectorView::ContentSelector::buildAddonView() ui.addonView->setModel(mAddonProxyModel); - connect(ui.addonView, SIGNAL(clicked(const QModelIndex &)), this, SLOT(slotAddonTableItemClicked(const QModelIndex &))); + connect(ui.addonView, SIGNAL(activated(const QModelIndex&)), this, SLOT(slotAddonTableItemActivated(const QModelIndex&))); + connect(mContentModel, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)), this, SIGNAL(signalAddonDataChanged(QModelIndex,QModelIndex))); } void ContentSelectorView::ContentSelector::setProfileContent(const QStringList &fileList) @@ -181,7 +182,7 @@ void ContentSelectorView::ContentSelector::slotCurrentGameFileIndexChanged(int i emit signalCurrentGamefileIndexChanged (index); } -void ContentSelectorView::ContentSelector::slotAddonTableItemClicked(const QModelIndex &index) +void ContentSelectorView::ContentSelector::slotAddonTableItemActivated(const QModelIndex &index) { QModelIndex sourceIndex = mAddonProxyModel->mapToSource (index); @@ -194,10 +195,4 @@ void ContentSelectorView::ContentSelector::slotAddonTableItemClicked(const QMode checkState = Qt::Checked; mContentModel->setData(sourceIndex, checkState, Qt::CheckStateRole); - - if (checkState == Qt::Checked) - emit signalAddonFileSelected (index.row()); - else - emit signalAddonFileUnselected (index.row()); - } diff --git a/components/contentselector/view/contentselector.hpp b/components/contentselector/view/contentselector.hpp index a25eb20ae..5fba9cd2e 100644 --- a/components/contentselector/view/contentselector.hpp +++ b/components/contentselector/view/contentselector.hpp @@ -55,13 +55,13 @@ namespace ContentSelectorView signals: void signalCurrentGamefileIndexChanged (int); - void signalAddonFileSelected (int); - void signalAddonFileUnselected (int); + + void signalAddonDataChanged (const QModelIndex& topleft, const QModelIndex& bottomright); private slots: void slotCurrentGameFileIndexChanged(int index); - void slotAddonTableItemClicked(const QModelIndex &index); + void slotAddonTableItemActivated(const QModelIndex& index); }; } From 9c5f15679309fabbccce29cf6bdf96f1c42847e2 Mon Sep 17 00:00:00 2001 From: Internecine Date: Wed, 5 Nov 2014 00:46:33 +1300 Subject: [PATCH 077/740] Fixes tooltip displaying 0 durations --- 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 d7bc2c96e..8eeb02a45 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -446,7 +446,7 @@ namespace MWGui // constant effects have no duration and no target if (!mEffectParams.mIsConstant) { - if (mEffectParams.mDuration >= 0 && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)) + if (mEffectParams.mDuration > 0 && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)) { spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sfor", "") + " " + boost::lexical_cast(mEffectParams.mDuration) + ((mEffectParams.mDuration == 1) ? sec : secs); } From 6741fbe7a9ff84f226db2fdbc37c5bdca00af3a1 Mon Sep 17 00:00:00 2001 From: Internecine Date: Wed, 5 Nov 2014 15:22:44 +1300 Subject: [PATCH 078/740] Fixes bug #2031 --- apps/openmw/mwmechanics/spellcasting.cpp | 30 +++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index d33bb6ad1..e124c8b79 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -434,7 +434,8 @@ namespace MWMechanics float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random; magnitude *= magnitudeMult; - bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration); + bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration) && effectIt->mDuration > 0; + std::cout << (hasDuration == true ? "true" : "false") << std::endl; if (target.getClass().isActor() && hasDuration) { ActiveSpells::ActiveEffect effect; @@ -578,6 +579,33 @@ namespace MWMechanics value.restore(magnitude); target.getClass().getCreatureStats(target).setAttribute(attribute, value); } + else if (effectId == ESM::MagicEffect::DamageHealth || effectId == ESM::MagicEffect::RestoreHealth) + { + MWMechanics::DynamicStat health = target.getClass().getCreatureStats(target).getHealth(); + if (effectId == ESM::MagicEffect::DamageHealth) + health.setCurrent(health.getCurrent() - magnitude); + else + health.setCurrent(health.getCurrent() + magnitude); + target.getClass().getCreatureStats(target).setHealth(health); + } + else if (effectId == ESM::MagicEffect::DamageFatigue || effectId == ESM::MagicEffect::RestoreFatigue) + { + MWMechanics::DynamicStat fatigue = target.getClass().getCreatureStats(target).getFatigue(); + if (effectId == ESM::MagicEffect::DamageFatigue) + fatigue.setCurrent(fatigue.getCurrent() - magnitude); + else + fatigue.setCurrent(fatigue.getCurrent() + magnitude); + target.getClass().getCreatureStats(target).setHealth(fatigue); + } + else if (effectId == ESM::MagicEffect::DamageMagicka || effectId == ESM::MagicEffect::RestoreMagicka) + { + MWMechanics::DynamicStat magicka = target.getClass().getCreatureStats(target).getMagicka(); + if (effectId == ESM::MagicEffect::DamageMagicka) + magicka.setCurrent(magicka.getCurrent() - magnitude); + else + magicka.setCurrent(magicka.getCurrent() + magnitude); + target.getClass().getCreatureStats(target).setHealth(magicka); + } else if (effectId == ESM::MagicEffect::DamageSkill || effectId == ESM::MagicEffect::RestoreSkill) { if (target.getTypeName() != typeid(ESM::NPC).name()) From edc51ab768d7413ac894f23e7044e7c55e74ce74 Mon Sep 17 00:00:00 2001 From: Internecine Date: Wed, 5 Nov 2014 15:26:13 +1300 Subject: [PATCH 079/740] Removed debug output --- apps/openmw/mwmechanics/spellcasting.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index e124c8b79..fd4c9406c 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -435,7 +435,6 @@ namespace MWMechanics magnitude *= magnitudeMult; bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration) && effectIt->mDuration > 0; - std::cout << (hasDuration == true ? "true" : "false") << std::endl; if (target.getClass().isActor() && hasDuration) { ActiveSpells::ActiveEffect effect; From c37881ead1ce513bbd4a90d5f56ab5c45957feac Mon Sep 17 00:00:00 2001 From: Digmaster Date: Mon, 8 Dec 2014 21:57:32 -0600 Subject: [PATCH 080/740] Joystick Support --- apps/openmw/engine.cpp | 2 +- apps/openmw/mwbase/inputmanager.hpp | 16 +- apps/openmw/mwgui/settingswindow.cpp | 46 +- apps/openmw/mwgui/settingswindow.hpp | 5 + apps/openmw/mwinput/inputmanagerimp.cpp | 471 +++++++++++-- apps/openmw/mwinput/inputmanagerimp.hpp | 44 +- apps/openmw/mwscript/interpretercontext.cpp | 4 +- extern/oics/ICSControl.cpp | 18 +- extern/oics/ICSInputControlSystem.cpp | 286 +++----- extern/oics/ICSInputControlSystem.h | 74 +- .../oics/ICSInputControlSystem_joystick.cpp | 630 ++++-------------- extern/sdl4ogre/events.h | 18 +- extern/sdl4ogre/sdlinputwrapper.cpp | 36 +- extern/sdl4ogre/sdlinputwrapper.hpp | 4 +- files/CMakeLists.txt | 2 + files/gamecontrollerdb.txt | 75 +++ 16 files changed, 894 insertions(+), 837 deletions(-) create mode 100644 files/gamecontrollerdb.txt diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index d7b23c096..0e636e054 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -190,7 +190,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) std::srand ( std::time(NULL) ); MWClass::registerClasses(); - Uint32 flags = SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE; + Uint32 flags = SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE|SDL_INIT_GAMECONTROLLER|SDL_INIT_JOYSTICK; if(SDL_WasInit(flags) == 0) { //kindly ask SDL not to trash our OGL context diff --git a/apps/openmw/mwbase/inputmanager.hpp b/apps/openmw/mwbase/inputmanager.hpp index d44da4974..3ffa7148a 100644 --- a/apps/openmw/mwbase/inputmanager.hpp +++ b/apps/openmw/mwbase/inputmanager.hpp @@ -37,11 +37,19 @@ namespace MWBase virtual bool getControlSwitch (const std::string& sw) = 0; virtual std::string getActionDescription (int action) = 0; - virtual std::string getActionBindingName (int action) = 0; - virtual std::vector getActionSorting () = 0; + virtual std::string getActionKeyBindingName (int action) = 0; + virtual std::string getActionControllerBindingName (int action) = 0; + virtual std::string sdlControllerAxisToString(int axis) = 0; + virtual std::string sdlControllerButtonToString(int button) = 0; + ///Actions available for binding to keyboard buttons + virtual std::vector getActionKeySorting() = 0; + ///Actions available for binding to controller buttons + virtual std::vector getActionControllerSorting() = 0; virtual int getNumActions() = 0; - virtual void enableDetectingBindingMode (int action) = 0; - virtual void resetToDefaultBindings() = 0; + ///If keyboard is true, only pay attention to keyboard events. If false, only pay attention to cntroller events (excluding esc) + virtual void enableDetectingBindingMode (int action, bool keyboard) = 0; + virtual void resetToDefaultKeyBindings() = 0; + virtual void resetToDefaultControllerBindings() = 0; }; } diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 8ef0a331a..619a0c87d 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -156,7 +156,8 @@ namespace MWGui } SettingsWindow::SettingsWindow() : - WindowBase("openmw_settings_window.layout") + WindowBase("openmw_settings_window.layout"), + mKeyboardMode(true) { configureWidgets(mMainWidget); @@ -180,6 +181,8 @@ namespace MWGui getWidget(mResetControlsButton, "ResetControlsButton"); getWidget(mRefractionButton, "RefractionButton"); getWidget(mDifficultySlider, "DifficultySlider"); + getWidget(mKeyboardSwitch, "KeyboardButton"); + getWidget(mControllerSwitch, "ControllerButton"); mMainWidget->castType()->eventWindowChangeCoord += MyGUI::newDelegate(this, &SettingsWindow::onWindowResize); @@ -191,6 +194,9 @@ namespace MWGui mShadowsTextureSize->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onShadowTextureSizeChanged); + mKeyboardSwitch->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onKeyboardSwitchClicked); + mControllerSwitch->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onControllerSwitchClicked); + center(); mResetControlsButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onResetDefaultBindings); @@ -436,14 +442,33 @@ namespace MWGui MWBase::Environment::get().getInputManager()->processChangedSettings(changed); } + void SettingsWindow::onKeyboardSwitchClicked(MyGUI::Widget* _sender) + { + if(mKeyboardMode) + return; + mKeyboardMode = true; + updateControlsBox(); + } + + void SettingsWindow::onControllerSwitchClicked(MyGUI::Widget* _sender) + { + if(!mKeyboardMode) + return; + mKeyboardMode = false; + updateControlsBox(); + } + void SettingsWindow::updateControlsBox() { while (mControlsBox->getChildCount()) MyGUI::Gui::getInstance().destroyWidget(mControlsBox->getChildAt(0)); - MWBase::Environment::get().getWindowManager ()->removeStaticMessageBox(); - - std::vector actions = MWBase::Environment::get().getInputManager()->getActionSorting (); + MWBase::Environment::get().getWindowManager()->removeStaticMessageBox(); + std::vector actions; + if(mKeyboardMode) + actions = MWBase::Environment::get().getInputManager()->getActionKeySorting(); + else + actions = MWBase::Environment::get().getInputManager()->getActionControllerSorting(); const int h = 18; const int w = mControlsBox->getWidth() - 28; @@ -454,7 +479,11 @@ namespace MWGui if (desc == "") continue; - std::string binding = MWBase::Environment::get().getInputManager()->getActionBindingName (*it); + std::string binding; + if(mKeyboardMode) + binding = MWBase::Environment::get().getInputManager()->getActionKeyBindingName(*it); + else + binding = MWBase::Environment::get().getInputManager()->getActionControllerBindingName(*it); Gui::SharedStateButton* leftText = mControlsBox->createWidget("SandTextButton", MyGUI::IntCoord(0,curH,w,h), MyGUI::Align::Default); leftText->setCaptionWithReplacing(desc); @@ -488,7 +517,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager ()->staticMessageBox ("#{sControlsMenu3}"); MWBase::Environment::get().getWindowManager ()->disallowMouse(); - MWBase::Environment::get().getInputManager ()->enableDetectingBindingMode (actionId); + MWBase::Environment::get().getInputManager ()->enableDetectingBindingMode (actionId, mKeyboardMode); } @@ -511,7 +540,10 @@ namespace MWGui void SettingsWindow::onResetDefaultBindingsAccept() { - MWBase::Environment::get().getInputManager ()->resetToDefaultBindings (); + if(mKeyboardMode) + MWBase::Environment::get().getInputManager ()->resetToDefaultKeyBindings (); + else + MWBase::Environment::get().getInputManager()->resetToDefaultControllerBindings(); updateControlsBox (); } diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 2619943f9..b4c3004af 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -45,6 +45,9 @@ namespace MWGui // controls MyGUI::ScrollView* mControlsBox; MyGUI::Button* mResetControlsButton; + MyGUI::Button* mKeyboardSwitch; + MyGUI::Button* mControllerSwitch; + bool mKeyboardMode; //if true, setting up the keyboard. Otherwise, it's controller void onOkButtonClicked(MyGUI::Widget* _sender); void onFpsToggled(MyGUI::Widget* _sender); @@ -62,6 +65,8 @@ namespace MWGui void onInputTabMouseWheel(MyGUI::Widget* _sender, int _rel); void onResetDefaultBindings(MyGUI::Widget* _sender); void onResetDefaultBindingsAccept (); + void onKeyboardSwitchClicked(MyGUI::Widget* _sender); + void onControllerSwitchClicked(MyGUI::Widget* _sender); void onWindowResize(MyGUI::Window* _sender); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index b0d2bfeff..a25bb727c 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -2,6 +2,7 @@ #include #include +#include #include @@ -32,6 +33,8 @@ #include "../mwgui/windowbase.hpp" +#include + using namespace ICS; namespace @@ -120,6 +123,7 @@ namespace MWInput , mAlwaysRunActive(Settings::Manager::getBool("always run", "Input")) , mAttemptJump(false) , mControlsDisabled(false) + , mJoystickLastUsed(false) { Ogre::RenderWindow* window = ogre.getWindow (); @@ -128,6 +132,7 @@ namespace MWInput mInputManager->setMouseEventCallback (this); mInputManager->setKeyboardEventCallback (this); mInputManager->setWindowEventCallback(this); + mInputManager->setControllerEventCallback(this); std::string file = userFileExists ? userFile : ""; mInputBinder = new ICS::InputControlSystem(file, true, this, NULL, A_Last); @@ -135,6 +140,7 @@ namespace MWInput adjustMouseRegion (window->getWidth(), window->getHeight()); loadKeyDefaults(); + loadControllerDefaults(); for (int i = 0; i < A_Last; ++i) { @@ -190,6 +196,15 @@ namespace MWInput int action = channel->getNumber(); + if(currentValue > .8) currentValue = 1.0; + else if(currentValue < .6) currentValue = 0.0; + else return; + + if(previousValue > .8) previousValue = 1.0; + else if(previousValue < .6) previousValue = 0.0; + + if(currentValue == previousValue) return; + if (mControlSwitch["playercontrols"]) { if (action == A_Use) @@ -326,6 +341,47 @@ namespace MWInput mInputManager->warpMouse(mMouseX, mMouseY); } + if(mJoystickLastUsed) + { + if (mGuiCursorEnabled) + { + float xAxis = mInputBinder->getChannel(A_MoveLeftRight)->getValue()*2.0f-1.0f; + float yAxis = mInputBinder->getChannel(A_MoveForwardBackward)->getValue()*2.0f-1.0f; + float zAxis = mInputBinder->getChannel(A_LookUpDown)->getValue()*2.0f-1.0f; + const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + + // We keep track of our own mouse position, so that moving the mouse while in + // game mode does not move the position of the GUI cursor + mMouseX += xAxis * dt * 1500.0f; + mMouseY += yAxis * dt * 1500.0f; + mMouseWheel -= zAxis * dt * 1500.0f; + + mMouseX = std::max(0.f, std::min(mMouseX, float(viewSize.width))); + mMouseY = std::max(0.f, std::min(mMouseY, float(viewSize.height))); + + MyGUI::InputManager::getInstance().injectMouseMove( mMouseX, mMouseY, mMouseWheel); + mInputManager->warpMouse(mMouseX, mMouseY); + } + if (mMouseLookEnabled) + { + float xAxis = mInputBinder->getChannel(A_LookLeftRight)->getValue()*2.0f-1.0f; + float yAxis = mInputBinder->getChannel(A_LookUpDown)->getValue()*2.0f-1.0f; + resetIdleTime(); + + float rot[3]; + rot[0] = yAxis * (dt * 100.0f) * 10.0f * mCameraSensitivity * (1.0f/256.f) * (mInvertY ? -1 : 1) * mCameraYMultiplier; + rot[1] = 0.0f; + rot[2] = xAxis * (dt * 100.0f) * 10.0f * mCameraSensitivity * (1.0f/256.f); + + // Only actually turn player when we're not in vanity mode + if(!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot)) + { + mPlayer->yaw(rot[2]); + mPlayer->pitch(rot[0]); + } + } + } + // Disable movement in Gui mode if (!(MWBase::Environment::get().getWindowManager()->isGuiMode() || MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_Running)) @@ -335,34 +391,74 @@ namespace MWInput if (mControlSwitch["playercontrols"]) { bool triedToMove = false; - if (actionIsActive(A_MoveLeft)) - { - triedToMove = true; - mPlayer->setLeftRight (-1); - } - else if (actionIsActive(A_MoveRight)) + bool isRunning = false; + if(mJoystickLastUsed) { - triedToMove = true; - mPlayer->setLeftRight (1); - } + float xAxis = mInputBinder->getChannel(A_MoveLeftRight)->getValue(); + float yAxis = mInputBinder->getChannel(A_MoveForwardBackward)->getValue(); + if (xAxis < .5) + { + triedToMove = true; + mPlayer->setLeftRight (-1); + } + else if (xAxis > .5) + { + triedToMove = true; + mPlayer->setLeftRight (1); + } - if (actionIsActive(A_MoveForward)) - { - triedToMove = true; - mPlayer->setAutoMove (false); - mPlayer->setForwardBackward (1); + if (yAxis < .5) + { + triedToMove = true; + mPlayer->setAutoMove (false); + mPlayer->setForwardBackward (1); + } + else if (yAxis > .5) + { + triedToMove = true; + mPlayer->setAutoMove (false); + mPlayer->setForwardBackward (-1); + } + + else if(mPlayer->getAutoMove()) + { + triedToMove = true; + mPlayer->setForwardBackward (1); + } + isRunning = xAxis > .75 || xAxis < .25 || yAxis > .75 || yAxis < .25; + if(triedToMove) resetIdleTime(); } - else if (actionIsActive(A_MoveBackward)) + else { - triedToMove = true; - mPlayer->setAutoMove (false); - mPlayer->setForwardBackward (-1); - } + if (actionIsActive(A_MoveLeft)) + { + triedToMove = true; + mPlayer->setLeftRight (-1); + } + else if (actionIsActive(A_MoveRight)) + { + triedToMove = true; + mPlayer->setLeftRight (1); + } - else if(mPlayer->getAutoMove()) - { - triedToMove = true; - mPlayer->setForwardBackward (1); + if (actionIsActive(A_MoveForward)) + { + triedToMove = true; + mPlayer->setAutoMove (false); + mPlayer->setForwardBackward (1); + } + else if (actionIsActive(A_MoveBackward)) + { + triedToMove = true; + mPlayer->setAutoMove (false); + mPlayer->setForwardBackward (-1); + } + + else if(mPlayer->getAutoMove()) + { + triedToMove = true; + mPlayer->setForwardBackward (1); + } } mPlayer->setSneak(actionIsActive(A_Sneak)); @@ -374,7 +470,7 @@ namespace MWInput mOverencumberedMessageDelay = 0.f; } - if (mAlwaysRunActive) + if (mAlwaysRunActive || isRunning) mPlayer->setRunState(!actionIsActive(A_Run)); else mPlayer->setRunState(actionIsActive(A_Run)); @@ -519,6 +615,7 @@ namespace MWInput } if (!mControlsDisabled && !consumed) mInputBinder->keyPressed (arg); + mJoystickLastUsed = false; } void InputManager::textInput(const SDL_TextInputEvent &arg) @@ -531,6 +628,7 @@ namespace MWInput void InputManager::keyReleased(const SDL_KeyboardEvent &arg ) { + mJoystickLastUsed = false; OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym); setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); @@ -539,6 +637,7 @@ namespace MWInput void InputManager::mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id ) { + mJoystickLastUsed = false; bool guiMode = false; if (id == SDL_BUTTON_LEFT || id == SDL_BUTTON_RIGHT) // MyGUI only uses these mouse events @@ -563,7 +662,8 @@ namespace MWInput } void InputManager::mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id ) - { + { + mJoystickLastUsed = false; if(mInputBinder->detectingBindingState()) { @@ -583,6 +683,7 @@ namespace MWInput { mInputBinder->mouseMoved (arg); + mJoystickLastUsed = false; resetIdleTime (); if (mGuiCursorEnabled) @@ -631,6 +732,75 @@ namespace MWInput } } + void InputManager::buttonPressed( const SDL_ControllerButtonEvent &arg ) + { + mJoystickLastUsed = true; + bool guiMode = false; + + if (arg.button == SDL_CONTROLLER_BUTTON_A || arg.button == SDL_CONTROLLER_BUTTON_B) // We'll pretend that A is left click and B is right click + { + guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); + guiMode = MyGUI::InputManager::getInstance().injectMousePress(mMouseX, mMouseY, sdlButtonToMyGUI((arg.button == SDL_CONTROLLER_BUTTON_B) ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT)) && guiMode; + if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0) + { + MyGUI::Button* b = MyGUI::InputManager::getInstance ().getMouseFocusWidget ()->castType(false); + if (b && b->getEnabled()) + { + MWBase::Environment::get().getSoundManager ()->playSound ("Menu Click", 1.f, 1.f); + } + } + } + + setPlayerControlsEnabled(!guiMode); + + //esc, to leave inital movie screen + OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); + bool guiFocus = MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); + setPlayerControlsEnabled(!guiFocus); + + if (!mControlsDisabled) + mInputBinder->buttonPressed(arg); + } + + void InputManager::buttonReleased( const SDL_ControllerButtonEvent &arg ) + { + mJoystickLastUsed = true; + if(mInputBinder->detectingBindingState()) + mInputBinder->buttonReleased(arg); + else if(arg.button == SDL_CONTROLLER_BUTTON_A || arg.button == SDL_CONTROLLER_BUTTON_B) + { + bool guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); + guiMode = MyGUI::InputManager::getInstance().injectMouseRelease(mMouseX, mMouseY, sdlButtonToMyGUI((arg.button == SDL_CONTROLLER_BUTTON_B) ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT)) && guiMode; + + if(mInputBinder->detectingBindingState()) return; // don't allow same mouseup to bind as initiated bind + + setPlayerControlsEnabled(!guiMode); + mInputBinder->buttonReleased(arg); + } + else + mInputBinder->buttonReleased(arg); + + //to escape inital movie + OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); + setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); + } + + void InputManager::axisMoved( const SDL_ControllerAxisEvent &arg ) + { + mJoystickLastUsed = true; + if (!mControlsDisabled) + mInputBinder->axisMoved(arg); + } + + void InputManager::controllerAdded(const SDL_ControllerDeviceEvent &arg) + { + mInputBinder->controllerAdded(arg); + } + void InputManager::controllerRemoved(const SDL_ControllerDeviceEvent &arg) + { + mInputBinder->controllerRemoved(arg); + } + void InputManager::windowFocusChange(bool have_focus) { } @@ -877,7 +1047,7 @@ namespace MWInput bool InputManager::actionIsActive (int id) { - return mInputBinder->getChannel (id)->getValue () == 1; + return (mInputBinder->getChannel (id)->getValue ()!=0.0); } void InputManager::loadKeyDefaults (bool force) @@ -945,14 +1115,80 @@ namespace MWInput && mInputBinder->getMouseButtonBinding (control, ICS::Control::INCREASE) == ICS_MAX_DEVICE_BUTTONS )) { - clearAllBindings (control); + clearAllKeyBindings(control); if (defaultKeyBindings.find(i) != defaultKeyBindings.end() && !mInputBinder->isKeyBound(defaultKeyBindings[i])) + { mInputBinder->addKeyBinding(control, defaultKeyBindings[i], ICS::Control::INCREASE); + } else if (defaultMouseButtonBindings.find(i) != defaultMouseButtonBindings.end() && !mInputBinder->isMouseButtonBound(defaultMouseButtonBindings[i])) + { mInputBinder->addMouseButtonBinding (control, defaultMouseButtonBindings[i], ICS::Control::INCREASE); + } + } + } + } + + void InputManager::loadControllerDefaults(bool force) + { + // using hardcoded key defaults is inevitable, if we want the configuration files to stay valid + // across different versions of OpenMW (in the case where another input action is added) + std::map defaultButtonBindings; + + defaultButtonBindings[A_Activate] = SDL_CONTROLLER_BUTTON_A; + defaultButtonBindings[A_ToggleWeapon] = SDL_CONTROLLER_BUTTON_X; + defaultButtonBindings[A_ToggleSpell] = SDL_CONTROLLER_BUTTON_LEFTSHOULDER; + //defaultButtonBindings[A_QuickButtonsMenu] = SDL_GetButtonFromScancode(SDL_SCANCODE_F1); // Need to implement, should be ToggleSpell(5) AND Wait(9) + defaultButtonBindings[A_Sneak] = SDL_CONTROLLER_BUTTON_RIGHTSTICK; + defaultButtonBindings[A_Jump] = SDL_CONTROLLER_BUTTON_Y; + defaultButtonBindings[A_Journal] = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER; + defaultButtonBindings[A_Rest] = SDL_CONTROLLER_BUTTON_BACK; + defaultButtonBindings[A_TogglePOV] = SDL_CONTROLLER_BUTTON_LEFTSTICK; + defaultButtonBindings[A_Inventory] = SDL_CONTROLLER_BUTTON_B; + defaultButtonBindings[A_GameMenu] = SDL_CONTROLLER_BUTTON_START; + defaultButtonBindings[A_QuickSave] = SDL_CONTROLLER_BUTTON_GUIDE; + defaultButtonBindings[A_QuickKey1] = SDL_CONTROLLER_BUTTON_DPAD_UP; + defaultButtonBindings[A_QuickKey2] = SDL_CONTROLLER_BUTTON_DPAD_LEFT; + defaultButtonBindings[A_QuickKey3] = SDL_CONTROLLER_BUTTON_DPAD_DOWN; + defaultButtonBindings[A_QuickKey4] = SDL_CONTROLLER_BUTTON_DPAD_RIGHT; + + std::map defaultAxisBindings; + defaultAxisBindings[A_MoveForwardBackward] = SDL_CONTROLLER_AXIS_LEFTY; + defaultAxisBindings[A_MoveLeftRight] = SDL_CONTROLLER_AXIS_LEFTX; + defaultAxisBindings[A_LookUpDown] = SDL_CONTROLLER_AXIS_RIGHTY; + defaultAxisBindings[A_LookLeftRight] = SDL_CONTROLLER_AXIS_RIGHTX; + defaultAxisBindings[A_Use] = SDL_CONTROLLER_AXIS_TRIGGERRIGHT; + + for (int i = 0; i < A_Last; i++) + { + ICS::Control* control; + bool controlExists = mInputBinder->getChannel(i)->getControlsCount () != 0; + if (!controlExists) + { + control = new ICS::Control(boost::lexical_cast(i), false, true, 0, ICS::ICS_MAX, ICS::ICS_MAX); + mInputBinder->addControl(control); + control->attachChannel(mInputBinder->getChannel(i), ICS::Channel::DIRECT); + } + else + { + control = mInputBinder->getChannel(i)->getAttachedControls ().front().control; + } + + if (!controlExists || force || ( mInputBinder->getJoystickAxisBinding (control, ICS::Control::INCREASE) == ICS::InputControlSystem::UNASSIGNED && mInputBinder->getJoystickButtonBinding (control, ICS::Control::INCREASE) == ICS_MAX_DEVICE_BUTTONS )) + { + clearAllControllerBindings(control); + + if (defaultButtonBindings.find(i) != defaultButtonBindings.end()) + { + control->setValue(0.5f); + mInputBinder->addJoystickButtonBinding(control, defaultButtonBindings[i], ICS::Control::INCREASE); + } + else if (defaultAxisBindings.find(i) != defaultAxisBindings.end()) + { + mInputBinder->addJoystickAxisBinding(control, defaultAxisBindings[i], ICS::Control::INCREASE); + } } } } @@ -1002,7 +1238,7 @@ namespace MWInput return "#{" + descriptions[action] + "}"; } - std::string InputManager::getActionBindingName (int action) + std::string InputManager::getActionKeyBindingName (int action) { if (mInputBinder->getChannel (action)->getControlsCount () == 0) return "#{sNone}"; @@ -1017,7 +1253,81 @@ namespace MWInput return "#{sNone}"; } - std::vector InputManager::getActionSorting() + std::string InputManager::getActionControllerBindingName (int action) + { + if (mInputBinder->getChannel (action)->getControlsCount () == 0) + return "#{sNone}"; + + ICS::Control* c = mInputBinder->getChannel (action)->getAttachedControls ().front().control; + + if (mInputBinder->getJoystickAxisBinding (c, ICS::Control::INCREASE) != ICS::InputControlSystem::UNASSIGNED) + return sdlControllerAxisToString(mInputBinder->getJoystickAxisBinding (c, ICS::Control::INCREASE)); + else if (mInputBinder->getJoystickButtonBinding (c, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS ) + return sdlControllerButtonToString(mInputBinder->getJoystickButtonBinding (c, ICS::Control::INCREASE)); + else + return "#{sNone}"; + } + + std::string InputManager::sdlControllerButtonToString(int button) + { + switch(button) + { + case SDL_CONTROLLER_BUTTON_A: + return "A Button"; + case SDL_CONTROLLER_BUTTON_B: + return "B Button"; + case SDL_CONTROLLER_BUTTON_BACK: + return "Back Button"; + case SDL_CONTROLLER_BUTTON_DPAD_DOWN: + return "DPad Down"; + case SDL_CONTROLLER_BUTTON_DPAD_LEFT: + return "DPad Left"; + case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: + return "DPad Right"; + case SDL_CONTROLLER_BUTTON_DPAD_UP: + return "DPad Up"; + case SDL_CONTROLLER_BUTTON_GUIDE: + return "Guide Button"; + case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: + return "Left Shoulder"; + case SDL_CONTROLLER_BUTTON_LEFTSTICK: + return "Left Stick Button"; + case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: + return "Right Shoulder"; + case SDL_CONTROLLER_BUTTON_RIGHTSTICK: + return "Right Stick Button"; + case SDL_CONTROLLER_BUTTON_START: + return "Start Button"; + case SDL_CONTROLLER_BUTTON_X: + return "X Button"; + case SDL_CONTROLLER_BUTTON_Y: + return "Y Button"; + default: + return "Button " + boost::lexical_cast(button); + } + } + std::string InputManager::sdlControllerAxisToString(int axis) + { + switch(axis) + { + case SDL_CONTROLLER_AXIS_LEFTX: + return "Left Stick X"; + case SDL_CONTROLLER_AXIS_LEFTY: + return "Left Stick Y"; + case SDL_CONTROLLER_AXIS_RIGHTX: + return "Right Stick X"; + case SDL_CONTROLLER_AXIS_RIGHTY: + return "Right Stick Y"; + case SDL_CONTROLLER_AXIS_TRIGGERLEFT: + return "Left Trigger"; + case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: + return "Right Trigger"; + default: + return "Axis " + boost::lexical_cast(axis); + } + } + + std::vector InputManager::getActionKeySorting() { std::vector ret; ret.push_back(A_MoveForward); @@ -1055,11 +1365,42 @@ namespace MWInput return ret; } + std::vector InputManager::getActionControllerSorting() + { + std::vector ret; + ret.push_back(A_TogglePOV); + ret.push_back(A_Sneak); + ret.push_back(A_Activate); + ret.push_back(A_Use); + ret.push_back(A_ToggleWeapon); + ret.push_back(A_ToggleSpell); + ret.push_back(A_AutoMove); + ret.push_back(A_Jump); + ret.push_back(A_Inventory); + ret.push_back(A_Journal); + ret.push_back(A_Rest); + ret.push_back(A_QuickSave); + ret.push_back(A_QuickLoad); + ret.push_back(A_Screenshot); + ret.push_back(A_QuickKeysMenu); + ret.push_back(A_QuickKey1); + ret.push_back(A_QuickKey2); + ret.push_back(A_QuickKey3); + ret.push_back(A_QuickKey4); + ret.push_back(A_QuickKey5); + ret.push_back(A_QuickKey6); + ret.push_back(A_QuickKey7); + ret.push_back(A_QuickKey8); + ret.push_back(A_QuickKey9); + ret.push_back(A_QuickKey10); + + return ret; + } - void InputManager::enableDetectingBindingMode (int action) + void InputManager::enableDetectingBindingMode (int action, bool keyboard) { + mDetectingKeyboard = keyboard; ICS::Control* c = mInputBinder->getChannel (action)->getAttachedControls ().front().control; - mInputBinder->enableDetectingBindingState (c, ICS::Control::INCREASE); } @@ -1075,9 +1416,16 @@ namespace MWInput { //Disallow binding escape key if(key==SDL_SCANCODE_ESCAPE) + { + //Stop binding if esc pressed + mInputBinder->cancelDetectingBindingState(); + MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); + return; + } + if(!mDetectingKeyboard) return; - clearAllBindings(control); + clearAllKeyBindings(control); ICS::DetectingBindingListener::keyBindingDetected (ICS, control, key, direction); MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); } @@ -1085,59 +1433,66 @@ namespace MWInput void InputManager::mouseButtonBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control , unsigned int button, ICS::Control::ControlChangingDirection direction) { - clearAllBindings(control); + if(!mDetectingKeyboard) + return; + clearAllKeyBindings(control); ICS::DetectingBindingListener::mouseButtonBindingDetected (ICS, control, button, direction); MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); } void InputManager::joystickAxisBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , int deviceId, int axis, ICS::Control::ControlChangingDirection direction) + , int axis, ICS::Control::ControlChangingDirection direction) { - clearAllBindings(control); - ICS::DetectingBindingListener::joystickAxisBindingDetected (ICS, control, deviceId, axis, direction); - MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); - } - - void InputManager::joystickButtonBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , int deviceId, unsigned int button, ICS::Control::ControlChangingDirection direction) - { - clearAllBindings(control); - ICS::DetectingBindingListener::joystickButtonBindingDetected (ICS, control, deviceId, button, direction); - MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); - } + //only allow binding to the trigers + if(axis != SDL_CONTROLLER_AXIS_TRIGGERLEFT && axis != SDL_CONTROLLER_AXIS_TRIGGERRIGHT) + return; + if(mDetectingKeyboard) + return; - void InputManager::joystickPOVBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , int deviceId, int pov,ICS:: InputControlSystem::POVAxis axis, ICS::Control::ControlChangingDirection direction) - { - clearAllBindings(control); - ICS::DetectingBindingListener::joystickPOVBindingDetected (ICS, control, deviceId, pov, axis, direction); + clearAllControllerBindings(control); + control->setValue(0.5f); //axis bindings must start at 0.5 + ICS::DetectingBindingListener::joystickAxisBindingDetected (ICS, control, axis, direction); MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); } - void InputManager::joystickSliderBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , int deviceId, int slider, ICS::Control::ControlChangingDirection direction) + void InputManager::joystickButtonBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control + , unsigned int button, ICS::Control::ControlChangingDirection direction) { - clearAllBindings(control); - ICS::DetectingBindingListener::joystickSliderBindingDetected (ICS, control, deviceId, slider, direction); + if(mDetectingKeyboard) + return; + clearAllControllerBindings(control); + ICS::DetectingBindingListener::joystickButtonBindingDetected (ICS, control, button, direction); MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); } - void InputManager::clearAllBindings (ICS::Control* control) + void InputManager::clearAllKeyBindings (ICS::Control* control) { // right now we don't really need multiple bindings for the same action, so remove all others first if (mInputBinder->getKeyBinding (control, ICS::Control::INCREASE) != SDL_SCANCODE_UNKNOWN) mInputBinder->removeKeyBinding (mInputBinder->getKeyBinding (control, ICS::Control::INCREASE)); if (mInputBinder->getMouseButtonBinding (control, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS) mInputBinder->removeMouseButtonBinding (mInputBinder->getMouseButtonBinding (control, ICS::Control::INCREASE)); + } - /// \todo add joysticks here once they are added + void InputManager::clearAllControllerBindings (ICS::Control* control) + { + // right now we don't really need multiple bindings for the same action, so remove all others first + if (mInputBinder->getJoystickAxisBinding (control, ICS::Control::INCREASE) != SDL_SCANCODE_UNKNOWN) + mInputBinder->removeJoystickAxisBinding (mInputBinder->getJoystickAxisBinding (control, ICS::Control::INCREASE)); + if (mInputBinder->getJoystickButtonBinding (control, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS) + mInputBinder->removeJoystickButtonBinding (mInputBinder->getJoystickButtonBinding (control, ICS::Control::INCREASE)); } - void InputManager::resetToDefaultBindings() + void InputManager::resetToDefaultKeyBindings() { loadKeyDefaults(true); } + void InputManager::resetToDefaultControllerBindings() + { + loadControllerDefaults(true); + } + MyGUI::MouseButton InputManager::sdlButtonToMyGUI(Uint8 button) { //The right button is the second button, according to MyGUI diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 346e02ff9..61dbf18f8 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -55,6 +55,7 @@ namespace MWInput public SFO::KeyListener, public SFO::MouseListener, public SFO::WindowListener, + public SFO::ControllerListener, public ICS::ChannelListener, public ICS::DetectingBindingListener { @@ -82,11 +83,16 @@ namespace MWInput virtual bool getControlSwitch (const std::string& sw); virtual std::string getActionDescription (int action); - virtual std::string getActionBindingName (int action); + virtual std::string getActionKeyBindingName (int action); + virtual std::string getActionControllerBindingName (int action); + virtual std::string sdlControllerAxisToString(int axis); + virtual std::string sdlControllerButtonToString(int button); virtual int getNumActions() { return A_Last; } - virtual std::vector getActionSorting (); - virtual void enableDetectingBindingMode (int action); - virtual void resetToDefaultBindings(); + virtual std::vector getActionKeySorting(); + virtual std::vector getActionControllerSorting(); + virtual void enableDetectingBindingMode (int action, bool keyboard); + virtual void resetToDefaultKeyBindings(); + virtual void resetToDefaultControllerBindings(); public: virtual void keyPressed(const SDL_KeyboardEvent &arg ); @@ -97,6 +103,12 @@ namespace MWInput virtual void mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id ); virtual void mouseMoved( const SFO::MouseMotionEvent &arg ); + virtual void buttonPressed( const SDL_ControllerButtonEvent &arg); + virtual void buttonReleased( const SDL_ControllerButtonEvent &arg); + virtual void axisMoved( const SDL_ControllerAxisEvent &arg); + virtual void controllerAdded( const SDL_ControllerDeviceEvent &arg); + virtual void controllerRemoved( const SDL_ControllerDeviceEvent &arg); + virtual void windowVisibilityChange( bool visible ); virtual void windowFocusChange( bool have_focus ); virtual void windowResized (int x, int y); @@ -114,20 +126,16 @@ namespace MWInput , unsigned int button, ICS::Control::ControlChangingDirection direction); virtual void joystickAxisBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , int deviceId, int axis, ICS::Control::ControlChangingDirection direction); + , int axis, ICS::Control::ControlChangingDirection direction); virtual void joystickButtonBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , int deviceId, unsigned int button, ICS::Control::ControlChangingDirection direction); - - virtual void joystickPOVBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , int deviceId, int pov,ICS:: InputControlSystem::POVAxis axis, ICS::Control::ControlChangingDirection direction); - - virtual void joystickSliderBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , int deviceId, int slider, ICS::Control::ControlChangingDirection direction); + , unsigned int button, ICS::Control::ControlChangingDirection direction); - void clearAllBindings (ICS::Control* control); + void clearAllKeyBindings (ICS::Control* control); + void clearAllControllerBindings (ICS::Control* control); private: + bool mJoystickLastUsed; OEngine::Render::OgreRenderer &mOgre; MWWorld::Player* mPlayer; OMW::Engine& mEngine; @@ -156,6 +164,8 @@ namespace MWInput bool mMouseLookEnabled; bool mGuiCursorEnabled; + bool mDetectingKeyboard; + float mOverencumberedMessageDelay; float mMouseX; @@ -191,12 +201,15 @@ namespace MWInput void quickLoad(); void quickSave(); + bool isAReverse(int action); + void quickKey (int index); void showQuickKeysMenu(); bool actionIsActive (int id); void loadKeyDefaults(bool force = false); + void loadControllerDefaults(bool force = false); private: enum Actions @@ -261,6 +274,11 @@ namespace MWInput A_ToggleDebug, + A_LookUpDown, //Joystick look + A_LookLeftRight, + A_MoveForwardBackward, + A_MoveLeftRight, + A_Last // Marker for the last item }; }; diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index d8d13a921..b71e92555 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -268,7 +268,7 @@ namespace MWScript std::string InterpreterContext::getActionBinding(const std::string& action) const { - std::vector actions = MWBase::Environment::get().getInputManager()->getActionSorting (); + std::vector actions = MWBase::Environment::get().getInputManager()->getActionKeySorting (); for (std::vector::const_iterator it = actions.begin(); it != actions.end(); ++it) { std::string desc = MWBase::Environment::get().getInputManager()->getActionDescription (*it); @@ -276,7 +276,7 @@ namespace MWScript continue; if(desc == action) - return MWBase::Environment::get().getInputManager()->getActionBindingName (*it); + return MWBase::Environment::get().getInputManager()->getActionKeyBindingName (*it); } return "None"; diff --git a/extern/oics/ICSControl.cpp b/extern/oics/ICSControl.cpp index 7c804d6ee..974d69f08 100644 --- a/extern/oics/ICSControl.cpp +++ b/extern/oics/ICSControl.cpp @@ -43,10 +43,10 @@ namespace ICS , mAxisBindable(axisBindable) , currentChangingDirection(STOP) { - + } - Control::~Control() + Control::~Control() { mAttachedChannels.clear(); } @@ -92,7 +92,7 @@ namespace ICS } void Control::setChangingDirection(ControlChangingDirection direction) - { + { currentChangingDirection = direction; mPendingActions.push_back(direction); } @@ -102,9 +102,9 @@ namespace ICS if(!mPendingActions.empty()) { size_t timedActionsCount = 0; - + std::list::iterator cached_end = mPendingActions.end(); - for(std::list::iterator it = mPendingActions.begin() ; + for(std::list::iterator it = mPendingActions.begin() ; it != cached_end ; ++it) { if( (*it) != Control::STOP ) @@ -112,14 +112,14 @@ namespace ICS timedActionsCount++; } } - + float timeSinceLastFramePart = timeSinceLastFrame / std::max(1, timedActionsCount); - for(std::list::iterator it = mPendingActions.begin() ; + for(std::list::iterator it = mPendingActions.begin() ; it != cached_end ; ++it) { if( (*it) != Control::STOP ) { - this->setValue(mValue + + this->setValue(mValue + (((int)(*it)) * mStepSize * mStepsPerSeconds * (timeSinceLastFramePart))); } else if(mAutoReverseToInitialValue && !mIgnoreAutoReverse && mValue != mInitialValue ) @@ -141,7 +141,7 @@ namespace ICS } else if( currentChangingDirection != Control::STOP ) { - this->setValue(mValue + + this->setValue(mValue + (((int)currentChangingDirection) * mStepSize * mStepsPerSeconds * (timeSinceLastFrame))); } else if(mAutoReverseToInitialValue && !mIgnoreAutoReverse && mValue != mInitialValue ) diff --git a/extern/oics/ICSInputControlSystem.cpp b/extern/oics/ICSInputControlSystem.cpp index 7dc026c7e..4237060bb 100644 --- a/extern/oics/ICSInputControlSystem.cpp +++ b/extern/oics/ICSInputControlSystem.cpp @@ -57,10 +57,10 @@ namespace ICS xmlDoc = new TiXmlDocument(file.c_str()); xmlDoc->LoadFile(); - if(xmlDoc->Error()) + if(xmlDoc->Error()) { - std::ostringstream message; - message << "TinyXml reported an error reading \""+ file + "\". Row " << + std::ostringstream message; + message << "TinyXml reported an error reading \""+ file + "\". Row " << (int)xmlDoc->ErrorRow() << ", Col " << (int)xmlDoc->ErrorCol() << ": " << xmlDoc->ErrorDesc() ; ICS_LOG(message.str()); @@ -78,10 +78,10 @@ namespace ICS TiXmlElement* xmlControl = xmlRoot->FirstChildElement("Control"); - size_t controlChannelCount = 0; - while(xmlControl) + size_t controlChannelCount = 0; + while(xmlControl) { - TiXmlElement* xmlChannel = xmlControl->FirstChildElement("Channel"); + TiXmlElement* xmlChannel = xmlControl->FirstChildElement("Channel"); while(xmlChannel) { controlChannelCount = std::max(channelCount, FromString(xmlChannel->Attribute("number"))+1); @@ -108,7 +108,7 @@ namespace ICS // // - TiXmlElement* xmlChannelFilter = xmlRoot->FirstChildElement("ChannelFilter"); + TiXmlElement* xmlChannelFilter = xmlRoot->FirstChildElement("ChannelFilter"); while(xmlChannelFilter) { int ch = FromString(xmlChannelFilter->Attribute("number")); @@ -130,12 +130,12 @@ namespace ICS float step = FromString(xmlInterval->Attribute("step")); ICS_LOG("Applying Bezier filter to channel [number=" - + ToString(ch) + ", startX=" - + ToString(startX) + ", startY=" - + ToString(startY) + ", midX=" - + ToString(midX) + ", midY=" - + ToString(midY) + ", endX=" - + ToString(endX) + ", endY=" + + ToString(ch) + ", startX=" + + ToString(startX) + ", startY=" + + ToString(startY) + ", midX=" + + ToString(midX) + ", midY=" + + ToString(midY) + ", endX=" + + ToString(endX) + ", endY=" + ToString(endY) + ", step=" + ToString(step) + "]"); @@ -149,8 +149,8 @@ namespace ICS xmlChannelFilter = xmlChannelFilter->NextSiblingElement("ChannelFilter"); } - xmlControl = xmlRoot->FirstChildElement("Control"); - while(xmlControl) + xmlControl = xmlRoot->FirstChildElement("Control"); + while(xmlControl) { bool axisBindable = true; if(xmlControl->Attribute("axisBindable")) @@ -173,11 +173,11 @@ namespace ICS std::string value(xmlControl->Attribute("stepSize")); if(value == "MAX") { - _stepSize = ICS_MAX; + _stepSize = ICS_MAX; } else { - _stepSize = FromString(value.c_str()); + _stepSize = FromString(value.c_str()); } } else @@ -191,7 +191,7 @@ namespace ICS std::string value(xmlControl->Attribute("stepsPerSeconds")); if(value == "MAX") { - _stepsPerSeconds = ICS_MAX; + _stepsPerSeconds = ICS_MAX; } else { @@ -221,12 +221,8 @@ namespace ICS loadJoystickButtonBinders(xmlControl); - loadJoystickPOVBinders(xmlControl); - - loadJoystickSliderBinders(xmlControl); - // Attach controls to channels - TiXmlElement* xmlChannel = xmlControl->FirstChildElement("Channel"); + TiXmlElement* xmlChannel = xmlControl->FirstChildElement("Channel"); while(xmlChannel) { ICS_LOG("\tAttaching control to channel [number=" @@ -247,7 +243,7 @@ namespace ICS { percentage = val; } - } + } else { ICS_LOG("ERROR: attaching percentage value range is [0,1]"); @@ -277,6 +273,35 @@ namespace ICS } delete xmlDoc; + } + + /* Joystick Init */ + + //Load controller mappings + int res = SDL_GameControllerAddMappingsFromFile("resources/gamecontrollerdb.txt"); + if(res == -1) + { + ICS_LOG(std::string("Error loading controller bindings: ")+SDL_GetError()); + } + else + { + ICS_LOG(std::string("Loaded ")+boost::lexical_cast(res)+" Game controller bindings"); + } + + //Open all presently connected sticks + int numSticks = SDL_NumJoysticks(); + for(int i = 0; i < numSticks; i++) + { + if(SDL_IsGameController(i)) + { + SDL_ControllerDeviceEvent evt; + evt.which = i; + controllerAdded(evt); + } + else + { + ICS_LOG(std::string("Unusable controller plugged in: ")+SDL_JoystickNameForIndex(i)); + } } ICS_LOG(" - InputControlSystem Created - "); @@ -335,7 +360,7 @@ namespace ICS for(std::vector::const_iterator o = mChannels.begin() ; o != mChannels.end(); ++o) { ICS::IntervalList intervals = (*o)->getIntervals(); - + if(intervals.size() > 1) // all channels have a default linear filter { TiXmlElement ChannelFilter( "ChannelFilter" ); @@ -368,7 +393,7 @@ namespace ICS ChannelFilter.InsertEndChild(XMLInterval); } - + ++interval; } @@ -398,7 +423,7 @@ namespace ICS control.SetAttribute( "autoReverseToInitialValue", "false" ); } control.SetAttribute( "initialValue", ToString((*o)->getInitialValue()).c_str() ); - + if((*o)->getStepSize() == ICS_MAX) { control.SetAttribute( "stepSize", "MAX" ); @@ -442,12 +467,12 @@ namespace ICS control.InsertEndChild(keyBinder); } - if(getMouseAxisBinding(*o, Control/*::ControlChangingDirection*/::INCREASE) + if(getMouseAxisBinding(*o, Control/*::ControlChangingDirection*/::INCREASE) != InputControlSystem/*::NamedAxis*/::UNASSIGNED) { TiXmlElement binder( "MouseBinder" ); - InputControlSystem::NamedAxis axis = + InputControlSystem::NamedAxis axis = getMouseAxisBinding(*o, Control/*::ControlChangingDirection*/::INCREASE); if(axis == InputControlSystem/*::NamedAxis*/::X) { @@ -466,12 +491,12 @@ namespace ICS control.InsertEndChild(binder); } - if(getMouseAxisBinding(*o, Control/*::ControlChangingDirection*/::DECREASE) + if(getMouseAxisBinding(*o, Control/*::ControlChangingDirection*/::DECREASE) != InputControlSystem/*::NamedAxis*/::UNASSIGNED) { TiXmlElement binder( "MouseBinder" ); - InputControlSystem::NamedAxis axis = + InputControlSystem::NamedAxis axis = getMouseAxisBinding(*o, Control/*::ControlChangingDirection*/::DECREASE); if(axis == InputControlSystem/*::NamedAxis*/::X) { @@ -490,7 +515,7 @@ namespace ICS control.InsertEndChild(binder); } - if(getMouseButtonBinding(*o, Control/*::ControlChangingDirection*/::INCREASE) + if(getMouseButtonBinding(*o, Control/*::ControlChangingDirection*/::INCREASE) != ICS_MAX_DEVICE_BUTTONS) { TiXmlElement binder( "MouseButtonBinder" ); @@ -516,7 +541,7 @@ namespace ICS control.InsertEndChild(binder); } - if(getMouseButtonBinding(*o, Control/*::ControlChangingDirection*/::DECREASE) + if(getMouseButtonBinding(*o, Control/*::ControlChangingDirection*/::DECREASE) != ICS_MAX_DEVICE_BUTTONS) { TiXmlElement binder( "MouseButtonBinder" ); @@ -541,152 +566,57 @@ namespace ICS binder.SetAttribute( "direction", "DECREASE" ); control.InsertEndChild(binder); } + if(getJoystickAxisBinding(*o, Control/*::ControlChangingDirection*/::INCREASE) + != /*NamedAxis::*/UNASSIGNED) + { + TiXmlElement binder( "JoystickAxisBinder" ); - JoystickIDList::const_iterator it = mJoystickIDList.begin(); - while(it != mJoystickIDList.end()) - { - int deviceId = *it; - - if(getJoystickAxisBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE) - != /*NamedAxis::*/UNASSIGNED) - { - TiXmlElement binder( "JoystickAxisBinder" ); - - binder.SetAttribute( "axis", ToString( - getJoystickAxisBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); - - binder.SetAttribute( "direction", "INCREASE" ); - - binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); - - control.InsertEndChild(binder); - } - - if(getJoystickAxisBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE) - != /*NamedAxis::*/UNASSIGNED) - { - TiXmlElement binder( "JoystickAxisBinder" ); - - binder.SetAttribute( "axis", ToString( - getJoystickAxisBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); - - binder.SetAttribute( "direction", "DECREASE" ); + binder.SetAttribute( "axis", ToString( + getJoystickAxisBinding(*o, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); - binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); - - control.InsertEndChild(binder); - } + binder.SetAttribute( "direction", "INCREASE" ); - if(getJoystickButtonBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE) - != ICS_MAX_DEVICE_BUTTONS) - { - TiXmlElement binder( "JoystickButtonBinder" ); + control.InsertEndChild(binder); + } - binder.SetAttribute( "button", ToString( - getJoystickButtonBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); + if(getJoystickAxisBinding(*o, Control/*::ControlChangingDirection*/::DECREASE) + != /*NamedAxis::*/UNASSIGNED) + { + TiXmlElement binder( "JoystickAxisBinder" ); - binder.SetAttribute( "direction", "INCREASE" ); + binder.SetAttribute( "axis", ToString( + getJoystickAxisBinding(*o, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); - binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); - - control.InsertEndChild(binder); - } + binder.SetAttribute( "direction", "DECREASE" ); - if(getJoystickButtonBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE) - != ICS_MAX_DEVICE_BUTTONS) - { - TiXmlElement binder( "JoystickButtonBinder" ); + control.InsertEndChild(binder); + } - binder.SetAttribute( "button", ToString( - getJoystickButtonBinding(*o, *it, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); + if(getJoystickButtonBinding(*o, Control/*::ControlChangingDirection*/::INCREASE) + != ICS_MAX_DEVICE_BUTTONS) + { + TiXmlElement binder( "JoystickButtonBinder" ); - binder.SetAttribute( "direction", "DECREASE" ); + binder.SetAttribute( "button", ToString( + getJoystickButtonBinding(*o, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); - binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); - - control.InsertEndChild(binder); - } + binder.SetAttribute( "direction", "INCREASE" ); - if(getJoystickPOVBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE).index >= 0) - { - TiXmlElement binder( "JoystickPOVBinder" ); + control.InsertEndChild(binder); + } - POVBindingPair POVPair = getJoystickPOVBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE); - - binder.SetAttribute( "pov", ToString(POVPair.index).c_str() ); + if(getJoystickButtonBinding(*o, Control/*::ControlChangingDirection*/::DECREASE) + != ICS_MAX_DEVICE_BUTTONS) + { + TiXmlElement binder( "JoystickButtonBinder" ); - binder.SetAttribute( "direction", "INCREASE" ); + binder.SetAttribute( "button", ToString( + getJoystickButtonBinding(*o, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); - binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); + binder.SetAttribute( "direction", "DECREASE" ); - if(POVPair.axis == ICS::InputControlSystem::EastWest) - { - binder.SetAttribute( "axis", "EastWest" ); - } - else - { - binder.SetAttribute( "axis", "NorthSouth" ); - } - - control.InsertEndChild(binder); - } - - if(getJoystickPOVBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE).index >= 0) - { - TiXmlElement binder( "JoystickPOVBinder" ); - - POVBindingPair POVPair = getJoystickPOVBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE); - - binder.SetAttribute( "pov", ToString(POVPair.index).c_str() ); - - binder.SetAttribute( "direction", "DECREASE" ); - - binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); - - if(POVPair.axis == ICS::InputControlSystem::EastWest) - { - binder.SetAttribute( "axis", "EastWest" ); - } - else - { - binder.SetAttribute( "axis", "NorthSouth" ); - } - - control.InsertEndChild(binder); - } - - if(getJoystickSliderBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE) - != /*NamedAxis::*/UNASSIGNED) - { - TiXmlElement binder( "JoystickSliderBinder" ); - - binder.SetAttribute( "slider", ToString( - getJoystickSliderBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); - - binder.SetAttribute( "direction", "INCREASE" ); - - binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); - - control.InsertEndChild(binder); - } - - if(getJoystickSliderBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE) - != /*NamedAxis::*/UNASSIGNED) - { - TiXmlElement binder( "JoystickSliderBinder" ); - - binder.SetAttribute( "slider", ToString( - getJoystickSliderBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); - - binder.SetAttribute( "direction", "DECREASE" ); - - binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); - - control.InsertEndChild(binder); - } - - ++it; - } + control.InsertEndChild(binder); + } std::list channels = (*o)->getAttachedChannels(); @@ -697,19 +627,19 @@ namespace ICS binder.SetAttribute( "number", ToString((*it)->getNumber()).c_str() ); - Channel::ChannelDirection direction = (*it)->getAttachedControlBinding(*o).direction; + Channel::ChannelDirection direction = (*it)->getAttachedControlBinding(*o).direction; if(direction == Channel/*::ChannelDirection*/::DIRECT) { binder.SetAttribute( "direction", "DIRECT" ); - } + } else { binder.SetAttribute( "direction", "INVERSE" ); } - + float percentage = (*it)->getAttachedControlBinding(*o).percentage; binder.SetAttribute( "percentage", ToString(percentage).c_str() ); - + control.InsertEndChild(binder); } @@ -731,7 +661,7 @@ namespace ICS } } - //! @todo Future versions should consider channel exponentials and mixtures, so + //! @todo Future versions should consider channel exponentials and mixtures, so // after updating Controls, Channels should be updated according to their values } @@ -745,24 +675,6 @@ namespace ICS return mControls[i]->getValue(); } - void InputControlSystem::addJoystick(int deviceId) - { - ICS_LOG("Adding joystick (device id: " + ToString(deviceId) + ")"); - - for(int j = 0 ; j < ICS_MAX_JOYSTICK_AXIS ; j++) - { - if(mControlsJoystickAxisBinderMap[deviceId].find(j) == mControlsJoystickAxisBinderMap[deviceId].end()) - { - ControlAxisBinderItem controlJoystickBinderItem; - controlJoystickBinderItem.direction = Control::STOP; - controlJoystickBinderItem.control = NULL; - mControlsJoystickAxisBinderMap[deviceId][j] = controlJoystickBinderItem; - } - } - - mJoystickIDList.push_back(deviceId); - } - Control* InputControlSystem::findControl(std::string name) { if(mActive) diff --git a/extern/oics/ICSInputControlSystem.h b/extern/oics/ICSInputControlSystem.h index 6a6a6bf09..0bdd67b34 100644 --- a/extern/oics/ICSInputControlSystem.h +++ b/extern/oics/ICSInputControlSystem.h @@ -32,7 +32,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "ICSControl.h" #include "ICSChannel.h" -#include "../sdl4ogre/events.h" +#include "../sdl4ogre/events.h" + +#include "boost/lexical_cast.hpp" #define ICS_LOG(text) if(mLog) mLog->logMessage( ("ICS: " + std::string(text)).c_str() ); #define ICS_MAX_JOYSTICK_AXIS 16 @@ -43,16 +45,16 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. namespace ICS { - class DllExport InputControlSystemLog + class DllExport InputControlSystemLog { public: virtual void logMessage(const char* text) = 0; }; - class DllExport InputControlSystem : + class DllExport InputControlSystem : public SFO::MouseListener, public SFO::KeyListener, - public SFO::JoyListener + public SFO::ControllerListener { public: @@ -62,7 +64,7 @@ namespace ICS typedef NamedAxis MouseAxis; // MouseAxis is deprecated. It will be removed in future versions - typedef std::list JoystickIDList; + typedef std::map JoystickIDList; typedef struct { @@ -72,7 +74,7 @@ namespace ICS InputControlSystem(std::string file = "", bool active = true , DetectingBindingListener* detectingBindingListener = NULL - , InputControlSystemLog* log = NULL, size_t channelCount = 16); + , InputControlSystemLog* log = NULL, size_t channelCount = 16); ~InputControlSystem(); std::string getFileName(){ return mFileName; }; @@ -98,50 +100,42 @@ namespace ICS inline void activate(){ this->mActive = true; }; inline void deactivate(){ this->mActive = false; }; - void addJoystick(int deviceId); + void controllerAdded (const SDL_ControllerDeviceEvent &args); + void controllerRemoved(const SDL_ControllerDeviceEvent &args); JoystickIDList& getJoystickIdList(){ return mJoystickIDList; }; - + // MouseListener void mouseMoved(const SFO::MouseMotionEvent &evt); void mousePressed(const SDL_MouseButtonEvent &evt, Uint8); void mouseReleased(const SDL_MouseButtonEvent &evt, Uint8); - + // KeyListener void keyPressed(const SDL_KeyboardEvent &evt); void keyReleased(const SDL_KeyboardEvent &evt); - - // JoyStickListener - void buttonPressed(const SDL_JoyButtonEvent &evt, int button); - void buttonReleased(const SDL_JoyButtonEvent &evt, int button); - void axisMoved(const SDL_JoyAxisEvent &evt, int axis); - void povMoved(const SDL_JoyHatEvent &evt, int index); - //TODO: does this have an SDL equivalent? - //bool sliderMoved(const OIS::JoyStickEvent &evt, int index); + + // ControllerListener + void buttonPressed(const SDL_ControllerButtonEvent &evt); + void buttonReleased(const SDL_ControllerButtonEvent &evt); + void axisMoved(const SDL_ControllerAxisEvent &evt); void addKeyBinding(Control* control, SDL_Scancode key, Control::ControlChangingDirection direction); bool isKeyBound(SDL_Scancode key) const; void addMouseAxisBinding(Control* control, NamedAxis axis, Control::ControlChangingDirection direction); void addMouseButtonBinding(Control* control, unsigned int button, Control::ControlChangingDirection direction); bool isMouseButtonBound(unsigned int button) const; - void addJoystickAxisBinding(Control* control, int deviceId, int axis, Control::ControlChangingDirection direction); - void addJoystickButtonBinding(Control* control, int deviceId, unsigned int button, Control::ControlChangingDirection direction); - void addJoystickPOVBinding(Control* control, int deviceId, int index, POVAxis axis, Control::ControlChangingDirection direction); - void addJoystickSliderBinding(Control* control, int deviceId, int index, Control::ControlChangingDirection direction); + void addJoystickAxisBinding(Control* control, int axis, Control::ControlChangingDirection direction); + void addJoystickButtonBinding(Control* control, unsigned int button, Control::ControlChangingDirection direction); void removeKeyBinding(SDL_Scancode key); void removeMouseAxisBinding(NamedAxis axis); void removeMouseButtonBinding(unsigned int button); - void removeJoystickAxisBinding(int deviceId, int axis); - void removeJoystickButtonBinding(int deviceId, unsigned int button); - void removeJoystickPOVBinding(int deviceId, int index, POVAxis axis); - void removeJoystickSliderBinding(int deviceId, int index); + void removeJoystickAxisBinding(int axis); + void removeJoystickButtonBinding(unsigned int button); SDL_Scancode getKeyBinding(Control* control, ICS::Control::ControlChangingDirection direction); NamedAxis getMouseAxisBinding(Control* control, ICS::Control::ControlChangingDirection direction); unsigned int getMouseButtonBinding(Control* control, ICS::Control::ControlChangingDirection direction); - int getJoystickAxisBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction); - unsigned int getJoystickButtonBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction); - POVBindingPair getJoystickPOVBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction); - int getJoystickSliderBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction); + int getJoystickAxisBinding(Control* control, ICS::Control::ControlChangingDirection direction); + unsigned int getJoystickButtonBinding(Control* control, ICS::Control::ControlChangingDirection direction); std::string scancodeToString(SDL_Scancode key); @@ -193,17 +187,10 @@ namespace ICS typedef std::map ControlsPOVBinderMapType; // typedef std::map ControlsSliderBinderMapType; // - typedef std::map JoystickAxisBinderMapType; // > - typedef std::map JoystickButtonBinderMapType; // > - typedef std::map > JoystickPOVBinderMapType; // > > - typedef std::map JoystickSliderBinderMapType; // > - ControlsAxisBinderMapType mControlsMouseAxisBinderMap; // ControlsButtonBinderMapType mControlsMouseButtonBinderMap; // - JoystickAxisBinderMapType mControlsJoystickAxisBinderMap; // > - JoystickButtonBinderMapType mControlsJoystickButtonBinderMap; // > - JoystickPOVBinderMapType mControlsJoystickPOVBinderMap; // > > - JoystickSliderBinderMapType mControlsJoystickSliderBinderMap; // > + ControlsAxisBinderMapType mControlsJoystickAxisBinderMap; // + ControlsButtonBinderMapType mControlsJoystickButtonBinderMap; // std::vector mControls; std::vector mChannels; @@ -212,7 +199,7 @@ namespace ICS bool mActive; InputControlSystemLog* mLog; - + DetectingBindingListener* mDetectingBindingListener; Control* mDetectingBindingControl; Control::ControlChangingDirection mDetectingBindingDirection; @@ -243,16 +230,11 @@ namespace ICS , unsigned int button, Control::ControlChangingDirection direction); virtual void joystickAxisBindingDetected(InputControlSystem* ICS, Control* control - , int deviceId, int axis, Control::ControlChangingDirection direction); + , int axis, Control::ControlChangingDirection direction); virtual void joystickButtonBindingDetected(InputControlSystem* ICS, Control* control - , int deviceId, unsigned int button, Control::ControlChangingDirection direction); - - virtual void joystickPOVBindingDetected(InputControlSystem* ICS, Control* control - , int deviceId, int pov, InputControlSystem::POVAxis axis, Control::ControlChangingDirection direction); + , unsigned int button, Control::ControlChangingDirection direction); - virtual void joystickSliderBindingDetected(InputControlSystem* ICS, Control* control - , int deviceId, int slider, Control::ControlChangingDirection direction); }; static const float ICS_MAX = std::numeric_limits::max(); diff --git a/extern/oics/ICSInputControlSystem_joystick.cpp b/extern/oics/ICSInputControlSystem_joystick.cpp index 8bf931788..9cd9b1461 100644 --- a/extern/oics/ICSInputControlSystem_joystick.cpp +++ b/extern/oics/ICSInputControlSystem_joystick.cpp @@ -27,14 +27,15 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "ICSInputControlSystem.h" #define SDL_JOY_AXIS_MIN -32768 -#define SDL_JOY_AXIS_MAX 32767 +#define SDL_JOY_AXIS_MAX 32767 +#define DEADZONE 0.1f namespace ICS { // load xml void InputControlSystem::loadJoystickAxisBinders(TiXmlElement* xmlControlNode) { - TiXmlElement* xmlJoystickBinder = xmlControlNode->FirstChildElement("JoystickAxisBinder"); + TiXmlElement* xmlJoystickBinder = xmlControlNode->FirstChildElement("JoystickAxisBinder"); while(xmlJoystickBinder) { Control::ControlChangingDirection dir = Control::STOP; @@ -47,8 +48,7 @@ namespace ICS dir = Control::DECREASE; } - addJoystickAxisBinding(mControls.back(), FromString(xmlJoystickBinder->Attribute("deviceId")) - , FromString(xmlJoystickBinder->Attribute("axis")), dir); + addJoystickAxisBinding(mControls.back(), FromString(xmlJoystickBinder->Attribute("axis")), dir); xmlJoystickBinder = xmlJoystickBinder->NextSiblingElement("JoystickAxisBinder"); } @@ -56,7 +56,7 @@ namespace ICS void InputControlSystem::loadJoystickButtonBinders(TiXmlElement* xmlControlNode) { - TiXmlElement* xmlJoystickButtonBinder = xmlControlNode->FirstChildElement("JoystickButtonBinder"); + TiXmlElement* xmlJoystickButtonBinder = xmlControlNode->FirstChildElement("JoystickButtonBinder"); while(xmlJoystickButtonBinder) { Control::ControlChangingDirection dir = Control::STOP; @@ -69,335 +69,168 @@ namespace ICS dir = Control::DECREASE; } - addJoystickButtonBinding(mControls.back(), FromString(xmlJoystickButtonBinder->Attribute("deviceId")) - , FromString(xmlJoystickButtonBinder->Attribute("button")), dir); + addJoystickButtonBinding(mControls.back(), FromString(xmlJoystickButtonBinder->Attribute("button")), dir); xmlJoystickButtonBinder = xmlJoystickButtonBinder->NextSiblingElement("JoystickButtonBinder"); } } - void InputControlSystem::loadJoystickPOVBinders(TiXmlElement* xmlControlNode) - { - TiXmlElement* xmlJoystickPOVBinder = xmlControlNode->FirstChildElement("JoystickPOVBinder"); - while(xmlJoystickPOVBinder) - { - Control::ControlChangingDirection dir = Control::STOP; - if(std::string(xmlJoystickPOVBinder->Attribute("direction")) == "INCREASE") - { - dir = Control::INCREASE; - } - else if(std::string(xmlJoystickPOVBinder->Attribute("direction")) == "DECREASE") - { - dir = Control::DECREASE; - } - - InputControlSystem::POVAxis axis = /*POVAxis::*/NorthSouth; - if(std::string(xmlJoystickPOVBinder->Attribute("axis")) == "EastWest") - { - axis = /*POVAxis::*/EastWest; - } - - addJoystickPOVBinding(mControls.back(), FromString(xmlJoystickPOVBinder->Attribute("deviceId")) - , FromString(xmlJoystickPOVBinder->Attribute("pov")), axis, dir); - - xmlJoystickPOVBinder = xmlJoystickPOVBinder->NextSiblingElement("JoystickPOVBinder"); - } - } - - void InputControlSystem::loadJoystickSliderBinders(TiXmlElement* xmlControlNode) - { - TiXmlElement* xmlJoystickSliderBinder = xmlControlNode->FirstChildElement("JoystickSliderBinder"); - while(xmlJoystickSliderBinder) - { - Control::ControlChangingDirection dir = Control::STOP; - if(std::string(xmlJoystickSliderBinder->Attribute("direction")) == "INCREASE") - { - dir = Control::INCREASE; - } - else if(std::string(xmlJoystickSliderBinder->Attribute("direction")) == "DECREASE") - { - dir = Control::DECREASE; - } - - addJoystickSliderBinding(mControls.back(), FromString(xmlJoystickSliderBinder->Attribute("deviceId")) - , FromString(xmlJoystickSliderBinder->Attribute("slider")), dir); - - xmlJoystickSliderBinder = xmlJoystickSliderBinder->NextSiblingElement("JoystickSliderBinder"); - } - } - // add bindings - void InputControlSystem::addJoystickAxisBinding(Control* control, int deviceId, int axis, Control::ControlChangingDirection direction) + void InputControlSystem::addJoystickAxisBinding(Control* control, int axis, Control::ControlChangingDirection direction) { - ICS_LOG("\tAdding AxisBinder [deviceid=" - + ToString(deviceId) + ", axis=" + ICS_LOG("\tAdding AxisBinder [axis=" + ToString(axis) + ", direction=" - + ToString(direction) + "]"); + + ToString(direction) + "]"); + + control->setValue(0.5f); //all joystick axis start at .5, so do that ControlAxisBinderItem controlAxisBinderItem; controlAxisBinderItem.control = control; controlAxisBinderItem.direction = direction; - mControlsJoystickAxisBinderMap[ deviceId ][ axis ] = controlAxisBinderItem; + mControlsJoystickAxisBinderMap[ axis ] = controlAxisBinderItem; } - void InputControlSystem::addJoystickButtonBinding(Control* control, int deviceId, unsigned int button, Control::ControlChangingDirection direction) + void InputControlSystem::addJoystickButtonBinding(Control* control, unsigned int button, Control::ControlChangingDirection direction) { - ICS_LOG("\tAdding JoystickButtonBinder [deviceId=" - + ToString(deviceId) + ", button=" + ICS_LOG("\tAdding JoystickButtonBinder [button=" + ToString(button) + ", direction=" + ToString(direction) + "]"); ControlButtonBinderItem controlJoystickButtonBinderItem; controlJoystickButtonBinderItem.direction = direction; controlJoystickButtonBinderItem.control = control; - mControlsJoystickButtonBinderMap[ deviceId ][ button ] = controlJoystickButtonBinderItem; - } - - void InputControlSystem::addJoystickPOVBinding(Control* control, int deviceId, int index, InputControlSystem::POVAxis axis, Control::ControlChangingDirection direction) - { - ICS_LOG("\tAdding JoystickPOVBinder [deviceId=" - + ToString(deviceId) + ", pov=" - + ToString(index) + ", axis=" - + ToString(axis) + ", direction=" - + ToString(direction) + "]"); - - ControlPOVBinderItem ControlPOVBinderItem; - ControlPOVBinderItem.direction = direction; - ControlPOVBinderItem.control = control; - mControlsJoystickPOVBinderMap[ deviceId ][ index ][ axis ] = ControlPOVBinderItem; - } - - void InputControlSystem::addJoystickSliderBinding(Control* control, int deviceId, int index, Control::ControlChangingDirection direction) - { - ICS_LOG("\tAdding JoystickSliderBinder [deviceId=" - + ToString(deviceId) + ", direction=" - + ToString(index) + ", direction=" - + ToString(direction) + "]"); - - ControlSliderBinderItem ControlSliderBinderItem; - ControlSliderBinderItem.direction = direction; - ControlSliderBinderItem.control = control; - mControlsJoystickSliderBinderMap[ deviceId ][ index ] = ControlSliderBinderItem; + mControlsJoystickButtonBinderMap[ button ] = controlJoystickButtonBinderItem; } // get bindings - int InputControlSystem::getJoystickAxisBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction) + int InputControlSystem::getJoystickAxisBinding(Control* control, ICS::Control::ControlChangingDirection direction) { - if(mControlsJoystickAxisBinderMap.find(deviceId) != mControlsJoystickAxisBinderMap.end()) - { - ControlsAxisBinderMapType::iterator it = mControlsJoystickAxisBinderMap[deviceId].begin(); - while(it != mControlsJoystickAxisBinderMap[deviceId].end()) - { - if(it->first >= 0 && it->second.control == control && it->second.direction == direction) - { - return it->first; - } - ++it; - } - } + ControlsAxisBinderMapType::iterator it = mControlsJoystickAxisBinderMap.begin(); + while(it != mControlsJoystickAxisBinderMap.end()) + { + if(it->first >= 0 && it->second.control == control && it->second.direction == direction) + { + return it->first; + } + ++it; + } return /*NamedAxis::*/UNASSIGNED; } - unsigned int InputControlSystem::getJoystickButtonBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction) + unsigned int InputControlSystem::getJoystickButtonBinding(Control* control, ICS::Control::ControlChangingDirection direction) { - if(mControlsJoystickButtonBinderMap.find(deviceId) != mControlsJoystickButtonBinderMap.end()) - { - ControlsButtonBinderMapType::iterator it = mControlsJoystickButtonBinderMap[deviceId].begin(); - while(it != mControlsJoystickButtonBinderMap[deviceId].end()) - { - if(it->second.control == control && it->second.direction == direction) - { - return it->first; - } - ++it; - } - } + ControlsButtonBinderMapType::iterator it = mControlsJoystickButtonBinderMap.begin(); + while(it != mControlsJoystickButtonBinderMap.end()) + { + if(it->second.control == control && it->second.direction == direction) + { + return it->first; + } + ++it; + } return ICS_MAX_DEVICE_BUTTONS; } - InputControlSystem::POVBindingPair InputControlSystem::getJoystickPOVBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction) - { - POVBindingPair result; - result.index = -1; - - if(mControlsJoystickPOVBinderMap.find(deviceId) != mControlsJoystickPOVBinderMap.end()) - { - //ControlsAxisBinderMapType::iterator it = mControlsJoystickPOVBinderMap[deviceId].begin(); - std::map::iterator it = mControlsJoystickPOVBinderMap[deviceId].begin(); - while(it != mControlsJoystickPOVBinderMap[deviceId].end()) - { - ControlsPOVBinderMapType::const_iterator it2 = it->second.begin(); - while(it2 != it->second.end()) - { - if(it2->second.control == control && it2->second.direction == direction) - { - result.index = it->first; - result.axis = (POVAxis)it2->first; - return result; - } - it2++; - } - - it++; - } - } - - return result; - } - - int InputControlSystem::getJoystickSliderBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction) - { - if(mControlsJoystickSliderBinderMap.find(deviceId) != mControlsJoystickSliderBinderMap.end()) - { - ControlsButtonBinderMapType::iterator it = mControlsJoystickSliderBinderMap[deviceId].begin(); - while(it != mControlsJoystickSliderBinderMap[deviceId].end()) - { - if(it->second.control == control && it->second.direction == direction) - { - return it->first; - } - it++; - } - } - - return /*NamedAxis::*/UNASSIGNED; - } - // remove bindings - void InputControlSystem::removeJoystickAxisBinding(int deviceId, int axis) + void InputControlSystem::removeJoystickAxisBinding(int axis) { - if(mControlsJoystickAxisBinderMap.find(deviceId) != mControlsJoystickAxisBinderMap.end()) - { - ControlsButtonBinderMapType::iterator it = mControlsJoystickAxisBinderMap[deviceId].find(axis); - if(it != mControlsJoystickAxisBinderMap[deviceId].end()) - { - mControlsJoystickAxisBinderMap[deviceId].erase(it); - } - } + ControlsButtonBinderMapType::iterator it = mControlsJoystickAxisBinderMap.find(axis); + if(it != mControlsJoystickAxisBinderMap.end()) + { + mControlsJoystickAxisBinderMap.erase(it); + } } - void InputControlSystem::removeJoystickButtonBinding(int deviceId, unsigned int button) + void InputControlSystem::removeJoystickButtonBinding(unsigned int button) { - if(mControlsJoystickButtonBinderMap.find(deviceId) != mControlsJoystickButtonBinderMap.end()) - { - ControlsButtonBinderMapType::iterator it = mControlsJoystickButtonBinderMap[deviceId].find(button); - if(it != mControlsJoystickButtonBinderMap[deviceId].end()) - { - mControlsJoystickButtonBinderMap[deviceId].erase(it); - } - } - } - - void InputControlSystem::removeJoystickPOVBinding(int deviceId, int index, POVAxis axis) - { - if(mControlsJoystickPOVBinderMap.find(deviceId) != mControlsJoystickPOVBinderMap.end()) - { - std::map::iterator it = mControlsJoystickPOVBinderMap[deviceId].find(index); - if(it != mControlsJoystickPOVBinderMap[deviceId].end()) - { - if(it->second.find(axis) != it->second.end()) - { - mControlsJoystickPOVBinderMap[deviceId].find(index)->second.erase( it->second.find(axis) ); - } - } - } - } - - void InputControlSystem::removeJoystickSliderBinding(int deviceId, int index) - { - if(mControlsJoystickSliderBinderMap.find(deviceId) != mControlsJoystickSliderBinderMap.end()) - { - ControlsButtonBinderMapType::iterator it = mControlsJoystickSliderBinderMap[deviceId].find(index); - if(it != mControlsJoystickSliderBinderMap[deviceId].end()) - { - mControlsJoystickSliderBinderMap[deviceId].erase(it); - } - } + ControlsButtonBinderMapType::iterator it = mControlsJoystickButtonBinderMap.find(button); + if(it != mControlsJoystickButtonBinderMap.end()) + { + mControlsJoystickButtonBinderMap.erase(it); + } } // joyStick listeners - void InputControlSystem::buttonPressed(const SDL_JoyButtonEvent &evt, int button) + void InputControlSystem::buttonPressed(const SDL_ControllerButtonEvent &evt) { - if(mActive) + if(mActive) { if(!mDetectingBindingControl) { - if(mControlsJoystickButtonBinderMap.find(evt.which) != mControlsJoystickButtonBinderMap.end()) - { - ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap[evt.which].find(button); - if(it != mControlsJoystickButtonBinderMap[evt.which].end()) - { - it->second.control->setIgnoreAutoReverse(false); - if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop()) - { - it->second.control->setChangingDirection(it->second.direction); - } - else - { - if(it->second.control->getValue() == 1) - { - it->second.control->setChangingDirection(Control::DECREASE); - } - else if(it->second.control->getValue() == 0) - { - it->second.control->setChangingDirection(Control::INCREASE); - } - } - } - } + ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap.find(evt.button); + if(it != mControlsJoystickButtonBinderMap.end()) + { + it->second.control->setIgnoreAutoReverse(false); + if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop()) + { + it->second.control->setChangingDirection(it->second.direction); + } + else + { + if(it->second.control->getValue() == 1) + { + it->second.control->setChangingDirection(Control::DECREASE); + } + else if(it->second.control->getValue() == 0) + { + it->second.control->setChangingDirection(Control::INCREASE); + } + } + } } else if(mDetectingBindingListener) { mDetectingBindingListener->joystickButtonBindingDetected(this, - mDetectingBindingControl, evt.which, button, mDetectingBindingDirection); + mDetectingBindingControl, evt.button, mDetectingBindingDirection); } } } - void InputControlSystem::buttonReleased(const SDL_JoyButtonEvent &evt, int button) + void InputControlSystem::buttonReleased(const SDL_ControllerButtonEvent &evt) { if(mActive) { - if(mControlsJoystickButtonBinderMap.find(evt.which) != mControlsJoystickButtonBinderMap.end()) - { - ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap[evt.which].find(button); - if(it != mControlsJoystickButtonBinderMap[evt.which].end()) - { - it->second.control->setChangingDirection(Control::STOP); - } - } + ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap.find(evt.button); + if(it != mControlsJoystickButtonBinderMap.end()) + { + it->second.control->setChangingDirection(Control::STOP); + } } } - void InputControlSystem::axisMoved(const SDL_JoyAxisEvent &evt, int axis) + void InputControlSystem::axisMoved(const SDL_ControllerAxisEvent &evt) { if(mActive) { if(!mDetectingBindingControl) { - if(mControlsJoystickAxisBinderMap.find(evt.which) != mControlsJoystickAxisBinderMap.end()) - { - ControlAxisBinderItem joystickBinderItem = mControlsJoystickAxisBinderMap[ evt.which ][ axis ]; // joystic axis start at 0 index - Control* ctrl = joystickBinderItem.control; - if(ctrl) - { - ctrl->setIgnoreAutoReverse(true); - - float axisRange = SDL_JOY_AXIS_MAX - SDL_JOY_AXIS_MIN; - float valDisplaced = (float)(evt.value - SDL_JOY_AXIS_MIN); - - if(joystickBinderItem.direction == Control::INCREASE) - { - ctrl->setValue( valDisplaced / axisRange ); - } - else if(joystickBinderItem.direction == Control::DECREASE) - { - ctrl->setValue( 1 - ( valDisplaced / axisRange ) ); - } - } - } + ControlAxisBinderItem joystickBinderItem = mControlsJoystickAxisBinderMap[evt.axis]; // joystic axis start at 0 index + Control* ctrl = joystickBinderItem.control; + if(ctrl) + { + ctrl->setIgnoreAutoReverse(true); + + float axisRange = SDL_JOY_AXIS_MAX - SDL_JOY_AXIS_MIN; + float valDisplaced = (float)(evt.value - SDL_JOY_AXIS_MIN); + float percent = valDisplaced / axisRange * (1+DEADZONE*2) - DEADZONE; //Assures all values, 0 through 1, are seen + if(percent > .5-DEADZONE && percent < .5+DEADZONE) //close enough to center + percent = .5; + else if(percent > .5) + percent -= DEADZONE; + else + percent += DEADZONE; + + if(joystickBinderItem.direction == Control::INCREASE) + { + ctrl->setValue( percent ); + } + else if(joystickBinderItem.direction == Control::DECREASE) + { + ctrl->setValue( 1 - ( percent ) ); + } + } } else if(mDetectingBindingListener) { @@ -409,249 +242,74 @@ namespace ICS if( abs( evt.value ) > ICS_JOYSTICK_AXIS_BINDING_MARGIN) { mDetectingBindingListener->joystickAxisBindingDetected(this, - mDetectingBindingControl, evt.which, axis, mDetectingBindingDirection); + mDetectingBindingControl, evt.axis, mDetectingBindingDirection); } } } } - } - - //Here be dragons, apparently - void InputControlSystem::povMoved(const SDL_JoyHatEvent &evt, int index) + } + + void InputControlSystem::controllerAdded(const SDL_ControllerDeviceEvent &args) { - if(mActive) - { - if(!mDetectingBindingControl) - { - if(mControlsJoystickPOVBinderMap.find(evt.which) != mControlsJoystickPOVBinderMap.end()) - { - std::map::const_iterator i = mControlsJoystickPOVBinderMap[ evt.which ].find(index); - if(i != mControlsJoystickPOVBinderMap[ evt.which ].end()) - { - if(evt.value != SDL_HAT_LEFT - && evt.value != SDL_HAT_RIGHT - && evt.value != SDL_HAT_CENTERED) - { - ControlsPOVBinderMapType::const_iterator it = i->second.find( /*POVAxis::*/NorthSouth ); - if(it != i->second.end()) - { - it->second.control->setIgnoreAutoReverse(false); - if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop()) - { - if(evt.value == SDL_HAT_UP - || evt.value == SDL_HAT_LEFTUP - || evt.value == SDL_HAT_RIGHTUP) - { - it->second.control->setChangingDirection(it->second.direction); - } - else - { - it->second.control->setChangingDirection((Control::ControlChangingDirection)(-1 * it->second.direction)); - } - } - else - { - if(it->second.control->getValue() == 1) - { - it->second.control->setChangingDirection(Control::DECREASE); - } - else if(it->second.control->getValue() == 0) - { - it->second.control->setChangingDirection(Control::INCREASE); - } - } - } - } - - if(evt.value != SDL_HAT_UP - && evt.value != SDL_HAT_DOWN - && evt.value != SDL_HAT_CENTERED) - { - ControlsPOVBinderMapType::const_iterator it = i->second.find( /*POVAxis::*/EastWest ); - if(it != i->second.end()) - { - it->second.control->setIgnoreAutoReverse(false); - if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop()) - { - if(evt.value == SDL_HAT_RIGHT - || evt.value == SDL_HAT_RIGHTUP - || evt.value == SDL_HAT_RIGHTDOWN) - { - it->second.control->setChangingDirection(it->second.direction); - } - else - { - it->second.control->setChangingDirection((Control::ControlChangingDirection)(-1 * it->second.direction)); - } - } - else - { - if(it->second.control->getValue() == 1) - { - it->second.control->setChangingDirection(Control::DECREASE); - } - else if(it->second.control->getValue() == 0) - { - it->second.control->setChangingDirection(Control::INCREASE); - } - } - } - } - - if(evt.value == SDL_HAT_CENTERED) - { - ControlsPOVBinderMapType::const_iterator it = i->second.find( /*POVAxis::*/NorthSouth ); - if(it != i->second.end()) - { - it->second.control->setChangingDirection(Control::STOP); - } - - it = i->second.find( /*POVAxis::*/EastWest ); - if(it != i->second.end()) - { - it->second.control->setChangingDirection(Control::STOP); - } - } - } - } - } - else if(mDetectingBindingListener) - { - if(mDetectingBindingControl && mDetectingBindingControl->isAxisBindable()) - { - if(evt.value == SDL_HAT_LEFT - || evt.value == SDL_HAT_RIGHT - || evt.value == SDL_HAT_UP - || evt.value == SDL_HAT_DOWN) - { - POVAxis povAxis = NorthSouth; - if(evt.value == SDL_HAT_LEFT - || evt.value == SDL_HAT_RIGHT) - { - povAxis = EastWest; - } - - mDetectingBindingListener->joystickPOVBindingDetected(this, - mDetectingBindingControl, evt.which, index, povAxis, mDetectingBindingDirection); - } - } - } - } + ICS_LOG("Adding joystick (index: " + ToString(args.which) + ")"); + SDL_GameController* cntrl = SDL_GameControllerOpen(args.which); + int instanceID = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(cntrl)); + if(mJoystickIDList.empty()) // + { + for(int j = 0 ; j < ICS_MAX_JOYSTICK_AXIS ; j++) + { + if(mControlsJoystickAxisBinderMap.find(j) == mControlsJoystickAxisBinderMap.end()) + { + ControlAxisBinderItem controlJoystickBinderItem; + controlJoystickBinderItem.direction = Control::STOP; + controlJoystickBinderItem.control = NULL; + mControlsJoystickAxisBinderMap[j] = controlJoystickBinderItem; + } + } + } + + mJoystickIDList[instanceID] = cntrl; + } + void InputControlSystem::controllerRemoved(const SDL_ControllerDeviceEvent &args) + { + ICS_LOG("Removing joystick (instance id: " + ToString(args.which) + ")"); + if(mJoystickIDList.count(args.which)!=0) + { + SDL_GameControllerClose(mJoystickIDList.at(args.which)); + mJoystickIDList.erase(args.which); + } } - //TODO: does this have an SDL equivalent? - /* - void InputControlSystem::sliderMoved(const OIS::JoyStickEvent &evt, int index) - { - if(mActive) - { - if(!mDetectingBindingControl) - { - if(mControlsJoystickSliderBinderMap.find(evt.device->getID()) != mControlsJoystickSliderBinderMap.end()) - { - ControlSliderBinderItem joystickBinderItem = mControlsJoystickSliderBinderMap[ evt.device->getID() ][ index ]; - Control* ctrl = joystickBinderItem.control; - if(ctrl) - { - ctrl->setIgnoreAutoReverse(true); - if(joystickBinderItem.direction == Control::INCREASE) - { - float axisRange = OIS::JoyStick::MAX_AXIS - OIS::JoyStick::MIN_AXIS; - float valDisplaced = (float)( evt.state.mSliders[index].abX - OIS::JoyStick::MIN_AXIS); - - ctrl->setValue( valDisplaced / axisRange ); - } - else if(joystickBinderItem.direction == Control::DECREASE) - { - float axisRange = OIS::JoyStick::MAX_AXIS - OIS::JoyStick::MIN_AXIS; - float valDisplaced = (float)(evt.state.mSliders[index].abX - OIS::JoyStick::MIN_AXIS); - - ctrl->setValue( 1 - ( valDisplaced / axisRange ) ); - } - } - } - } - else if(mDetectingBindingListener) - { - if(mDetectingBindingControl && mDetectingBindingControl->isAxisBindable()) - { - if( abs( evt.state.mSliders[index].abX ) > ICS_JOYSTICK_SLIDER_BINDING_MARGIN) - { - mDetectingBindingListener->joystickSliderBindingDetected(this, - mDetectingBindingControl, evt.device->getID(), index, mDetectingBindingDirection); - } - } - } - } - } - */ - // joystick auto bindings - void DetectingBindingListener::joystickAxisBindingDetected(InputControlSystem* ICS, Control* control - , int deviceId, int axis, Control::ControlChangingDirection direction) + void DetectingBindingListener::joystickAxisBindingDetected(InputControlSystem* ICS, Control* control, int axis, Control::ControlChangingDirection direction) { // if the joystick axis is used by another control, remove it - ICS->removeJoystickAxisBinding(deviceId, axis); + ICS->removeJoystickAxisBinding(axis); // if the control has an axis assigned, remove it - int oldAxis = ICS->getJoystickAxisBinding(control, deviceId, direction); - if(oldAxis != InputControlSystem::UNASSIGNED) + int oldAxis = ICS->getJoystickAxisBinding(control, direction); + if(oldAxis != InputControlSystem::UNASSIGNED) { - ICS->removeJoystickAxisBinding(deviceId, oldAxis); + ICS->removeJoystickAxisBinding(oldAxis); } - ICS->addJoystickAxisBinding(control, deviceId, axis, direction); + ICS->addJoystickAxisBinding(control, axis, direction); ICS->cancelDetectingBindingState(); } void DetectingBindingListener::joystickButtonBindingDetected(InputControlSystem* ICS, Control* control - , int deviceId, unsigned int button, Control::ControlChangingDirection direction) + , unsigned int button, Control::ControlChangingDirection direction) { // if the joystick button is used by another control, remove it - ICS->removeJoystickButtonBinding(deviceId, button); + ICS->removeJoystickButtonBinding(button); // if the control has a joystick button assigned, remove it - unsigned int oldButton = ICS->getJoystickButtonBinding(control, deviceId, direction); + unsigned int oldButton = ICS->getJoystickButtonBinding(control, direction); if(oldButton != ICS_MAX_DEVICE_BUTTONS) { - ICS->removeJoystickButtonBinding(deviceId, oldButton); - } - - ICS->addJoystickButtonBinding(control, deviceId, button, direction); - ICS->cancelDetectingBindingState(); - } - - - void DetectingBindingListener::joystickPOVBindingDetected(InputControlSystem* ICS, Control* control - , int deviceId, int pov, InputControlSystem::POVAxis axis, Control::ControlChangingDirection direction) - { - // if the joystick slider is used by another control, remove it - ICS->removeJoystickPOVBinding(deviceId, pov, axis); - - // if the control has a joystick button assigned, remove it - ICS::InputControlSystem::POVBindingPair oldPOV = ICS->getJoystickPOVBinding(control, deviceId, direction); - if(oldPOV.index >= 0 && oldPOV.axis == axis) - { - ICS->removeJoystickPOVBinding(deviceId, oldPOV.index, oldPOV.axis); - } - - ICS->addJoystickPOVBinding(control, deviceId, pov, axis, direction); - ICS->cancelDetectingBindingState(); - } - - void DetectingBindingListener::joystickSliderBindingDetected(InputControlSystem* ICS, Control* control - , int deviceId, int slider, Control::ControlChangingDirection direction) - { - // if the joystick slider is used by another control, remove it - ICS->removeJoystickSliderBinding(deviceId, slider); - - // if the control has a joystick slider assigned, remove it - int oldSlider = ICS->getJoystickSliderBinding(control, deviceId, direction); - if(oldSlider != InputControlSystem::/*NamedAxis::*/UNASSIGNED) - { - ICS->removeJoystickSliderBinding(deviceId, oldSlider); + ICS->removeJoystickButtonBinding(oldButton); } - ICS->addJoystickSliderBinding(control, deviceId, slider, direction); + ICS->addJoystickButtonBinding(control, button, direction); ICS->cancelDetectingBindingState(); } } diff --git a/extern/sdl4ogre/events.h b/extern/sdl4ogre/events.h index 0fb4d6f06..ebabb4cbb 100644 --- a/extern/sdl4ogre/events.h +++ b/extern/sdl4ogre/events.h @@ -40,23 +40,25 @@ public: virtual void keyReleased(const SDL_KeyboardEvent &arg) = 0; }; -class JoyListener +class ControllerListener { public: - virtual ~JoyListener() {} + virtual ~ControllerListener() {} /** @remarks Joystick button down event */ - virtual void buttonPressed( const SDL_JoyButtonEvent &evt, int button ) = 0; + virtual void buttonPressed( const SDL_ControllerButtonEvent &evt) = 0; /** @remarks Joystick button up event */ - virtual void buttonReleased( const SDL_JoyButtonEvent &evt, int button ) = 0; + virtual void buttonReleased( const SDL_ControllerButtonEvent &evt) = 0; /** @remarks Joystick axis moved event */ - virtual void axisMoved( const SDL_JoyAxisEvent &arg, int axis ) = 0; + virtual void axisMoved( const SDL_ControllerAxisEvent &arg) = 0; - //-- Not so common control events, so are not required --// + /** @remarks Joystick Added **/ + virtual void controllerAdded( const SDL_ControllerDeviceEvent &arg) = 0; + + /** @remarks Joystick Removed **/ + virtual void controllerRemoved( const SDL_ControllerDeviceEvent &arg) = 0; - //! Joystick Event, and povID - virtual void povMoved( const SDL_JoyHatEvent &arg, int index) {} }; class WindowListener diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index db46a4af9..f211811cc 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -20,7 +20,7 @@ namespace SFO mMouseY(0), mMouseX(0), mMouseInWindow(true), - mJoyListener(NULL), + mConListener(NULL), mKeyboardListener(NULL), mMouseListener(NULL), mWindowListener(NULL), @@ -88,24 +88,32 @@ namespace SFO case SDL_TEXTINPUT: mKeyboardListener->textInput(evt.text); break; + case SDL_JOYHATMOTION: //As we manage everything with GameController, don't even bother with these. case SDL_JOYAXISMOTION: - if (mJoyListener) - mJoyListener->axisMoved(evt.jaxis, evt.jaxis.axis); - break; case SDL_JOYBUTTONDOWN: - if (mJoyListener) - mJoyListener->buttonPressed(evt.jbutton, evt.jbutton.button); - break; case SDL_JOYBUTTONUP: - if (mJoyListener) - mJoyListener->buttonReleased(evt.jbutton, evt.jbutton.button); - break; case SDL_JOYDEVICEADDED: - //SDL_JoystickOpen(evt.jdevice.which); - //std::cout << "Detected a new joystick: " << SDL_JoystickNameForIndex(evt.jdevice.which) << std::endl; - break; case SDL_JOYDEVICEREMOVED: - //std::cout << "A joystick has been removed" << std::endl; + break; + case SDL_CONTROLLERDEVICEADDED: + if(mConListener) + mConListener->controllerAdded(evt.cdevice); + break; + case SDL_CONTROLLERDEVICEREMOVED: + if(mConListener) + mConListener->controllerRemoved(evt.cdevice); + break; + case SDL_CONTROLLERBUTTONDOWN: + if(mConListener) + mConListener->buttonPressed(evt.cbutton); + break; + case SDL_CONTROLLERBUTTONUP: + if(mConListener) + mConListener->buttonReleased(evt.cbutton); + break; + case SDL_CONTROLLERAXISMOTION: + if(mConListener) + mConListener->axisMoved(evt.caxis); break; case SDL_WINDOWEVENT: handleWindowEvent(evt); diff --git a/extern/sdl4ogre/sdlinputwrapper.hpp b/extern/sdl4ogre/sdlinputwrapper.hpp index 339e99de1..efc71f1a1 100644 --- a/extern/sdl4ogre/sdlinputwrapper.hpp +++ b/extern/sdl4ogre/sdlinputwrapper.hpp @@ -24,7 +24,7 @@ namespace SFO void setMouseEventCallback(MouseListener* listen) { mMouseListener = listen; } void setKeyboardEventCallback(KeyListener* listen) { mKeyboardListener = listen; } void setWindowEventCallback(WindowListener* listen) { mWindowListener = listen; } - void setJoyEventCallback(JoyListener* listen) { mJoyListener = listen; } + void setControllerEventCallback(ControllerListener* listen) { mConListener = listen; } void capture(bool windowEventsOnly); bool isModifierHeld(SDL_Keymod mod); @@ -54,7 +54,7 @@ namespace SFO SFO::MouseListener* mMouseListener; SFO::KeyListener* mKeyboardListener; SFO::WindowListener* mWindowListener; - SFO::JoyListener* mJoyListener; + SFO::ControllerListener* mConListener; typedef boost::unordered_map KeyMap; KeyMap mKeyMap; diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt index 9b2325744..b7417a51d 100644 --- a/files/CMakeLists.txt +++ b/files/CMakeLists.txt @@ -52,3 +52,5 @@ set(MATERIAL_FILES copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/water "${OpenMW_BINARY_DIR}/resources/water/" "${WATER_FILES}") copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/materials "${OpenMW_BINARY_DIR}/resources/materials/" "${MATERIAL_FILES}") + +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/gamecontrollerdb.txt ${OpenMW_BINARY_DIR}/resources/) diff --git a/files/gamecontrollerdb.txt b/files/gamecontrollerdb.txt new file mode 100644 index 000000000..9ad8778a0 --- /dev/null +++ b/files/gamecontrollerdb.txt @@ -0,0 +1,75 @@ +# Windows - DINPUT +8f0e1200000000000000504944564944,Acme,platform:Windows,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +341a3608000000000000504944564944,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +ffff0000000000000000504944564944,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +6d0416c2000000000000504944564944,Generic DirectInput Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +6d0419c2000000000000504944564944,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +88880803000000000000504944564944,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows, +4c056802000000000000504944564944,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows, +25090500000000000000504944564944,PS3 DualShock,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows, +4c05c405000000000000504944564944,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +xinput,X360 Controller,a:b10,b:b11,back:b5,dpdown:b1,dpleft:b2,dpright:b3,dpup:b0,guide:b14,leftshoulder:b8,leftstick:b6,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b7,righttrigger:a5,rightx:a2,righty:a3,start:b4,x:b12,y:b13,platform:Windows, +6d0418c2000000000000504944564944,Logitech RumblePad 2 USB,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, +36280100000000000000504944564944,OUYA Controller,platform:Windows,a:b0,b:b3,y:b2,x:b1,start:b14,guide:b15,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b8,dpleft:b10,dpdown:b9,dpright:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b12,righttrigger:b13, +4f0400b3000000000000504944564944,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Windows, +00f00300000000000000504944564944,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows, +00f0f100000000000000504944564944,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows, +28040140000000000000504944564944,GamePad Pro USB,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7, +ff113133000000000000504944564944,SVEN X-PAD,platform:Windows,a:b2,b:b3,y:b1,x:b0,start:b5,back:b4,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b8,righttrigger:b9, + +# OS X +0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, +6d0400000000000016c2000000000000,Logitech F310 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +6d0400000000000018c2000000000000,Logitech F510 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +6d040000000000001fc2000000000000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +6d0400000000000019c2000000000000,Logitech Wireless Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +4c050000000000006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X, +4c05000000000000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,Platform:Mac OS X, +5e040000000000008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +891600000000000000fd000000000000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b8,guide:b10,back:b9,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b11,dpleft:b13,dpdown:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Mac OS X, +4f0400000000000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Mac OS X, + +# Linux +0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, +030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d0400001dc2000014400000,Logitech F310 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux, +030000004c050000c405000011010000,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Linux, +03000000de280000ff11000001000000,Valve Streaming Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000014010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000010010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000100800000100000010010000,Twin USB PS2 Adapter,a:b2,b:b1,y:b0,x:b3,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,platform:Linux, +03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Linux, +030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,y:b3,x:b1,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux, +030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5, +030000008f0e00000300000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +030000008f0e00001200000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux, +030000006d04000016c2000010010000,Logitech Logitech Dual Action,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, +03000000260900008888000000010000,GameCube {WiseGroup USB box},a:b0,b:b2,y:b3,x:b1,start:b7,leftshoulder:,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,rightstick:,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Linux, +030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,y:b4,x:b3,start:b8,guide:b5,back:b2,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b9,righttrigger:b10,platform:Linux, +030000006d04000018c2000010010000,Logitech Logitech RumblePad 2 USB,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, +05000000d6200000ad0d000001000000,Moga Pro,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b6,leftstick:b7,rightstick:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4, +030000004f04000009d0000000010000,Thrustmaster Run N Drive Wireless PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, +030000004f04000008d0000000010000,Thrustmaster Run N Drive Wireless,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7, +0300000000f000000300000000010000,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux, +0300000000f00000f100000000010000,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux, +030000006f0e00001f01000000010000,Generic X-Box pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4, +03000000280400000140000000010000,Gravis GamePad Pro USB ,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftx:a0,lefty:a1, +030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:a2,rightshoulder:b2,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4, +030000006f0e00001e01000011010000,Rock Candy Gamepad for PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,guide:b12,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2, +03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,platform:Linux,a:b2,b:b1,y:b0,x:b3,start:b8,back:b9,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5, +030000008916000000fd000024010000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux, +030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux, +03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux, +050000004c050000c405000000010000,PS4 Controller (Bluetooth),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +060000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux, +03000000790000000600000010010000,DragonRise Inc. Generic USB Joystick ,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4, +03000000666600000488000000010000,Super Joy Box 5 Pro,platform:Linux,a:b2,b:b1,x:b3,y:b0,back:b9,start:b8,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,dpup:b12,dpleft:b15,dpdown:b14,dpright:b13, +05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2, +05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2, From 073a2f067417b4d4c1ceb3f802198f1111647608 Mon Sep 17 00:00:00 2001 From: Digmaster Date: Tue, 9 Dec 2014 00:02:18 -0600 Subject: [PATCH 081/740] Fixed issue with walking --- apps/openmw/mwinput/inputmanagerimp.cpp | 2 +- files/CMakeLists.txt | 6 ++++- files/mygui/openmw_settings_window.layout | 28 ++++++++++++++--------- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index a25bb727c..2cb9075bd 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -1047,7 +1047,7 @@ namespace MWInput bool InputManager::actionIsActive (int id) { - return (mInputBinder->getChannel (id)->getValue ()!=0.0); + return (mInputBinder->getChannel (id)->getValue ()==1.0); } void InputManager::loadKeyDefaults (bool force) diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt index b7417a51d..4635cbfa4 100644 --- a/files/CMakeLists.txt +++ b/files/CMakeLists.txt @@ -49,8 +49,12 @@ set(MATERIAL_FILES mygui.shaderset ) +set(ETC_FILES + gamecontrollerdb.txt +) + copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/water "${OpenMW_BINARY_DIR}/resources/water/" "${WATER_FILES}") copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/materials "${OpenMW_BINARY_DIR}/resources/materials/" "${MATERIAL_FILES}") -file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/gamecontrollerdb.txt ${OpenMW_BINARY_DIR}/resources/) +copy_all_files(${CMAKE_CURRENT_SOURCE_DIR} "${OpenMW_BINARY_DIR}/resources/" "${ETC_FILES}") diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index fd84be3e9..11751b7ec 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -1,10 +1,10 @@  - + - + - + @@ -172,15 +172,21 @@ - + + + + + + + - + - + @@ -190,10 +196,10 @@ - + - + @@ -203,11 +209,11 @@ - + - + @@ -460,7 +466,7 @@ - + From ad54e095934d0660308c8e9fe21aa9c6d9b916af Mon Sep 17 00:00:00 2001 From: Digmaster Date: Tue, 9 Dec 2014 11:16:17 -0600 Subject: [PATCH 082/740] Inital value for joysticks is 0.5 --- apps/openmw/mwinput/inputmanagerimp.cpp | 16 ++++++++++++++-- extern/oics/ICSControl.h | 7 ++++--- extern/oics/ICSInputControlSystem.cpp | 2 ++ 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 2cb9075bd..633ae10d4 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -1120,11 +1120,13 @@ namespace MWInput if (defaultKeyBindings.find(i) != defaultKeyBindings.end() && !mInputBinder->isKeyBound(defaultKeyBindings[i])) { + control->setInitialValue(0.0f); mInputBinder->addKeyBinding(control, defaultKeyBindings[i], ICS::Control::INCREASE); } else if (defaultMouseButtonBindings.find(i) != defaultMouseButtonBindings.end() && !mInputBinder->isMouseButtonBound(defaultMouseButtonBindings[i])) { + control->setInitialValue(0.0f); mInputBinder->addMouseButtonBinding (control, defaultMouseButtonBindings[i], ICS::Control::INCREASE); } } @@ -1167,7 +1169,11 @@ namespace MWInput bool controlExists = mInputBinder->getChannel(i)->getControlsCount () != 0; if (!controlExists) { - control = new ICS::Control(boost::lexical_cast(i), false, true, 0, ICS::ICS_MAX, ICS::ICS_MAX); + int inital; + if (defaultButtonBindings.find(i) != defaultButtonBindings.end()) + inital = 0.0f; + else inital = 0.5f; + control = new ICS::Control(boost::lexical_cast(i), false, true, inital, ICS::ICS_MAX, ICS::ICS_MAX); mInputBinder->addControl(control); control->attachChannel(mInputBinder->getChannel(i), ICS::Channel::DIRECT); } @@ -1182,11 +1188,13 @@ namespace MWInput if (defaultButtonBindings.find(i) != defaultButtonBindings.end()) { - control->setValue(0.5f); + control->setInitialValue(0.0f); mInputBinder->addJoystickButtonBinding(control, defaultButtonBindings[i], ICS::Control::INCREASE); } else if (defaultAxisBindings.find(i) != defaultAxisBindings.end()) { + control->setValue(0.5f); + control->setInitialValue(0.5f); mInputBinder->addJoystickAxisBinding(control, defaultAxisBindings[i], ICS::Control::INCREASE); } } @@ -1426,6 +1434,7 @@ namespace MWInput return; clearAllKeyBindings(control); + control->setInitialValue(0.0f); ICS::DetectingBindingListener::keyBindingDetected (ICS, control, key, direction); MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); } @@ -1436,6 +1445,7 @@ namespace MWInput if(!mDetectingKeyboard) return; clearAllKeyBindings(control); + control->setInitialValue(0.0f); ICS::DetectingBindingListener::mouseButtonBindingDetected (ICS, control, button, direction); MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); } @@ -1451,6 +1461,7 @@ namespace MWInput clearAllControllerBindings(control); control->setValue(0.5f); //axis bindings must start at 0.5 + control->setInitialValue(0.5f); ICS::DetectingBindingListener::joystickAxisBindingDetected (ICS, control, axis, direction); MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); } @@ -1461,6 +1472,7 @@ namespace MWInput if(mDetectingKeyboard) return; clearAllControllerBindings(control); + control->setInitialValue(0.0f); ICS::DetectingBindingListener::joystickButtonBindingDetected (ICS, control, button, direction); MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); } diff --git a/extern/oics/ICSControl.h b/extern/oics/ICSControl.h index ebf75a3fe..1ed437652 100644 --- a/extern/oics/ICSControl.h +++ b/extern/oics/ICSControl.h @@ -34,7 +34,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. namespace ICS { - + class DllExport Control { public: @@ -52,9 +52,10 @@ namespace ICS void setValue(float value); inline float getValue(){ return mValue; }; - inline float getInitialValue(){ return mInitialValue; }; + inline float getInitialValue(){ return mInitialValue; }; + inline void setInitialValue(float i) {mInitialValue = i;}; - void attachChannel(Channel* channel, Channel::ChannelDirection direction, float percentage = 1.0); + void attachChannel(Channel* channel, Channel::ChannelDirection direction, float percentage = 1.0); std::list getAttachedChannels(){ return mAttachedChannels; }; inline float getStepSize(){ return mStepSize; }; diff --git a/extern/oics/ICSInputControlSystem.cpp b/extern/oics/ICSInputControlSystem.cpp index 4237060bb..3c719151b 100644 --- a/extern/oics/ICSInputControlSystem.cpp +++ b/extern/oics/ICSInputControlSystem.cpp @@ -278,6 +278,7 @@ namespace ICS /* Joystick Init */ //Load controller mappings +#if SDL_VERSION_ATLEAST(2,0,2) int res = SDL_GameControllerAddMappingsFromFile("resources/gamecontrollerdb.txt"); if(res == -1) { @@ -287,6 +288,7 @@ namespace ICS { ICS_LOG(std::string("Loaded ")+boost::lexical_cast(res)+" Game controller bindings"); } +#endif //Open all presently connected sticks int numSticks = SDL_NumJoysticks(); From a7a211860aa691c0169fdd8c6ba44a997d5478d7 Mon Sep 17 00:00:00 2001 From: Digmaster Date: Tue, 9 Dec 2014 12:12:38 -0600 Subject: [PATCH 083/740] Fixed binding controls to A on joystick --- apps/openmw/mwinput/inputmanagerimp.cpp | 13 +++++++---- .../oics/ICSInputControlSystem_joystick.cpp | 23 +++++++++++-------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 633ae10d4..2dbbea662 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -740,13 +740,16 @@ namespace MWInput if (arg.button == SDL_CONTROLLER_BUTTON_A || arg.button == SDL_CONTROLLER_BUTTON_B) // We'll pretend that A is left click and B is right click { guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); - guiMode = MyGUI::InputManager::getInstance().injectMousePress(mMouseX, mMouseY, sdlButtonToMyGUI((arg.button == SDL_CONTROLLER_BUTTON_B) ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT)) && guiMode; - if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0) + if(!mInputBinder->detectingBindingState()) { - MyGUI::Button* b = MyGUI::InputManager::getInstance ().getMouseFocusWidget ()->castType(false); - if (b && b->getEnabled()) + guiMode = MyGUI::InputManager::getInstance().injectMousePress(mMouseX, mMouseY, sdlButtonToMyGUI((arg.button == SDL_CONTROLLER_BUTTON_B) ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT)) && guiMode; + if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0) { - MWBase::Environment::get().getSoundManager ()->playSound ("Menu Click", 1.f, 1.f); + MyGUI::Button* b = MyGUI::InputManager::getInstance ().getMouseFocusWidget ()->castType(false); + if (b && b->getEnabled()) + { + MWBase::Environment::get().getSoundManager ()->playSound ("Menu Click", 1.f, 1.f); + } } } } diff --git a/extern/oics/ICSInputControlSystem_joystick.cpp b/extern/oics/ICSInputControlSystem_joystick.cpp index 9cd9b1461..d8dbfa112 100644 --- a/extern/oics/ICSInputControlSystem_joystick.cpp +++ b/extern/oics/ICSInputControlSystem_joystick.cpp @@ -180,23 +180,26 @@ namespace ICS } } } - else if(mDetectingBindingListener) - { - mDetectingBindingListener->joystickButtonBindingDetected(this, - mDetectingBindingControl, evt.button, mDetectingBindingDirection); - } } } void InputControlSystem::buttonReleased(const SDL_ControllerButtonEvent &evt) { if(mActive) - { - ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap.find(evt.button); - if(it != mControlsJoystickButtonBinderMap.end()) + { + if(!mDetectingBindingControl) { - it->second.control->setChangingDirection(Control::STOP); - } + ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap.find(evt.button); + if(it != mControlsJoystickButtonBinderMap.end()) + { + it->second.control->setChangingDirection(Control::STOP); + } + } + else if(mDetectingBindingListener) + { + mDetectingBindingListener->joystickButtonBindingDetected(this, + mDetectingBindingControl, evt.button, mDetectingBindingDirection); + } } } From bb6ed06a4eacf1dc0c3fa852eb9cec70e138cc11 Mon Sep 17 00:00:00 2001 From: Digmaster Date: Tue, 9 Dec 2014 14:37:32 -0600 Subject: [PATCH 084/740] read gamecontrollerdb file location from settings file --- apps/openmw/mwinput/inputmanagerimp.cpp | 4 ++-- extern/oics/ICSInputControlSystem.cpp | 21 ++++++++++++--------- extern/oics/ICSInputControlSystem.h | 3 ++- files/settings-default.cfg | 2 ++ 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 2dbbea662..3d1239f54 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -135,8 +135,8 @@ namespace MWInput mInputManager->setControllerEventCallback(this); std::string file = userFileExists ? userFile : ""; - mInputBinder = new ICS::InputControlSystem(file, true, this, NULL, A_Last); - + std::string controllerdb = Settings::Manager::getString("gamecontrollerdb file", "Input"); + mInputBinder = new ICS::InputControlSystem(file, true, this, NULL, controllerdb, A_Last); adjustMouseRegion (window->getWidth(), window->getHeight()); loadKeyDefaults(); diff --git a/extern/oics/ICSInputControlSystem.cpp b/extern/oics/ICSInputControlSystem.cpp index 3c719151b..4db28d3f1 100644 --- a/extern/oics/ICSInputControlSystem.cpp +++ b/extern/oics/ICSInputControlSystem.cpp @@ -30,7 +30,7 @@ namespace ICS { InputControlSystem::InputControlSystem(std::string file, bool active , DetectingBindingListener* detectingBindingListener - , InputControlSystemLog* log, size_t channelCount) + , InputControlSystemLog* log, std::string controllerdb, size_t channelCount) : mFileName(file) , mDetectingBindingListener(detectingBindingListener) , mDetectingBindingControl(NULL) @@ -279,14 +279,17 @@ namespace ICS //Load controller mappings #if SDL_VERSION_ATLEAST(2,0,2) - int res = SDL_GameControllerAddMappingsFromFile("resources/gamecontrollerdb.txt"); - if(res == -1) - { - ICS_LOG(std::string("Error loading controller bindings: ")+SDL_GetError()); - } - else - { - ICS_LOG(std::string("Loaded ")+boost::lexical_cast(res)+" Game controller bindings"); + if(!controllerdb.empty()) + { + int res = SDL_GameControllerAddMappingsFromFile(controllerdb.c_str()); + if(res == -1) + { + ICS_LOG(std::string("Error loading controller bindings: ")+SDL_GetError()); + } + else + { + ICS_LOG(std::string("Loaded ")+boost::lexical_cast(res)+" Game controller bindings"); + } } #endif diff --git a/extern/oics/ICSInputControlSystem.h b/extern/oics/ICSInputControlSystem.h index 0bdd67b34..f58d242fc 100644 --- a/extern/oics/ICSInputControlSystem.h +++ b/extern/oics/ICSInputControlSystem.h @@ -74,7 +74,8 @@ namespace ICS InputControlSystem(std::string file = "", bool active = true , DetectingBindingListener* detectingBindingListener = NULL - , InputControlSystemLog* log = NULL, size_t channelCount = 16); + , InputControlSystemLog* log = NULL, std::string controllerdb = "" + , size_t channelCount = 16); ~InputControlSystem(); std::string getFileName(){ return mFileName; }; diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 7566994e2..ae0a468cd 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -181,6 +181,8 @@ always run = false allow third person zoom = false +gamecontrollerdb file = resources/gamecontrollerdb.txt + [Game] # Always use the most powerful attack when striking with a weapon (chop, slash or thrust) best attack = false From 95219a7936be2aaca207b9c1b2712f218e0ad69c Mon Sep 17 00:00:00 2001 From: Digmaster Date: Tue, 9 Dec 2014 14:48:34 -0600 Subject: [PATCH 085/740] Show currently selected input type for settings window --- apps/openmw/mwgui/settingswindow.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 619a0c87d..a07fa032a 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -245,6 +245,9 @@ namespace MWGui MyGUI::TextBox* diffText; getWidget(diffText, "DifficultyText"); diffText->setCaptionWithReplacing("#{sDifficulty} (" + boost::lexical_cast(int(Settings::Manager::getInt("difficulty", "Game"))) + ")"); + + mKeyboardSwitch->setStateSelected(true); + mControllerSwitch->setStateSelected(false); } void SettingsWindow::onOkButtonClicked(MyGUI::Widget* _sender) @@ -447,6 +450,8 @@ namespace MWGui if(mKeyboardMode) return; mKeyboardMode = true; + mKeyboardSwitch->setStateSelected(true); + mControllerSwitch->setStateSelected(false); updateControlsBox(); } @@ -455,6 +460,8 @@ namespace MWGui if(!mKeyboardMode) return; mKeyboardMode = false; + mKeyboardSwitch->setStateSelected(false); + mControllerSwitch->setStateSelected(true); updateControlsBox(); } From e076e8a9bd3303cbce04d475ce9cdc0c2091df14 Mon Sep 17 00:00:00 2001 From: Digmaster Date: Tue, 9 Dec 2014 14:53:50 -0600 Subject: [PATCH 086/740] Fixed error when downgrading openmw versions --- extern/oics/ICSInputControlSystem.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/extern/oics/ICSInputControlSystem.cpp b/extern/oics/ICSInputControlSystem.cpp index 4db28d3f1..a8efd54bc 100644 --- a/extern/oics/ICSInputControlSystem.cpp +++ b/extern/oics/ICSInputControlSystem.cpp @@ -579,7 +579,9 @@ namespace ICS binder.SetAttribute( "axis", ToString( getJoystickAxisBinding(*o, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); - binder.SetAttribute( "direction", "INCREASE" ); + binder.SetAttribute( "direction", "INCREASE" ); + + binder.SetAttribute( "deviceId", "1" ); //completely useless, but required for backwards compatability control.InsertEndChild(binder); } @@ -592,7 +594,9 @@ namespace ICS binder.SetAttribute( "axis", ToString( getJoystickAxisBinding(*o, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); - binder.SetAttribute( "direction", "DECREASE" ); + binder.SetAttribute( "direction", "DECREASE" ); + + binder.SetAttribute( "deviceId", "1" ); //completely useless, but required for backwards compatability control.InsertEndChild(binder); } @@ -605,7 +609,9 @@ namespace ICS binder.SetAttribute( "button", ToString( getJoystickButtonBinding(*o, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); - binder.SetAttribute( "direction", "INCREASE" ); + binder.SetAttribute( "direction", "INCREASE" ); + + binder.SetAttribute( "deviceId", "1" ); //completely useless, but required for backwards compatability control.InsertEndChild(binder); } @@ -618,7 +624,9 @@ namespace ICS binder.SetAttribute( "button", ToString( getJoystickButtonBinding(*o, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); - binder.SetAttribute( "direction", "DECREASE" ); + binder.SetAttribute( "direction", "DECREASE" ); + + binder.SetAttribute( "deviceId", "1" ); //completely useless, but required for backwards compatability control.InsertEndChild(binder); } From 61d73d186dafd98eea27d9ce1404a23b631a6f7a Mon Sep 17 00:00:00 2001 From: Digmaster Date: Tue, 9 Dec 2014 14:56:40 -0600 Subject: [PATCH 087/740] Fixed part of settings window being in the incorrect place --- files/mygui/openmw_settings_window.layout | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 11751b7ec..d0ab0a7bc 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -213,7 +213,7 @@ - + From a87fe71ddf643fc6231f3cb90a831ed76942187c Mon Sep 17 00:00:00 2001 From: Internecine Date: Sat, 27 Dec 2014 19:46:54 +1300 Subject: [PATCH 088/740] Added a helper function to handle dynamic stat changes --- apps/openmw/mwmechanics/spellcasting.cpp | 28 +++++++++--------------- apps/openmw/mwmechanics/spellcasting.hpp | 2 ++ 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index fd4c9406c..3ec52cf46 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -580,30 +580,15 @@ namespace MWMechanics } else if (effectId == ESM::MagicEffect::DamageHealth || effectId == ESM::MagicEffect::RestoreHealth) { - MWMechanics::DynamicStat health = target.getClass().getCreatureStats(target).getHealth(); - if (effectId == ESM::MagicEffect::DamageHealth) - health.setCurrent(health.getCurrent() - magnitude); - else - health.setCurrent(health.getCurrent() + magnitude); - target.getClass().getCreatureStats(target).setHealth(health); + applyDynamicStatsEffect(0, target, magnitude); } else if (effectId == ESM::MagicEffect::DamageFatigue || effectId == ESM::MagicEffect::RestoreFatigue) { - MWMechanics::DynamicStat fatigue = target.getClass().getCreatureStats(target).getFatigue(); - if (effectId == ESM::MagicEffect::DamageFatigue) - fatigue.setCurrent(fatigue.getCurrent() - magnitude); - else - fatigue.setCurrent(fatigue.getCurrent() + magnitude); - target.getClass().getCreatureStats(target).setHealth(fatigue); + applyDynamicStatsEffect(1, target, magnitude); } else if (effectId == ESM::MagicEffect::DamageMagicka || effectId == ESM::MagicEffect::RestoreMagicka) { - MWMechanics::DynamicStat magicka = target.getClass().getCreatureStats(target).getMagicka(); - if (effectId == ESM::MagicEffect::DamageMagicka) - magicka.setCurrent(magicka.getCurrent() - magnitude); - else - magicka.setCurrent(magicka.getCurrent() + magnitude); - target.getClass().getCreatureStats(target).setHealth(magicka); + applyDynamicStatsEffect(2, target, magnitude); } else if (effectId == ESM::MagicEffect::DamageSkill || effectId == ESM::MagicEffect::RestoreSkill) { @@ -666,6 +651,13 @@ namespace MWMechanics } } } + + void CastSpell::applyDynamicStatsEffect(int attribute, const MWWorld::Ptr& target, float magnitude) + { + DynamicStat value = target.getClass().getCreatureStats(target).getDynamic(attribute); + value.modify(magnitude); + target.getClass().getCreatureStats(target).setDynamic(attribute, value); + } bool CastSpell::cast(const std::string &id) { diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 395ae043b..d76478146 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -93,6 +93,8 @@ namespace MWMechanics /// @note \a caster can be any type of object, or even an empty object. void applyInstantEffect (const MWWorld::Ptr& target, const MWWorld::Ptr& caster, const MWMechanics::EffectKey& effect, float magnitude); + + void applyDynamicStatsEffect (int attribute, const MWWorld::Ptr& target, float magnitude); }; } From 5f9540318a99dc3c551abf6c66a26a6428a1c0a9 Mon Sep 17 00:00:00 2001 From: Internecine Date: Sat, 27 Dec 2014 19:49:14 +1300 Subject: [PATCH 089/740] Fixed incorrect indexes --- 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 3ec52cf46..352db88b4 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -584,11 +584,11 @@ namespace MWMechanics } else if (effectId == ESM::MagicEffect::DamageFatigue || effectId == ESM::MagicEffect::RestoreFatigue) { - applyDynamicStatsEffect(1, target, magnitude); + applyDynamicStatsEffect(2, target, magnitude); } else if (effectId == ESM::MagicEffect::DamageMagicka || effectId == ESM::MagicEffect::RestoreMagicka) { - applyDynamicStatsEffect(2, target, magnitude); + applyDynamicStatsEffect(1, target, magnitude); } else if (effectId == ESM::MagicEffect::DamageSkill || effectId == ESM::MagicEffect::RestoreSkill) { From a62e15d93d6d0350c9807ae71870357926eef17c Mon Sep 17 00:00:00 2001 From: dteviot Date: Tue, 30 Dec 2014 17:25:19 +1300 Subject: [PATCH 090/740] Read profile files from LauncherSettings in load order. --- apps/launcher/datafilespage.cpp | 20 ++++++++++++++------ apps/launcher/datafilespage.hpp | 2 ++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 3c4d36de7..a0ef97ff9 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -94,20 +94,28 @@ bool Launcher::DataFilesPage::loadSettings() if (!currentProfile.isEmpty()) addProfile(currentProfile, true); - QStringList files = mLauncherSettings.values(QString("Profiles/") + currentProfile + QString("/content"), Qt::MatchExactly); + mSelector->setProfileContent(filesInProfile(currentProfile, pathIterator)); + + return true; +} + +QStringList Launcher::DataFilesPage::filesInProfile(const QString& profileName, PathIterator& pathIterator) +{ + QStringList files = mLauncherSettings.values(QString("Profiles/") + profileName + QString("/content"), Qt::MatchExactly); QStringList filepaths; - foreach (const QString &file, files) + // mLauncherSettings.values() returns the files in reverse load order + QListIterator i(files); + i.toBack(); + while (i.hasPrevious()) { - QString filepath = pathIterator.findFirstPath (file); + QString filepath = pathIterator.findFirstPath(i.previous()); if (!filepath.isEmpty()) filepaths << filepath; } - mSelector->setProfileContent (filepaths); - - return true; + return filepaths; } void Launcher::DataFilesPage::saveSettings(const QString &profile) diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index 15fa00308..c2fc22461 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -134,6 +134,8 @@ namespace Launcher } }; + + QStringList filesInProfile(const QString& profileName, PathIterator& pathIterator); }; } #endif From 3024c67995db4d7f2cbe5ac51ce3db5d9e40b872 Mon Sep 17 00:00:00 2001 From: Marco Schulze Date: Tue, 30 Dec 2014 18:37:33 -0300 Subject: [PATCH 091/740] Regenerate components/version/version.hpp as HEAD moves on a git checkout Pull request #416 introduced a common bug where version.hpp wouldn't be regenerated every build, poteantially leading to stale version data. This commit adds a custom build target, git-version, which updates version.hpp before the components library is built. --- CMakeLists.txt | 25 ++----------------------- cmake/GitVersion.cmake | 24 ++++++++++++++++++++++++ components/CMakeLists.txt | 23 ++++++++++++++++++++++- 3 files changed, 48 insertions(+), 24 deletions(-) create mode 100644 cmake/GitVersion.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index d7c85818e..323b743bc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,33 +20,13 @@ set(OPENMW_VERSION_TAGHASH "") set(OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}") +set(GIT_CHECKOUT FALSE) if(EXISTS ${PROJECT_SOURCE_DIR}/.git) if(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/shallow) find_package(Git) if(GIT_FOUND) - execute_process ( - COMMAND "${GIT_EXECUTABLE}" rev-list --tags --max-count=1 - WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" - RESULT_VARIABLE EXITCODE1 - OUTPUT_VARIABLE TAGHASH - OUTPUT_STRIP_TRAILING_WHITESPACE) - - execute_process ( - COMMAND "${GIT_EXECUTABLE}" rev-parse HEAD - WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" - RESULT_VARIABLE EXITCODE2 - OUTPUT_VARIABLE COMMITHASH - OUTPUT_STRIP_TRAILING_WHITESPACE) - - string (COMPARE EQUAL "${EXITCODE1}:${EXITCODE2}" "0:0" SUCCESS) - if (SUCCESS) - set(OPENMW_VERSION_COMMITHASH "${COMMITHASH}") - set(OPENMW_VERSION_TAGHASH "${TAGHASH}") - message(STATUS "OpenMW version ${OPENMW_VERSION}") - else (SUCCESS) - message(WARNING "Failed to get valid version information from Git") - endif (SUCCESS) + set(GIT_CHECKOUT TRUE) else(GIT_FOUND) message(WARNING "Git executable not found") endif(GIT_FOUND) @@ -874,4 +854,3 @@ if (DOXYGEN_FOUND) WORKING_DIRECTORY ${OpenMW_BINARY_DIR} COMMENT "Generating documentation for the github-pages at ${DOXYGEN_PAGES_OUTPUT_DIR}" VERBATIM) endif () - diff --git a/cmake/GitVersion.cmake b/cmake/GitVersion.cmake new file mode 100644 index 000000000..0087461a1 --- /dev/null +++ b/cmake/GitVersion.cmake @@ -0,0 +1,24 @@ +execute_process ( + COMMAND ${GIT_EXECUTABLE} rev-list --tags --max-count=1 + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + RESULT_VARIABLE EXITCODE1 + OUTPUT_VARIABLE TAGHASH + OUTPUT_STRIP_TRAILING_WHITESPACE) + +execute_process ( + COMMAND ${GIT_EXECUTABLE} rev-parse HEAD + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + RESULT_VARIABLE EXITCODE2 + OUTPUT_VARIABLE COMMITHASH + OUTPUT_STRIP_TRAILING_WHITESPACE) + +string (COMPARE EQUAL "${EXITCODE1}:${EXITCODE2}" "0:0" SUCCESS) +if (SUCCESS) + set(OPENMW_VERSION_COMMITHASH "${COMMITHASH}") + set(OPENMW_VERSION_TAGHASH "${TAGHASH}") + message(STATUS "OpenMW version ${OPENMW_VERSION}") +else (SUCCESS) + message(WARNING "Failed to get valid version information from Git") +endif (SUCCESS) + +configure_file(${VERSION_HPP_IN} ${VERSION_HPP}) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 6918b87a7..1e400f779 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -2,7 +2,24 @@ project (Components) set (CMAKE_BUILD_TYPE DEBUG) # Version file -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/version/version.hpp.cmake" "${CMAKE_CURRENT_SOURCE_DIR}/version/version.hpp") +set (VERSION_HPP_IN ${CMAKE_CURRENT_SOURCE_DIR}/version/version.hpp.cmake) +set (VERSION_HPP ${CMAKE_CURRENT_SOURCE_DIR}/version/version.hpp) +if (GIT_CHECKOUT) + add_custom_target (git-version + COMMAND ${CMAKE_COMMAND} + -DGIT_EXECUTABLE=${GIT_EXECUTABLE} + -DPROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR} + -DVERSION_HPP_IN=${VERSION_HPP_IN} + -DVERSION_HPP=${VERSION_HPP} + -DOPENMW_VERSION_MAJOR=${OPENMW_VERSION_MAJOR} + -DOPENMW_VERSION_MINOR=${OPENMW_VERSION_MINOR} + -DOPENMW_VERSION_RELEASE=${OPENMW_VERSION_RELEASE} + -DOPENMW_VERSION=${OPENMW_VERSION} + -P ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/GitVersion.cmake + VERBATIM) +else (GIT_CHECKOUT) + configure_file(${VERSION_HPP_IN} ${VERSION_HPP}) +endif (GIT_CHECKOUT) # source files @@ -145,6 +162,10 @@ add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS} ${ESM_UI_HDR}) target_link_libraries(components ${Boost_LIBRARIES} ${OGRE_LIBRARIES}) +if (GIT_CHECKOUT) + add_dependencies (components git-version) +endif (GIT_CHECKOUT) + # Fix for not visible pthreads functions for linker with glibc 2.15 if (UNIX AND NOT APPLE) target_link_libraries(components ${CMAKE_THREAD_LIBS_INIT}) From dfbd470613045f19a7628de5ad600cf3296bc8da Mon Sep 17 00:00:00 2001 From: dteviot Date: Wed, 31 Dec 2014 19:19:54 +1300 Subject: [PATCH 092/740] Adjust plug-in order to match profile loading. Also marks plug-ins with load order problems in red and changes tool tip to describe error. --- components/CMakeLists.txt | 1 + .../contentselector/model/contentmodel.cpp | 93 ++++++++++++++++++- .../contentselector/model/contentmodel.hpp | 11 ++- .../contentselector/model/loadordererror.cpp | 22 +++++ .../contentselector/model/loadordererror.hpp | 41 ++++++++ .../contentselector/view/contentselector.cpp | 6 +- .../contentselector/view/contentselector.hpp | 2 +- 7 files changed, 167 insertions(+), 9 deletions(-) create mode 100644 components/contentselector/model/loadordererror.cpp create mode 100644 components/contentselector/model/loadordererror.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 6918b87a7..fbad61bfd 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -116,6 +116,7 @@ if(QT_QTGUI_LIBRARY AND QT_QTCORE_LIBRARY) add_component_qt_dir (contentselector model/modelitem model/esmfile model/naturalsort model/contentmodel + model/loadordererror view/combobox view/contentselector ) add_component_qt_dir (config diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 0d4f2365a..72bca2244 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "components/esm/esmreader.hpp" @@ -170,6 +171,16 @@ QVariant ContentSelectorModel::ContentModel::data(const QModelIndex &index, int switch (role) { + case Qt::ForegroundRole: + { + if (isLoadOrderError(file->filePath())) + { + QBrush redBackground(Qt::red, Qt::SolidPattern); + return redBackground; + } + break; + } + case Qt::EditRole: case Qt::DisplayRole: { @@ -202,7 +213,7 @@ QVariant ContentSelectorModel::ContentModel::data(const QModelIndex &index, int if (column != 0) return QVariant(); - return file->toolTip(); + return isLoadOrderError(file->filePath()) ? getLoadOrderError(file->filePath()).toolTip() : file->toolTip(); break; } @@ -341,6 +352,8 @@ bool ContentSelectorModel::ContentModel::removeRows(int position, int rows, cons } endRemoveRows(); + // at this point we know that drag and drop has finished. + checkForLoadOrderErrors(); return true; } @@ -530,11 +543,83 @@ bool ContentSelectorModel::ContentModel::isEnabled (QModelIndex index) const return (flags(index) & Qt::ItemIsEnabled); } -void ContentSelectorModel::ContentModel::setCheckStates (const QStringList &fileList, bool isChecked) +bool ContentSelectorModel::ContentModel::isLoadOrderError(const QString& filepath) const +{ + return !(getLoadOrderError(filepath) == LoadOrderError::sNoError); +} + +ContentSelectorModel::LoadOrderError ContentSelectorModel::ContentModel::getLoadOrderError(const QString& filepath) const +{ + return mLoadOrderErrors.contains(filepath) ? mLoadOrderErrors[filepath] : ContentSelectorModel::LoadOrderError::sNoError; +} + +void ContentSelectorModel::ContentModel::setLoadOrderError(const QString& filepath, const ContentSelectorModel::LoadOrderError& loadOrderError) +{ + mLoadOrderErrors[filepath] = loadOrderError; + int filePosition = indexFromItem(item(filepath)).row(); + emit dataChanged(index(filePosition, 0, QModelIndex()), index(filePosition, 0, QModelIndex())); +} + +void ContentSelectorModel::ContentModel::setContentList(const QStringList &fileList, bool isChecked) { - foreach (const QString &file, fileList) + mLoadOrderErrors.clear(); + int previousPosition = -1; + foreach (const QString &filepath, fileList) { - setCheckState (file, isChecked); + if (setCheckState(filepath, isChecked)) + { + // as necessary, move plug-ins in visible list to match sequence of supplied filelist + const EsmFile* file = item(filepath); + int filePosition = indexFromItem(file).row(); + if (filePosition < previousPosition) + { + mFiles.move(filePosition, previousPosition); + emit dataChanged(index(filePosition, 0, QModelIndex()), index(previousPosition, 0, QModelIndex())); + } + else + { + previousPosition = filePosition; + } + } + } + checkForLoadOrderErrors(); +} + +void ContentSelectorModel::ContentModel::checkForLoadOrderErrors() +{ + for (int row = 0; row < mFiles.count(); ++row) + { + EsmFile* file = item(row); + bool isRowInError = isLoadOrderError(file->filePath()); + LoadOrderError::ErrorCode error = LoadOrderError::ErrorCode_None; + foreach(QString dependantfileName, file->gameFiles()) + { + const EsmFile* dependentFile = item(dependantfileName); + + if (!dependentFile) + { + error = LoadOrderError::ErrorCode_MissingDependency; + } + else if (!isChecked(dependentFile->filePath())) + { + error = LoadOrderError::ErrorCode_InactiveDependency; + } + else if (row < indexFromItem(dependentFile).row()) + { + error = LoadOrderError::ErrorCode_LoadOrder; + } + + if (!isRowInError && (error != LoadOrderError::ErrorCode_None)) + { + setLoadOrderError(file->filePath(), LoadOrderError(error, dependantfileName)); + break; + } + } + + if (isRowInError && (error == LoadOrderError::ErrorCode_None)) + { + setLoadOrderError(file->filePath(), LoadOrderError::sNoError); + } } } diff --git a/components/contentselector/model/contentmodel.hpp b/components/contentselector/model/contentmodel.hpp index 7b2000b51..fc50eeb85 100644 --- a/components/contentselector/model/contentmodel.hpp +++ b/components/contentselector/model/contentmodel.hpp @@ -4,6 +4,8 @@ #include #include +#include "loadordererror.hpp" + namespace ContentSelectorModel { class EsmFile; @@ -47,10 +49,14 @@ namespace ContentSelectorModel bool isEnabled (QModelIndex index) const; bool isChecked(const QString &filepath) const; bool setCheckState(const QString &filepath, bool isChecked); - void setCheckStates (const QStringList &fileList, bool isChecked); + void setContentList(const QStringList &fileList, bool isChecked); ContentFileList checkedItems() const; void uncheckAll(); + bool isLoadOrderError(const QString& filepath) const; + ContentSelectorModel::LoadOrderError ContentSelectorModel::ContentModel::getLoadOrderError(const QString& filepath) const; + void ContentSelectorModel::ContentModel::setLoadOrderError(const QString& filepath, const ContentSelectorModel::LoadOrderError& loadOrderError); + void refreshModel(); private: @@ -60,9 +66,12 @@ namespace ContentSelectorModel EsmFile *item(int row); void sortFiles(); + void checkForLoadOrderErrors(); + ContentFileList mFiles; QHash mCheckStates; + QHash mLoadOrderErrors; QTextCodec *mCodec; QString mEncoding; diff --git a/components/contentselector/model/loadordererror.cpp b/components/contentselector/model/loadordererror.cpp new file mode 100644 index 000000000..c8b258e98 --- /dev/null +++ b/components/contentselector/model/loadordererror.cpp @@ -0,0 +1,22 @@ +#include "loadordererror.hpp" +#include + +QString ContentSelectorModel::LoadOrderError::sErrorToolTips[ErrorCode_LoadOrder] = +{ + QString("Unable to find dependant file: %1"), + QString("Dependent file needs to be active: %1"), + QString("This file needs to load after %1"), +}; + +ContentSelectorModel::LoadOrderError ContentSelectorModel::LoadOrderError::sNoError = ContentSelectorModel::LoadOrderError(); + +QString ContentSelectorModel::LoadOrderError::toolTip() const +{ + assert(mErrorCode); + return sErrorToolTips[mErrorCode - 1].arg(mFileName); +} + +bool ContentSelectorModel::LoadOrderError::operator== (const ContentSelectorModel::LoadOrderError& rhs) const +{ + return (mErrorCode == rhs.mErrorCode) && ((mErrorCode == ErrorCode_None) || (mFileName == rhs.mFileName)); +} \ No newline at end of file diff --git a/components/contentselector/model/loadordererror.hpp b/components/contentselector/model/loadordererror.hpp new file mode 100644 index 000000000..75ec2ad92 --- /dev/null +++ b/components/contentselector/model/loadordererror.hpp @@ -0,0 +1,41 @@ +#ifndef LOADORDERERROR_HPP +#define LOADORDERERROR_HPP + +#include + +namespace ContentSelectorModel +{ + /// \Details of a suspected Load Order problem a plug-in will have. This is basically a POD + class LoadOrderError + { + public: + enum ErrorCode + { + ErrorCode_None = 0, + ErrorCode_MissingDependency = 1, + ErrorCode_InactiveDependency = 2, + ErrorCode_LoadOrder = 3, + }; + + inline LoadOrderError() : mErrorCode(ErrorCode_None) {}; + inline LoadOrderError(ErrorCode errorCode, QString fileName) + { + mErrorCode = errorCode; + mFileName = fileName; + } + inline ErrorCode errorCode() const { return mErrorCode; } + inline QString fileName() const { return mFileName; } + bool operator==(const LoadOrderError& rhs) const; + QString toolTip() const; + + /// \Sentinal to represent a "No Load Order Error" condition + static LoadOrderError sNoError; + + private: + ErrorCode mErrorCode; + QString mFileName; + static QString sErrorToolTips[ErrorCode_LoadOrder]; + }; +} + +#endif // LOADORDERERROR_HPP diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index b12d4147a..a5e250840 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -75,7 +75,7 @@ void ContentSelectorView::ContentSelector::setProfileContent(const QStringList & } } - setCheckStates (fileList); + setContentList(fileList); } void ContentSelectorView::ContentSelector::setGameFile(const QString &filename) @@ -103,14 +103,14 @@ void ContentSelectorView::ContentSelector::clearCheckStates() mContentModel->uncheckAll(); } -void ContentSelectorView::ContentSelector::setCheckStates(const QStringList &list) +void ContentSelectorView::ContentSelector::setContentList(const QStringList &list) { if (list.isEmpty()) { slotCurrentGameFileIndexChanged (ui.gameFileView->currentIndex()); } else - mContentModel->setCheckStates (list, true); + mContentModel->setContentList(list, true); } ContentSelectorModel::ContentFileList diff --git a/components/contentselector/view/contentselector.hpp b/components/contentselector/view/contentselector.hpp index a25eb20ae..a4da38727 100644 --- a/components/contentselector/view/contentselector.hpp +++ b/components/contentselector/view/contentselector.hpp @@ -32,7 +32,7 @@ namespace ContentSelectorView void setProfileContent (const QStringList &fileList); void clearCheckStates(); - void setCheckStates (const QStringList &list); + void setContentList(const QStringList &list); ContentSelectorModel::ContentFileList selectedFiles() const; From 93bbd7463ad1c0b9e97c1e9794f916b2ce1823c6 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 1 Jan 2015 09:40:42 +1300 Subject: [PATCH 093/740] Fixed errors and warnings from Travis CI. --- components/contentselector/model/contentmodel.cpp | 2 +- components/contentselector/model/loadordererror.cpp | 2 +- components/contentselector/model/loadordererror.hpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 72bca2244..b74960dc8 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include "components/esm/esmreader.hpp" diff --git a/components/contentselector/model/loadordererror.cpp b/components/contentselector/model/loadordererror.cpp index c8b258e98..593c53abb 100644 --- a/components/contentselector/model/loadordererror.cpp +++ b/components/contentselector/model/loadordererror.cpp @@ -5,7 +5,7 @@ QString ContentSelectorModel::LoadOrderError::sErrorToolTips[ErrorCode_LoadOrder { QString("Unable to find dependant file: %1"), QString("Dependent file needs to be active: %1"), - QString("This file needs to load after %1"), + QString("This file needs to load after %1") }; ContentSelectorModel::LoadOrderError ContentSelectorModel::LoadOrderError::sNoError = ContentSelectorModel::LoadOrderError(); diff --git a/components/contentselector/model/loadordererror.hpp b/components/contentselector/model/loadordererror.hpp index 75ec2ad92..f7a58c25f 100644 --- a/components/contentselector/model/loadordererror.hpp +++ b/components/contentselector/model/loadordererror.hpp @@ -14,7 +14,7 @@ namespace ContentSelectorModel ErrorCode_None = 0, ErrorCode_MissingDependency = 1, ErrorCode_InactiveDependency = 2, - ErrorCode_LoadOrder = 3, + ErrorCode_LoadOrder = 3 }; inline LoadOrderError() : mErrorCode(ErrorCode_None) {}; From 43dd9aee94c70230181eea114e1165210fb5d510 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 1 Jan 2015 10:13:27 +1300 Subject: [PATCH 094/740] Fix for more errors found by Travis CI. --- components/contentselector/model/contentmodel.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/contentselector/model/contentmodel.hpp b/components/contentselector/model/contentmodel.hpp index fc50eeb85..2a9f2c93b 100644 --- a/components/contentselector/model/contentmodel.hpp +++ b/components/contentselector/model/contentmodel.hpp @@ -54,8 +54,8 @@ namespace ContentSelectorModel void uncheckAll(); bool isLoadOrderError(const QString& filepath) const; - ContentSelectorModel::LoadOrderError ContentSelectorModel::ContentModel::getLoadOrderError(const QString& filepath) const; - void ContentSelectorModel::ContentModel::setLoadOrderError(const QString& filepath, const ContentSelectorModel::LoadOrderError& loadOrderError); + LoadOrderError getLoadOrderError(const QString& filepath) const; + void setLoadOrderError(const QString& filepath, const LoadOrderError& loadOrderError); void refreshModel(); From fb671fed20eb7e254665ddaab865690db3a761aa Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 1 Jan 2015 15:53:35 +1300 Subject: [PATCH 095/740] Corrected issues found by Scrawl. --- components/contentselector/model/contentmodel.cpp | 6 +++--- components/contentselector/model/loadordererror.cpp | 2 +- components/contentselector/model/loadordererror.hpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index b74960dc8..6366d7f54 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -592,9 +592,9 @@ void ContentSelectorModel::ContentModel::checkForLoadOrderErrors() EsmFile* file = item(row); bool isRowInError = isLoadOrderError(file->filePath()); LoadOrderError::ErrorCode error = LoadOrderError::ErrorCode_None; - foreach(QString dependantfileName, file->gameFiles()) + foreach(QString dependentfileName, file->gameFiles()) { - const EsmFile* dependentFile = item(dependantfileName); + const EsmFile* dependentFile = item(dependentfileName); if (!dependentFile) { @@ -611,7 +611,7 @@ void ContentSelectorModel::ContentModel::checkForLoadOrderErrors() if (!isRowInError && (error != LoadOrderError::ErrorCode_None)) { - setLoadOrderError(file->filePath(), LoadOrderError(error, dependantfileName)); + setLoadOrderError(file->filePath(), LoadOrderError(error, dependentfileName)); break; } } diff --git a/components/contentselector/model/loadordererror.cpp b/components/contentselector/model/loadordererror.cpp index 593c53abb..0d02efbeb 100644 --- a/components/contentselector/model/loadordererror.cpp +++ b/components/contentselector/model/loadordererror.cpp @@ -3,7 +3,7 @@ QString ContentSelectorModel::LoadOrderError::sErrorToolTips[ErrorCode_LoadOrder] = { - QString("Unable to find dependant file: %1"), + QString("Unable to find dependent file: %1"), QString("Dependent file needs to be active: %1"), QString("This file needs to load after %1") }; diff --git a/components/contentselector/model/loadordererror.hpp b/components/contentselector/model/loadordererror.hpp index f7a58c25f..f3d3b0f8a 100644 --- a/components/contentselector/model/loadordererror.hpp +++ b/components/contentselector/model/loadordererror.hpp @@ -5,7 +5,7 @@ namespace ContentSelectorModel { - /// \Details of a suspected Load Order problem a plug-in will have. This is basically a POD + /// \brief Details of a suspected Load Order problem a plug-in will have. This is basically a POD. class LoadOrderError { public: @@ -28,7 +28,7 @@ namespace ContentSelectorModel bool operator==(const LoadOrderError& rhs) const; QString toolTip() const; - /// \Sentinal to represent a "No Load Order Error" condition + /// Sentinel to represent a "No Load Order Error" condition static LoadOrderError sNoError; private: From a7a3ab0c78aef3f601e5e7006fa664a8abdf6a7e Mon Sep 17 00:00:00 2001 From: Internecine Date: Thu, 1 Jan 2015 21:26:09 +1300 Subject: [PATCH 096/740] Fixed instant negative dynamic stat changes being applied as positive --- apps/openmw/mwmechanics/spellcasting.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 352db88b4..71064d9b0 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -578,15 +578,27 @@ namespace MWMechanics value.restore(magnitude); target.getClass().getCreatureStats(target).setAttribute(attribute, value); } - else if (effectId == ESM::MagicEffect::DamageHealth || effectId == ESM::MagicEffect::RestoreHealth) + else if (effectId == ESM::MagicEffect::DamageHealth) { - applyDynamicStatsEffect(0, target, magnitude); + applyDynamicStatsEffect(0, target, magnitude * -1); } - else if (effectId == ESM::MagicEffect::DamageFatigue || effectId == ESM::MagicEffect::RestoreFatigue) + else if (effectId == ESM::MagicEffect::RestoreHealth) { applyDynamicStatsEffect(2, target, magnitude); } - else if (effectId == ESM::MagicEffect::DamageMagicka || effectId == ESM::MagicEffect::RestoreMagicka) + else if (effectId == ESM::MagicEffect::DamageFatigue) + { + applyDynamicStatsEffect(2, target, magnitude * -1); + } + else if (effectId == ESM::MagicEffect::RestoreFatigue) + { + applyDynamicStatsEffect(2, target, magnitude); + } + else if (effectId == ESM::MagicEffect::DamageMagicka) + { + applyDynamicStatsEffect(1, target, magnitude * -1); + } + else if (effectId == ESM::MagicEffect::RestoreMagicka) { applyDynamicStatsEffect(1, target, magnitude); } From 4a734f5cd3750ba3c781290d6c8fc3c945f11eb4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 2 Jan 2015 00:17:51 +0100 Subject: [PATCH 097/740] Fall back to top-level directory when looking for resources (Fixes #2169) --- components/misc/resourcehelpers.cpp | 47 ++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/components/misc/resourcehelpers.cpp b/components/misc/resourcehelpers.cpp index 9eaf441ef..ee911c566 100644 --- a/components/misc/resourcehelpers.cpp +++ b/components/misc/resourcehelpers.cpp @@ -4,6 +4,29 @@ #include +namespace +{ + + + struct MatchPathSeparator + { + bool operator()( char ch ) const + { + return ch == '\\' || ch == '/'; + } + }; + + std::string + getBasename( std::string const& pathname ) + { + return std::string( + std::find_if( pathname.rbegin(), pathname.rend(), + MatchPathSeparator() ).base(), + pathname.end() ); + } + +} + bool Misc::ResourceHelpers::changeExtensionToDds(std::string &path) { Ogre::String::size_type pos = path.rfind('.'); @@ -40,14 +63,24 @@ std::string Misc::ResourceHelpers::correctResourcePath(const std::string &topLev // since we know all (GOTY edition or less) textures end // in .dds, we change the extension - if (changeExtensionToDds(correctedPath)) + bool changedToDds = changeExtensionToDds(correctedPath); + if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(correctedPath)) + return correctedPath; + // if it turns out that the above wasn't true in all cases (not for vanilla, but maybe mods) + // verify, and revert if false (this call succeeds quickly, but fails slowly) + if (changedToDds && Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(origExt)) + return origExt; + + // fall back to a resource in the top level directory if it exists + std::string fallback = topLevelDirectory + "\\" + getBasename(correctedPath); + if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(fallback)) + return fallback; + + if (changedToDds) { - // if it turns out that the above wasn't true in all cases (not for vanilla, but maybe mods) - // verify, and revert if false (this call succeeds quickly, but fails slowly) - if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(correctedPath)) - { - return origExt; - } + fallback = topLevelDirectory + "\\" + getBasename(origExt); + if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(fallback)) + return fallback; } return correctedPath; From 593ca6bd48dc2904d6bab232a4c4028ae049ae65 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 2 Jan 2015 00:34:16 +0100 Subject: [PATCH 098/740] Fix for framerate-dependent maximum stepping distance (Bug #1638) --- apps/openmw/mwworld/physicssystem.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 1374dc37a..3a7aa0490 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -108,7 +108,7 @@ namespace MWWorld } static bool stepMove(btCollisionObject *colobj, Ogre::Vector3 &position, - const Ogre::Vector3 &velocity, float &remainingTime, + const Ogre::Vector3 &toMove, float &remainingTime, OEngine::Physic::PhysicEngine *engine) { /* @@ -124,7 +124,7 @@ namespace MWWorld * If not successful return 'false'. May fail for these reasons: * - can't move directly up from current position * - having moved up by between epsilon() and sStepSize, can't move forward - * - having moved forward by between epsilon() and velocity*remainingTime, + * - having moved forward by between epsilon() and toMove, * = moved down between 0 and just under sStepSize but slope was too steep, or * = moved the full sStepSize down (FIXME: this could be a bug) * @@ -133,7 +133,7 @@ namespace MWWorld * Starting position. Obstacle or stairs with height upto sStepSize in front. * * +--+ +--+ |XX - * | | -------> velocity | | +--+XX + * | | -------> toMove | | +--+XX * | | | | |XXXXX * | | +--+ | | +--+XXXXX * | | |XX| | | |XXXXXXXX @@ -171,11 +171,11 @@ namespace MWWorld * | | * <------------------->| | * +--+ +--+ - * |XX| the moved amount is velocity*remainingTime*tracer.mFraction + * |XX| the moved amount is toMove*tracer.mFraction * +--+ * ============================================== */ - tracer.doTrace(colobj, stepper.mEndPos, stepper.mEndPos + velocity*remainingTime, engine); + tracer.doTrace(colobj, stepper.mEndPos, stepper.mEndPos + toMove, engine); if(tracer.mFraction < std::numeric_limits::epsilon()) return false; // didn't even move the smallest representable amount @@ -428,9 +428,9 @@ namespace MWWorld Ogre::Vector3 oldPosition = newPosition; // We hit something. Try to step up onto it. (NOTE: stepMove does not allow stepping over) // NOTE: stepMove modifies newPosition if successful - bool result = stepMove(colobj, newPosition, velocity, remainingTime, engine); - if (!result) - result = stepMove(colobj, newPosition, velocity.normalisedCopy()*300.f, remainingTime, engine); + bool result = stepMove(colobj, newPosition, velocity*remainingTime, remainingTime, engine); + if (!result) // to make sure the maximum stepping distance isn't framerate-dependent or movement-speed dependent + result = stepMove(colobj, newPosition, velocity.normalisedCopy()*10.f, remainingTime, engine); if(result) { // don't let pure water creatures move out of water after stepMove From 6f747df7133284ea8146b70595e82951265704e5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 2 Jan 2015 02:10:40 +0100 Subject: [PATCH 099/740] Remove an unused constructor --- apps/openmw/mwrender/sky.cpp | 5 ----- apps/openmw/mwrender/sky.hpp | 1 - 2 files changed, 6 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 385e7d8c5..761d3fd96 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -104,11 +104,6 @@ BillboardObject::BillboardObject( const String& textureName, bodyCount++; } -BillboardObject::BillboardObject() -: mNode(NULL), mMaterial(NULL), mEntity(NULL), mVisibility(1.f) -{ -} - void BillboardObject::requestedConfiguration (sh::MaterialInstance* m, const std::string& configuration) { } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 0544f17ef..70251f490 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -39,7 +39,6 @@ namespace MWRender Ogre::SceneNode* rootNode, const std::string& material ); - BillboardObject(); void requestedConfiguration (sh::MaterialInstance* m, const std::string& configuration); void createdConfiguration (sh::MaterialInstance* m, const std::string& configuration); From d56906acf714c8decf35336ecf104647dd954e45 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 2 Jan 2015 02:27:05 +0100 Subject: [PATCH 100/740] Fix the creature position glitch --- apps/openmw/mwmechanics/character.cpp | 2 ++ apps/openmw/mwrender/animation.cpp | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 3136ae676..21683d3cc 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -441,6 +441,8 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat } // idle handled last as it can depend on the other states + // 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 || mHitState != CharState_None) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index a922fa170..1ef7a3533 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -988,7 +988,11 @@ void Animation::resetActiveGroups() AnimStateMap::const_iterator state = mStates.find(mAnimationTimePtr[0]->getAnimName()); if(state == mStates.end()) + { + if (mAccumRoot && mNonAccumRoot) + mAccumRoot->setPosition(-mNonAccumRoot->getPosition()*mAccumulate); return; + } const Ogre::SharedPtr &animsrc = state->second.mSource; const std::vector >&ctrls = animsrc->mControllers[0]; @@ -1142,9 +1146,6 @@ Ogre::Vector3 Animation::runAnimation(float duration) if(!state.mPlaying && state.mAutoDisable) { - if(mNonAccumCtrl && stateiter->first == mAnimationTimePtr[0]->getAnimName()) - mAccumRoot->setPosition(0.f,0.f,0.f); - mStates.erase(stateiter++); resetActiveGroups(); From 398fe6e780314bd94bee591a9d59b608b48aee56 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 4 Jan 2015 01:33:36 +0100 Subject: [PATCH 101/740] Thrown weapon fix (Fixes #2248) --- apps/openmw/mwrender/weaponanimation.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/weaponanimation.cpp b/apps/openmw/mwrender/weaponanimation.cpp index 8a9feef03..8af4d637a 100644 --- a/apps/openmw/mwrender/weaponanimation.cpp +++ b/apps/openmw/mwrender/weaponanimation.cpp @@ -68,9 +68,6 @@ void WeaponAnimation::attachArrow(MWWorld::Ptr actor) void WeaponAnimation::releaseArrow(MWWorld::Ptr actor) { - if (!mAmmunition.get()) - return; - MWWorld::InventoryStore& inv = actor.getClass().getInventoryStore(actor); MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); if (weapon == inv.end()) @@ -131,6 +128,9 @@ void WeaponAnimation::releaseArrow(MWWorld::Ptr actor) if (ammo == inv.end()) return; + if (!mAmmunition.get()) + return; + Ogre::Vector3 launchPos(0,0,0); if (mAmmunition->mSkelBase) { From bc686c93b50485bc6e3bb4e94d83c7b46def6dca Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 4 Jan 2015 01:36:57 +0100 Subject: [PATCH 102/740] Potential fix for thrown weapons being regarded as broken --- apps/openmw/mwclass/weapon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index f1f0386c6..8456c72e6 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -386,7 +386,7 @@ namespace MWClass std::pair Weapon::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const { - if (ptr.getCellRef().getCharge() == 0) + if (hasItemHealth(ptr) && ptr.getCellRef().getCharge() == 0) return std::make_pair(0, "#{sInventoryMessage1}"); std::pair, bool> slots_ = ptr.getClass().getEquipmentSlots(ptr); From de12c96a460815da6acff2828ce745581e9f01ca Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 4 Jan 2015 19:23:31 +0100 Subject: [PATCH 103/740] Fix crash on exit if the window wasn't created (Fixes #2249) --- apps/openmw/engine.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 3473d0b29..24e1388d0 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -208,7 +208,8 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) OMW::Engine::~Engine() { - mOgre->restoreWindowGammaRamp(); + if (mOgre) + mOgre->restoreWindowGammaRamp(); mEnvironment.cleanup(); delete mScriptContext; delete mOgre; From 5e7e40aac90af0d55e51e7113203f3e96d517585 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 4 Jan 2015 19:50:46 +0100 Subject: [PATCH 104/740] Fix being able to switch weapons while knocked out --- apps/openmw/mwmechanics/character.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 21683d3cc..6632f0275 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -900,7 +900,8 @@ bool CharacterController::updateWeaponState() } bool forcestateupdate = false; - if(weaptype != mWeaponType && mHitState != CharState_KnockDown) + if(weaptype != mWeaponType && mHitState != CharState_KnockDown && mHitState != CharState_KnockOut + && mHitState != CharState_Hit) { forcestateupdate = true; From d919a0186e9f50999f9d10962333f8d60536433f Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 5 Jan 2015 18:54:52 +0100 Subject: [PATCH 105/740] Comment out unused opSkipOnZero --- components/compiler/generator.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/compiler/generator.cpp b/components/compiler/generator.cpp index 2efa2477e..ead0c7290 100644 --- a/components/compiler/generator.cpp +++ b/components/compiler/generator.cpp @@ -150,10 +150,13 @@ namespace code.push_back (Compiler::Generator::segment0 (2, offset)); } + /* + Currently unused void opSkipOnZero (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (24)); } + */ void opSkipOnNonZero (Compiler::Generator::CodeContainer& code) { From c1955ef7fa983b9f9bf72e2cd0ee64af1f03320f Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 5 Jan 2015 05:33:51 +0100 Subject: [PATCH 106/740] Fix enchanting dialog effect labels showing a duration for constant effects --- apps/openmw/mwgui/enchantingdialog.cpp | 9 ++++---- apps/openmw/mwgui/spellcreationdialog.cpp | 25 +++++++++++++++++------ apps/openmw/mwgui/spellcreationdialog.hpp | 9 +++++++- 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 224f8a4d8..4744fd1a1 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -120,19 +120,19 @@ namespace MWGui { case ESM::Enchantment::CastOnce: mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastOnce","Cast Once")); - mAddEffectDialog.constantEffect=false; + setConstantEffect(false); break; case ESM::Enchantment::WhenStrikes: mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastWhenStrikes", "When Strikes")); - mAddEffectDialog.constantEffect=false; + setConstantEffect(false); break; case ESM::Enchantment::WhenUsed: mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastWhenUsed", "When Used")); - mAddEffectDialog.constantEffect=false; + setConstantEffect(false); break; case ESM::Enchantment::ConstantEffect: mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastConstant", "Cast Constant")); - mAddEffectDialog.constantEffect=true; + setConstantEffect(true); break; } } @@ -283,6 +283,7 @@ namespace MWGui { mEnchanting.nextCastStyle(); updateLabels(); + updateEffectsView(); } void EnchantingDialog::onBuyButtonClicked(MyGUI::Widget* sender) diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 6716f87da..0db2e30ce 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -42,6 +42,7 @@ namespace MWGui : WindowModal("openmw_edit_effect.layout") , mEditing(false) , mMagicEffect(NULL) + , mConstantEffect(false) { getWidget(mCancelButton, "CancelButton"); getWidget(mOkButton, "OkButton"); @@ -71,7 +72,11 @@ namespace MWGui mMagnitudeMaxSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &EditEffectDialog::onMagnitudeMaxChanged); mDurationSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &EditEffectDialog::onDurationChanged); mAreaSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &EditEffectDialog::onAreaChanged); - constantEffect=false; + } + + void EditEffectDialog::setConstantEffect(bool constant) + { + mConstantEffect = constant; } void EditEffectDialog::open() @@ -92,8 +97,8 @@ namespace MWGui void EditEffectDialog::newEffect (const ESM::MagicEffect *effect) { bool allowSelf = effect->mData.mFlags & ESM::MagicEffect::CastSelf; - bool allowTouch = (effect->mData.mFlags & ESM::MagicEffect::CastTouch) && !constantEffect; - bool allowTarget = (effect->mData.mFlags & ESM::MagicEffect::CastTarget) && !constantEffect; + bool allowTouch = (effect->mData.mFlags & ESM::MagicEffect::CastTouch) && !mConstantEffect; + bool allowTarget = (effect->mData.mFlags & ESM::MagicEffect::CastTarget) && !mConstantEffect; if (!allowSelf && !allowTouch && !allowTarget) return; // TODO: Show an error message popup? @@ -183,7 +188,7 @@ namespace MWGui mMagnitudeBox->setVisible (true); curY += mMagnitudeBox->getSize().height; } - if (!(mMagicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)&&constantEffect==false) + if (!(mMagicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)&&mConstantEffect==false) { mDurationBox->setPosition(mDurationBox->getPosition().left, curY); mDurationBox->setVisible (true); @@ -204,8 +209,8 @@ namespace MWGui // cycle through range types until we find something that's allowed // does not handle the case where nothing is allowed (this should be prevented before opening the Add Effect dialog) bool allowSelf = mMagicEffect->mData.mFlags & ESM::MagicEffect::CastSelf; - bool allowTouch = (mMagicEffect->mData.mFlags & ESM::MagicEffect::CastTouch) && !constantEffect; - bool allowTarget = (mMagicEffect->mData.mFlags & ESM::MagicEffect::CastTarget) && !constantEffect; + bool allowTouch = (mMagicEffect->mData.mFlags & ESM::MagicEffect::CastTouch) && !mConstantEffect; + bool allowTarget = (mMagicEffect->mData.mFlags & ESM::MagicEffect::CastTarget) && !mConstantEffect; if (mEffect.mRange == ESM::RT_Self && !allowSelf) mEffect.mRange = (mEffect.mRange+1)%3; if (mEffect.mRange == ESM::RT_Touch && !allowTouch) @@ -468,6 +473,7 @@ namespace MWGui , mSelectedEffect(0) , mSelectedKnownEffectId(0) , mType(type) + , mConstantEffect(false) { mAddEffectDialog.eventEffectAdded += MyGUI::newDelegate(this, &EffectEditorBase::onEffectAdded); mAddEffectDialog.eventEffectModified += MyGUI::newDelegate(this, &EffectEditorBase::onEffectModified); @@ -659,6 +665,7 @@ namespace MWGui params.mMagnMax = it->mMagnMax; params.mRange = it->mRange; params.mArea = it->mArea; + params.mIsConstant = mConstantEffect; MyGUI::Button* button = mUsedEffectsView->createWidget("", MyGUI::IntCoord(0, size.height, 0, 24), MyGUI::Align::Default); button->setUserData(i); @@ -703,4 +710,10 @@ namespace MWGui mAddEffectDialog.editEffect (mEffects[id]); mAddEffectDialog.setVisible (true); } + + void EffectEditorBase::setConstantEffect(bool constant) + { + mAddEffectDialog.setConstantEffect(constant); + mConstantEffect = constant; + } } diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index a94289bfd..72e581c87 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -23,12 +23,13 @@ namespace MWGui virtual void open(); virtual void exit(); + void setConstantEffect(bool constant); + void setSkill(int skill); void setAttribute(int attribute); void newEffect (const ESM::MagicEffect* effect); void editEffect (ESM::ENAMstruct effect); - bool constantEffect; typedef MyGUI::delegates::CMultiDelegate1 EventHandle_Effect; EventHandle_Effect eventEffectAdded; @@ -82,6 +83,8 @@ namespace MWGui ESM::ENAMstruct mOldEffect; const ESM::MagicEffect* mMagicEffect; + + bool mConstantEffect; }; @@ -97,6 +100,8 @@ namespace MWGui EffectEditorBase(Type type); virtual ~EffectEditorBase(); + void setConstantEffect(bool constant); + protected: std::map mButtonMapping; // maps button ID to effect ID @@ -110,6 +115,8 @@ namespace MWGui int mSelectedEffect; short mSelectedKnownEffectId; + bool mConstantEffect; + std::vector mEffects; void onEffectAdded(ESM::ENAMstruct effect); From e6be979350102155e281a628027ea887131e74c0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 5 Jan 2015 06:29:33 +0100 Subject: [PATCH 107/740] Fix default position for spell window --- files/settings-default.cfg | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 39232c95c..6ec9b03e9 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -251,10 +251,10 @@ stats y = 0 stats w = 0.375 stats h = 0.4275 -spells x = 0.3775 -spells y = 0.4275 +spells x = 0.625 +spells y = 0.5725 spells w = 0.375 -spells h = 0.5725 +spells h = 0.4275 console x = 0 console y = 0 From c343a5c803b047fdbddbc42cdfe9a15b41b43977 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 5 Jan 2015 19:33:51 +0100 Subject: [PATCH 108/740] stopCombat fix --- apps/openmw/mwmechanics/aisequence.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index ea59708c2..13d09af7e 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -125,19 +125,23 @@ bool AiSequence::isInCombat(const MWWorld::Ptr &actor) const void AiSequence::stopCombat() { - while (getTypeId() == AiPackage::TypeIdCombat) + for(std::list::iterator it = mPackages.begin(); it != mPackages.end(); ) { - delete *mPackages.begin(); - mPackages.erase (mPackages.begin()); + if ((*it)->getTypeId() == AiPackage::TypeIdCombat) + it = mPackages.erase(it); + else + ++it; } } void AiSequence::stopPursuit() { - while (getTypeId() == AiPackage::TypeIdPursue) + for(std::list::iterator it = mPackages.begin(); it != mPackages.end(); ) { - delete *mPackages.begin(); - mPackages.erase (mPackages.begin()); + if ((*it)->getTypeId() == AiPackage::TypeIdPursue) + it = mPackages.erase(it); + else + ++it; } } From 708dbc2518c127ac692e18fcf80cc154b5ca8716 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 5 Jan 2015 19:59:47 +0100 Subject: [PATCH 109/740] Crime fix --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 42728290b..3d757bde6 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1164,6 +1164,19 @@ namespace MWMechanics player.getClass().getNpcStats(player).expell(factionID); } } + + if (type == OT_Assault && !victim.isEmpty() + && !victim.getClass().getCreatureStats(victim).getAiSequence().isInCombat(player) + && victim.getClass().isNpc()) + { + // Attacker is in combat with us, but we are not in combat with the attacker yet. Time to fight back. + // Note: accidental or collateral damage attacks are ignored. + startCombat(victim, player); + + // Set the crime ID, which we will use to calm down participants + // once the bounty has been paid. + victim.getClass().getNpcStats(victim).setCrimeId(id); + } } } From afc961d19c0618c58ae9343a194003ae13b37987 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 5 Jan 2015 20:15:30 +0100 Subject: [PATCH 110/740] Workaround for random AABB assertion due to zero-sized particles (Fixes #1663) --- components/nifogre/ogrenifloader.cpp | 5 ++++- components/nifogre/particles.cpp | 8 ++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index b55248784..9c5f4a016 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -973,7 +973,10 @@ class NIFObjectLoader { const Nif::NiParticleSystemController *partctrl = static_cast(ctrl.getPtr()); - partsys->setDefaultDimensions(partctrl->size*2, partctrl->size*2); + float size = partctrl->size*2; + // HACK: don't allow zero-sized particles which can rarely cause an AABB assertion in Ogre to fail + size = std::max(size, 0.00001f); + partsys->setDefaultDimensions(size, size); if(!partctrl->emitter.empty()) { diff --git a/components/nifogre/particles.cpp b/components/nifogre/particles.cpp index 316e4edc2..4fec2d29e 100644 --- a/components/nifogre/particles.cpp +++ b/components/nifogre/particles.cpp @@ -452,6 +452,8 @@ public: { Ogre::Real scale = (life_time-particle_time) / mGrowTime; assert (scale >= 0); + // HACK: don't allow zero-sized particles which can rarely cause an AABB assertion in Ogre to fail + scale = std::max(scale, 0.00001f); width *= scale; height *= scale; } @@ -459,6 +461,8 @@ public: { Ogre::Real scale = particle_time / mFadeTime; assert (scale >= 0); + // HACK: don't allow zero-sized particles which can rarely cause an AABB assertion in Ogre to fail + scale = std::max(scale, 0.00001f); width *= scale; height *= scale; } @@ -485,6 +489,8 @@ public: { Ogre::Real scale = (life_time-particle_time) / mGrowTime; assert (scale >= 0); + // HACK: don't allow zero-sized particles which can rarely cause an AABB assertion in Ogre to fail + scale = std::max(scale, 0.00001f); width *= scale; height *= scale; } @@ -492,6 +498,8 @@ public: { Ogre::Real scale = particle_time / mFadeTime; assert (scale >= 0); + // HACK: don't allow zero-sized particles which can rarely cause an AABB assertion in Ogre to fail + scale = std::max(scale, 0.00001f); width *= scale; height *= scale; } From 464f8abb3f954a2798e8d312f938ccd6fef5ef26 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 6 Jan 2015 01:10:09 +0100 Subject: [PATCH 111/740] List exterior cell names in tab completion (Fixes #2252) --- apps/openmw/mwgui/console.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index c922b625d..97f11f4f3 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -102,8 +102,20 @@ namespace MWGui it->second->listIdentifier (mNames); } + // exterior cell names aren't technically identifiers, but since the COC function accepts them, + // we should list them too + for (MWWorld::Store::iterator it = store.get().extBegin(); + it != store.get().extEnd(); ++it) + { + if (!it->mName.empty()) + mNames.push_back(it->mName); + } + // sort std::sort (mNames.begin(), mNames.end()); + + // remove duplicates + mNames.erase( std::unique( mNames.begin(), mNames.end() ), mNames.end() ); } } From e1fdcb608eaa0bff2e491a4f4b063b02bf4d41b7 Mon Sep 17 00:00:00 2001 From: Internecine Date: Tue, 6 Jan 2015 15:00:24 +1300 Subject: [PATCH 112/740] Fixed incorrect index --- apps/openmw/mwmechanics/spellcasting.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 71064d9b0..8e4e80d9c 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -584,7 +584,7 @@ namespace MWMechanics } else if (effectId == ESM::MagicEffect::RestoreHealth) { - applyDynamicStatsEffect(2, target, magnitude); + applyDynamicStatsEffect(0, target, magnitude); } else if (effectId == ESM::MagicEffect::DamageFatigue) { From f267497c0316f1163c4202451babf768274a6440 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 5 Jan 2015 18:52:37 +0100 Subject: [PATCH 113/740] Allow separate summoned creature instances for each spell ID (Fixes #2194) --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwgui/spellicons.cpp | 2 +- apps/openmw/mwgui/spellicons.hpp | 2 +- apps/openmw/mwmechanics/activespells.cpp | 18 +- apps/openmw/mwmechanics/activespells.hpp | 3 + apps/openmw/mwmechanics/actors.cpp | 159 +----------------- apps/openmw/mwmechanics/creaturestats.cpp | 2 +- apps/openmw/mwmechanics/creaturestats.hpp | 11 +- apps/openmw/mwmechanics/magiceffects.hpp | 2 +- apps/openmw/mwmechanics/spellcasting.cpp | 1 + apps/openmw/mwmechanics/spells.cpp | 2 +- apps/openmw/mwmechanics/summoning.cpp | 195 ++++++++++++++++++++++ apps/openmw/mwmechanics/summoning.hpp | 35 ++++ apps/openmw/mwworld/inventorystore.cpp | 49 +++++- apps/openmw/mwworld/inventorystore.hpp | 3 + components/esm/creaturestats.cpp | 8 +- components/esm/creaturestats.hpp | 2 +- 17 files changed, 329 insertions(+), 167 deletions(-) create mode 100644 apps/openmw/mwmechanics/summoning.cpp create mode 100644 apps/openmw/mwmechanics/summoning.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index c645e1a0a..97ab13012 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -76,7 +76,7 @@ add_openmw_dir (mwmechanics mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting - disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor + disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning ) add_openmw_dir (mwstate diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index 8ea9cfd7f..d23f1a235 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -25,7 +25,7 @@ namespace MWGui { void EffectSourceVisitor::visit (MWMechanics::EffectKey key, - const std::string& sourceName, int casterActorId, + const std::string& sourceName, const std::string& sourceId, int casterActorId, float magnitude, float remainingTime, float totalTime) { MagicEffectInfo newEffectSource; diff --git a/apps/openmw/mwgui/spellicons.hpp b/apps/openmw/mwgui/spellicons.hpp index e9d9967ea..5099fc4d6 100644 --- a/apps/openmw/mwgui/spellicons.hpp +++ b/apps/openmw/mwgui/spellicons.hpp @@ -47,7 +47,7 @@ namespace MWGui virtual ~EffectSourceVisitor() {} virtual void visit (MWMechanics::EffectKey key, - const std::string& sourceName, int casterActorId, + const std::string& sourceName, const std::string& sourceId, int casterActorId, float magnitude, float remainingTime = -1, float totalTime = -1); }; diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index 717a63be8..6e15449e1 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -195,7 +195,7 @@ namespace MWMechanics float magnitude = effectIt->mMagnitude; if (magnitude) - visitor.visit(MWMechanics::EffectKey(effectIt->mEffectId, effectIt->mArg), name, it->second.mCasterActorId, magnitude, remainingTime, effectIt->mDuration); + visitor.visit(MWMechanics::EffectKey(effectIt->mEffectId, effectIt->mArg), name, it->first, it->second.mCasterActorId, magnitude, remainingTime, effectIt->mDuration); } } } @@ -229,6 +229,22 @@ namespace MWMechanics mSpellsChanged = true; } + void ActiveSpells::purgeEffect(short effectId, const std::string& sourceId) + { + for (TContainer::iterator it = mSpells.begin(); it != mSpells.end(); ++it) + { + for (std::vector::iterator effectIt = it->second.mEffects.begin(); + effectIt != it->second.mEffects.end();) + { + if (effectIt->mEffectId == effectId && it->first == sourceId) + effectIt = it->second.mEffects.erase(effectIt); + else + ++effectIt; + } + } + mSpellsChanged = true; + } + void ActiveSpells::purge(int casterActorId) { for (TContainer::iterator it = mSpells.begin(); it != mSpells.end(); ++it) diff --git a/apps/openmw/mwmechanics/activespells.hpp b/apps/openmw/mwmechanics/activespells.hpp index 9c1a5e613..4f9d15d8c 100644 --- a/apps/openmw/mwmechanics/activespells.hpp +++ b/apps/openmw/mwmechanics/activespells.hpp @@ -82,6 +82,9 @@ namespace MWMechanics /// Remove all active effects with this effect id void purgeEffect (short effectId); + /// Remove all active effects with this effect id and source id + void purgeEffect (short effectId, const std::string& sourceId); + /// Remove all active effects, if roll succeeds (for each effect) void purgeAll (float chance); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 1055e0f4a..c0fc80692 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -36,6 +36,7 @@ #include "aipursue.hpp" #include "actor.hpp" +#include "summoning.hpp" namespace { @@ -105,7 +106,7 @@ public: , mCommanded(false){} virtual void visit (MWMechanics::EffectKey key, - const std::string& sourceName, int casterActorId, + const std::string& sourceName, const std::string& sourceId, int casterActorId, float magnitude, float remainingTime = -1, float totalTime = -1) { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); @@ -165,30 +166,6 @@ void getRestorationPerHourOfSleep (const MWWorld::Ptr& ptr, float& health, float } } -void cleanupSummonedCreature (MWMechanics::CreatureStats& casterStats, int creatureActorId) -{ - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaActorId(creatureActorId); - if (!ptr.isEmpty()) - { - // TODO: Show death animation before deleting? We shouldn't allow looting the corpse while the animation - // plays though, which is a rather lame exploit in vanilla. - MWBase::Environment::get().getWorld()->deleteObject(ptr); - - const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get() - .search("VFX_Summon_End"); - if (fx) - MWBase::Environment::get().getWorld()->spawnEffect("meshes\\" + fx->mModel, - "", Ogre::Vector3(ptr.getRefData().getPosition().pos)); - } - else - { - // We didn't find the creature. It's probably in an inactive cell. - // Add to graveyard so we can delete it when the cell becomes active. - std::vector& graveyard = casterStats.getSummonedCreatureGraveyard(); - graveyard.push_back(creatureActorId); - } -} - } namespace MWMechanics @@ -203,7 +180,7 @@ namespace MWMechanics : mCreature(trappedCreature) {} virtual void visit (MWMechanics::EffectKey key, - const std::string& sourceName, int casterActorId, + const std::string& sourceName, const std::string& sourceId, int casterActorId, float magnitude, float remainingTime = -1, float totalTime = -1) { if (key.mId != ESM::MagicEffect::Soultrap) @@ -782,131 +759,11 @@ namespace MWMechanics } } - // Update summon effects - static std::map summonMap; - if (summonMap.empty()) - { - summonMap[ESM::MagicEffect::SummonAncestralGhost] = "sMagicAncestralGhostID"; - summonMap[ESM::MagicEffect::SummonBonelord] = "sMagicBonelordID"; - summonMap[ESM::MagicEffect::SummonBonewalker] = "sMagicLeastBonewalkerID"; - summonMap[ESM::MagicEffect::SummonCenturionSphere] = "sMagicCenturionSphereID"; - summonMap[ESM::MagicEffect::SummonClannfear] = "sMagicClannfearID"; - summonMap[ESM::MagicEffect::SummonDaedroth] = "sMagicDaedrothID"; - summonMap[ESM::MagicEffect::SummonDremora] = "sMagicDremoraID"; - summonMap[ESM::MagicEffect::SummonFabricant] = "sMagicFabricantID"; - summonMap[ESM::MagicEffect::SummonFlameAtronach] = "sMagicFlameAtronachID"; - summonMap[ESM::MagicEffect::SummonFrostAtronach] = "sMagicFrostAtronachID"; - summonMap[ESM::MagicEffect::SummonGoldenSaint] = "sMagicGoldenSaintID"; - summonMap[ESM::MagicEffect::SummonGreaterBonewalker] = "sMagicGreaterBonewalkerID"; - summonMap[ESM::MagicEffect::SummonHunger] = "sMagicHungerID"; - summonMap[ESM::MagicEffect::SummonScamp] = "sMagicScampID"; - summonMap[ESM::MagicEffect::SummonSkeletalMinion] = "sMagicSkeletalMinionID"; - summonMap[ESM::MagicEffect::SummonStormAtronach] = "sMagicStormAtronachID"; - summonMap[ESM::MagicEffect::SummonWingedTwilight] = "sMagicWingedTwilightID"; - summonMap[ESM::MagicEffect::SummonWolf] = "sMagicCreature01ID"; - summonMap[ESM::MagicEffect::SummonBear] = "sMagicCreature02ID"; - summonMap[ESM::MagicEffect::SummonBonewolf] = "sMagicCreature03ID"; - summonMap[ESM::MagicEffect::SummonCreature04] = "sMagicCreature04ID"; - summonMap[ESM::MagicEffect::SummonCreature05] = "sMagicCreature05ID"; - } - - std::map& creatureMap = creatureStats.getSummonedCreatureMap(); - for (std::map::iterator it = summonMap.begin(); it != summonMap.end(); ++it) - { - bool found = creatureMap.find(it->first) != creatureMap.end(); - int magnitude = creatureStats.getMagicEffects().get(it->first).getMagnitude(); - if (found != (magnitude > 0)) - { - if (magnitude > 0) - { - ESM::Position ipos = ptr.getRefData().getPosition(); - Ogre::Vector3 pos(ipos.pos); - Ogre::Quaternion rot(Ogre::Radian(-ipos.rot[2]), Ogre::Vector3::UNIT_Z); - const float distance = 50; - pos = pos + distance*rot.yAxis(); - ipos.pos[0] = pos.x; - ipos.pos[1] = pos.y; - ipos.pos[2] = pos.z; - ipos.rot[0] = 0; - ipos.rot[1] = 0; - ipos.rot[2] = 0; - - std::string creatureID = - MWBase::Environment::get().getWorld()->getStore().get().find(it->second)->getString(); - - if (!creatureID.empty()) - { - MWWorld::CellStore* store = ptr.getCell(); - MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), creatureID, 1); - ref.getPtr().getCellRef().setPosition(ipos); - - MWMechanics::CreatureStats& summonedCreatureStats = ref.getPtr().getClass().getCreatureStats(ref.getPtr()); - - // Make the summoned creature follow its master and help in fights - AiFollow package(ptr.getCellRef().getRefId()); - summonedCreatureStats.getAiSequence().stack(package, ref.getPtr()); - int creatureActorId = summonedCreatureStats.getActorId(); - - MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos); - - MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(placed); - if (anim) - { - const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get() - .search("VFX_Summon_Start"); - if (fx) - anim->addEffect("meshes\\" + fx->mModel, -1, false); - } - - creatureMap.insert(std::make_pair(it->first, creatureActorId)); - } - } - else - { - // Effect has ended - std::map::iterator foundCreature = creatureMap.find(it->first); - cleanupSummonedCreature(creatureStats, foundCreature->second); - creatureMap.erase(foundCreature); - } - } - } - - for (std::map::iterator it = creatureMap.begin(); it != creatureMap.end(); ) - { - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaActorId(it->second); - if (!ptr.isEmpty() && ptr.getClass().getCreatureStats(ptr).isDead()) - { - // Purge the magic effect so a new creature can be summoned if desired - creatureStats.getActiveSpells().purgeEffect(it->first); - if (ptr.getClass().hasInventoryStore(ptr)) - ptr.getClass().getInventoryStore(ptr).purgeEffect(it->first); - - cleanupSummonedCreature(creatureStats, it->second); - creatureMap.erase(it++); - } - else - ++it; - } - - std::vector& graveyard = creatureStats.getSummonedCreatureGraveyard(); - for (std::vector::iterator it = graveyard.begin(); it != graveyard.end(); ) - { - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaActorId(*it); - if (!ptr.isEmpty()) - { - it = graveyard.erase(it); - - const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get() - .search("VFX_Summon_End"); - if (fx) - MWBase::Environment::get().getWorld()->spawnEffect("meshes\\" + fx->mModel, - "", Ogre::Vector3(ptr.getRefData().getPosition().pos)); - - MWBase::Environment::get().getWorld()->deleteObject(ptr); - } - else - ++it; - } + UpdateSummonedCreatures updateSummonedCreatures(ptr); + creatureStats.getActiveSpells().visitEffectSources(updateSummonedCreatures); + if (ptr.getClass().hasInventoryStore(ptr)) + ptr.getClass().getInventoryStore(ptr).visitEffectSources(updateSummonedCreatures); + updateSummonedCreatures.finish(); } void Actors::calculateNpcStatModifiers (const MWWorld::Ptr& ptr, float duration) diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index ac6f88d44..c61cc9697 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -638,7 +638,7 @@ namespace MWMechanics mDeathAnimation = index; } - std::map& CreatureStats::getSummonedCreatureMap() + std::map& CreatureStats::getSummonedCreatureMap() { return mSummonedCreatures; } diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 9a08b58c9..145eb8a5b 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -67,8 +67,11 @@ namespace MWMechanics // The index of the death animation that was played unsigned char mDeathAnimation; - // - std::map mSummonedCreatures; + public: + typedef std::pair SummonKey; // + private: + std::map mSummonedCreatures; // + // Contains ActorIds of summoned creatures with an expired lifetime that have not been deleted yet. // This may be necessary when the creature is in an inactive cell. std::vector mSummonGraveyard; @@ -216,8 +219,8 @@ namespace MWMechanics void setBlock(bool value); bool getBlock() const; - std::map& getSummonedCreatureMap(); - std::vector& getSummonedCreatureGraveyard(); + std::map& getSummonedCreatureMap(); // + std::vector& getSummonedCreatureGraveyard(); // ActorIds enum Flag { diff --git a/apps/openmw/mwmechanics/magiceffects.hpp b/apps/openmw/mwmechanics/magiceffects.hpp index 88d8d988f..c384d0857 100644 --- a/apps/openmw/mwmechanics/magiceffects.hpp +++ b/apps/openmw/mwmechanics/magiceffects.hpp @@ -73,7 +73,7 @@ namespace MWMechanics struct EffectSourceVisitor { virtual void visit (MWMechanics::EffectKey key, - const std::string& sourceName, int casterActorId, + const std::string& sourceName, const std::string& sourceId, int casterActorId, float magnitude, float remainingTime = -1, float totalTime = -1) = 0; }; diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 58ccd389a..9cfcdda18 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -21,6 +21,7 @@ #include "magiceffects.hpp" #include "npcstats.hpp" +#include "summoning.hpp" namespace { diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index 5953be523..1f8ada06d 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -249,7 +249,7 @@ namespace MWMechanics random = it->second.at(i); float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random; - visitor.visit(MWMechanics::EffectKey(*effectIt), spell->mName, -1, magnitude); + visitor.visit(MWMechanics::EffectKey(*effectIt), spell->mName, spell->mId, -1, magnitude); } } } diff --git a/apps/openmw/mwmechanics/summoning.cpp b/apps/openmw/mwmechanics/summoning.cpp new file mode 100644 index 000000000..356cb422f --- /dev/null +++ b/apps/openmw/mwmechanics/summoning.cpp @@ -0,0 +1,195 @@ +#include "summoning.hpp" + +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +#include "../mwworld/esmstore.hpp" +#include "../mwworld/class.hpp" +#include "../mwworld/manualref.hpp" +#include "../mwworld/inventorystore.hpp" + +#include "../mwrender/animation.hpp" + +#include "creaturestats.hpp" +#include "aifollow.hpp" + + +namespace MWMechanics +{ + + void cleanupSummonedCreature (MWMechanics::CreatureStats& casterStats, int creatureActorId) + { + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaActorId(creatureActorId); + if (!ptr.isEmpty()) + { + // TODO: Show death animation before deleting? We shouldn't allow looting the corpse while the animation + // plays though, which is a rather lame exploit in vanilla. + MWBase::Environment::get().getWorld()->deleteObject(ptr); + + const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get() + .search("VFX_Summon_End"); + if (fx) + MWBase::Environment::get().getWorld()->spawnEffect("meshes\\" + fx->mModel, + "", Ogre::Vector3(ptr.getRefData().getPosition().pos)); + } + else + { + // We didn't find the creature. It's probably in an inactive cell. + // Add to graveyard so we can delete it when the cell becomes active. + std::vector& graveyard = casterStats.getSummonedCreatureGraveyard(); + graveyard.push_back(creatureActorId); + } + } + + UpdateSummonedCreatures::UpdateSummonedCreatures(const MWWorld::Ptr &actor) + : mActor(actor) + { + + } + + void UpdateSummonedCreatures::visit(EffectKey key, const std::string &sourceName, const std::string &sourceId, int casterActorId, float magnitude, float remainingTime, float totalTime) + { + if (key.mId >= ESM::MagicEffect::SummonScamp + && key.mId <= ESM::MagicEffect::SummonStormAtronach && magnitude > 0) + { + mActiveEffects.insert(std::make_pair(key.mId, sourceId)); + } + } + + void UpdateSummonedCreatures::finish() + { + static std::map summonMap; + if (summonMap.empty()) + { + summonMap[ESM::MagicEffect::SummonAncestralGhost] = "sMagicAncestralGhostID"; + summonMap[ESM::MagicEffect::SummonBonelord] = "sMagicBonelordID"; + summonMap[ESM::MagicEffect::SummonBonewalker] = "sMagicLeastBonewalkerID"; + summonMap[ESM::MagicEffect::SummonCenturionSphere] = "sMagicCenturionSphereID"; + summonMap[ESM::MagicEffect::SummonClannfear] = "sMagicClannfearID"; + summonMap[ESM::MagicEffect::SummonDaedroth] = "sMagicDaedrothID"; + summonMap[ESM::MagicEffect::SummonDremora] = "sMagicDremoraID"; + summonMap[ESM::MagicEffect::SummonFabricant] = "sMagicFabricantID"; + summonMap[ESM::MagicEffect::SummonFlameAtronach] = "sMagicFlameAtronachID"; + summonMap[ESM::MagicEffect::SummonFrostAtronach] = "sMagicFrostAtronachID"; + summonMap[ESM::MagicEffect::SummonGoldenSaint] = "sMagicGoldenSaintID"; + summonMap[ESM::MagicEffect::SummonGreaterBonewalker] = "sMagicGreaterBonewalkerID"; + summonMap[ESM::MagicEffect::SummonHunger] = "sMagicHungerID"; + summonMap[ESM::MagicEffect::SummonScamp] = "sMagicScampID"; + summonMap[ESM::MagicEffect::SummonSkeletalMinion] = "sMagicSkeletalMinionID"; + summonMap[ESM::MagicEffect::SummonStormAtronach] = "sMagicStormAtronachID"; + summonMap[ESM::MagicEffect::SummonWingedTwilight] = "sMagicWingedTwilightID"; + summonMap[ESM::MagicEffect::SummonWolf] = "sMagicCreature01ID"; + summonMap[ESM::MagicEffect::SummonBear] = "sMagicCreature02ID"; + summonMap[ESM::MagicEffect::SummonBonewolf] = "sMagicCreature03ID"; + summonMap[ESM::MagicEffect::SummonCreature04] = "sMagicCreature04ID"; + summonMap[ESM::MagicEffect::SummonCreature05] = "sMagicCreature05ID"; + } + + MWMechanics::CreatureStats& creatureStats = mActor.getClass().getCreatureStats(mActor); + + // Update summon effects + std::map& creatureMap = creatureStats.getSummonedCreatureMap(); + for (std::map::iterator it = creatureMap.begin(); it != creatureMap.end(); ) + { + bool found = mActiveEffects.find(it->first) != mActiveEffects.end(); + if (!found) + { + // Effect has ended + cleanupSummonedCreature(creatureStats, it->second); + creatureMap.erase(it++); + continue; + } + ++it; + } + + for (std::set >::iterator it = mActiveEffects.begin(); it != mActiveEffects.end(); ++it) + { + bool found = creatureMap.find(std::make_pair(it->first, it->second)) != creatureMap.end(); + if (!found) + { + ESM::Position ipos = mActor.getRefData().getPosition(); + Ogre::Vector3 pos(ipos.pos); + Ogre::Quaternion rot(Ogre::Radian(-ipos.rot[2]), Ogre::Vector3::UNIT_Z); + const float distance = 50; + pos = pos + distance*rot.yAxis(); + ipos.pos[0] = pos.x; + ipos.pos[1] = pos.y; + ipos.pos[2] = pos.z; + ipos.rot[0] = 0; + ipos.rot[1] = 0; + ipos.rot[2] = 0; + + const std::string& creatureGmst = summonMap[it->first]; + std::string creatureID = + MWBase::Environment::get().getWorld()->getStore().get().find(creatureGmst)->getString(); + + if (!creatureID.empty()) + { + MWWorld::CellStore* store = mActor.getCell(); + MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), creatureID, 1); + ref.getPtr().getCellRef().setPosition(ipos); + + MWMechanics::CreatureStats& summonedCreatureStats = ref.getPtr().getClass().getCreatureStats(ref.getPtr()); + + // Make the summoned creature follow its master and help in fights + AiFollow package(mActor.getCellRef().getRefId()); + summonedCreatureStats.getAiSequence().stack(package, ref.getPtr()); + int creatureActorId = summonedCreatureStats.getActorId(); + + MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos); + + MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(placed); + if (anim) + { + const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get() + .search("VFX_Summon_Start"); + if (fx) + anim->addEffect("meshes\\" + fx->mModel, -1, false); + } + + creatureMap.insert(std::make_pair(*it, creatureActorId)); + } + } + } + + for (std::map::iterator it = creatureMap.begin(); it != creatureMap.end(); ) + { + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaActorId(it->second); + if (!ptr.isEmpty() && ptr.getClass().getCreatureStats(ptr).isDead()) + { + // Purge the magic effect so a new creature can be summoned if desired + creatureStats.getActiveSpells().purgeEffect(it->first.first, it->first.second); + if (mActor.getClass().hasInventoryStore(ptr)) + mActor.getClass().getInventoryStore(mActor).purgeEffect(it->first.first, it->first.second); + + cleanupSummonedCreature(creatureStats, it->second); + creatureMap.erase(it++); + } + else + ++it; + } + + std::vector& graveyard = creatureStats.getSummonedCreatureGraveyard(); + for (std::vector::iterator it = graveyard.begin(); it != graveyard.end(); ) + { + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaActorId(*it); + if (!ptr.isEmpty()) + { + it = graveyard.erase(it); + + const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get() + .search("VFX_Summon_End"); + if (fx) + MWBase::Environment::get().getWorld()->spawnEffect("meshes\\" + fx->mModel, + "", Ogre::Vector3(ptr.getRefData().getPosition().pos)); + + MWBase::Environment::get().getWorld()->deleteObject(ptr); + } + else + ++it; + } + } + +} diff --git a/apps/openmw/mwmechanics/summoning.hpp b/apps/openmw/mwmechanics/summoning.hpp new file mode 100644 index 000000000..b8fe37783 --- /dev/null +++ b/apps/openmw/mwmechanics/summoning.hpp @@ -0,0 +1,35 @@ +#ifndef OPENMW_MECHANICS_SUMMONING_H +#define OPENMW_MECHANICS_SUMMONING_H + +#include + +#include "magiceffects.hpp" +#include "../mwworld/ptr.hpp" + +namespace MWMechanics +{ + + class CreatureStats; + + struct UpdateSummonedCreatures : public EffectSourceVisitor + { + UpdateSummonedCreatures(const MWWorld::Ptr& actor); + + virtual void visit (MWMechanics::EffectKey key, + const std::string& sourceName, const std::string& sourceId, int casterActorId, + float magnitude, float remainingTime = -1, float totalTime = -1); + + /// To call after all effect sources have been visited + void finish(); + + private: + MWWorld::Ptr mActor; + + std::set > mActiveEffects; + }; + + void cleanupSummonedCreature (MWMechanics::CreatureStats& casterStats, int creatureActorId); + +} + +#endif diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 9c329ce72..445b42d8d 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -583,7 +583,8 @@ void MWWorld::InventoryStore::visitEffectSources(MWMechanics::EffectSourceVisito const EffectParams& params = mPermanentMagicEffectMagnitudes[(**iter).getCellRef().getRefId()][i]; float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params.mRandom; magnitude *= params.mMultiplier; - visitor.visit(MWMechanics::EffectKey(*effectIt), (**iter).getClass().getName(**iter), -1, magnitude); + if (magnitude > 0) + visitor.visit(MWMechanics::EffectKey(*effectIt), (**iter).getClass().getName(**iter), (**iter).getCellRef().getRefId(), -1, magnitude); ++i; } @@ -639,6 +640,52 @@ void MWWorld::InventoryStore::purgeEffect(short effectId) mMagicEffects.remove(MWMechanics::EffectKey(effectId)); } +void MWWorld::InventoryStore::purgeEffect(short effectId, const std::string &sourceId) +{ + TEffectMagnitudes::iterator effectMagnitudeIt = mPermanentMagicEffectMagnitudes.find(sourceId); + if (effectMagnitudeIt == mPermanentMagicEffectMagnitudes.end()) + return; + + for (TSlots::const_iterator iter (mSlots.begin()); iter!=mSlots.end(); ++iter) + { + if (*iter==end()) + continue; + + if ((*iter)->getClass().getId(**iter) != sourceId) + continue; + + std::string enchantmentId = (*iter)->getClass().getEnchantment (**iter); + + if (!enchantmentId.empty()) + { + const ESM::Enchantment& enchantment = + *MWBase::Environment::get().getWorld()->getStore().get().find (enchantmentId); + + if (enchantment.mData.mType != ESM::Enchantment::ConstantEffect) + continue; + + std::vector& params = effectMagnitudeIt->second; + + int i=0; + for (std::vector::const_iterator effectIt (enchantment.mEffects.mList.begin()); + effectIt!=enchantment.mEffects.mList.end(); ++effectIt, ++i) + { + if (effectIt->mEffectID != effectId) + continue; + + float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params[i].mRandom; + magnitude *= params[i].mMultiplier; + + if (magnitude) + mMagicEffects.add (*effectIt, -magnitude); + + params[i].mMultiplier = 0; + break; + } + } + } +} + void MWWorld::InventoryStore::clear() { mSlots.clear(); diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 48742b557..9fd18c54b 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -203,6 +203,9 @@ namespace MWWorld void purgeEffect (short effectId); ///< Remove a magic effect + void purgeEffect (short effectId, const std::string& sourceId); + ///< Remove a magic effect + virtual void clear(); ///< Empty container. diff --git a/components/esm/creaturestats.cpp b/components/esm/creaturestats.cpp index cc76ef0df..1fdce703c 100644 --- a/components/esm/creaturestats.cpp +++ b/components/esm/creaturestats.cpp @@ -94,9 +94,10 @@ void ESM::CreatureStats::load (ESMReader &esm) { int magicEffect; esm.getHT(magicEffect); + std::string source = esm.getHNOString("SOUR"); int actorId; esm.getHNT (actorId, "ACID"); - mSummonedCreatureMap[magicEffect] = actorId; + mSummonedCreatureMap[std::make_pair(magicEffect, source)] = actorId; } while (esm.isNextSub("GRAV")) @@ -204,9 +205,10 @@ void ESM::CreatureStats::save (ESMWriter &esm) const mAiSequence.save(esm); mMagicEffects.save(esm); - for (std::map::const_iterator it = mSummonedCreatureMap.begin(); it != mSummonedCreatureMap.end(); ++it) + for (std::map, int>::const_iterator it = mSummonedCreatureMap.begin(); it != mSummonedCreatureMap.end(); ++it) { - esm.writeHNT ("SUMM", it->first); + esm.writeHNT ("SUMM", it->first.first); + esm.writeHNString ("SOUR", it->first.second); esm.writeHNT ("ACID", it->second); } diff --git a/components/esm/creaturestats.hpp b/components/esm/creaturestats.hpp index 7946d0e45..680577f93 100644 --- a/components/esm/creaturestats.hpp +++ b/components/esm/creaturestats.hpp @@ -32,7 +32,7 @@ namespace ESM bool mHasAiSettings; StatState mAiSettings[4]; - std::map mSummonedCreatureMap; + std::map, int> mSummonedCreatureMap; std::vector mSummonGraveyard; ESM::TimeStamp mTradeTime; From 992b87ea441de3be8c673f300532f902330c0dda Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 6 Jan 2015 16:08:23 +0100 Subject: [PATCH 114/740] Reset existing summons when the spell is re-casted (Fixes #2135) --- apps/openmw/mwmechanics/spellcasting.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 9cfcdda18..b7c7e00a1 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -471,6 +471,20 @@ namespace MWMechanics else applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude); + // Re-casting a summon effect will remove the creature from previous castings of that effect. + if (effectIt->mEffectID >= ESM::MagicEffect::SummonScamp + && effectIt->mEffectID <= ESM::MagicEffect::SummonStormAtronach + && !target.isEmpty() && target.getClass().isActor()) + { + CreatureStats& targetStats = target.getClass().getCreatureStats(target); + std::map::iterator found = targetStats.getSummonedCreatureMap().find(std::make_pair(effectIt->mEffectID, mId)); + if (found != targetStats.getSummonedCreatureMap().end()) + { + cleanupSummonedCreature(targetStats, found->second); + targetStats.getSummonedCreatureMap().erase(found); + } + } + // HACK: Damage attribute/skill actually has a duration, even though the actual effect is instant and permanent. // This was probably just done to have the effect visible in the magic menu for a while // to notify the player they've been damaged? From c6c7d102d0171c1f0daedc8fa0435cb913bc7b13 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 6 Jan 2015 23:35:40 +0100 Subject: [PATCH 115/740] Revert "components/nif/base.hpp now uses the templated get() function" This reverts commit ad609bff7822abffc76de9ae01b50cb9df97b093. Revert "Made incorrect nif get error message more informative." This reverts commit 9909c4abadbe4c0aedc24a50155908c5e7e39b13. Revert "Build the nif file tester by default" This reverts commit c1315ed90c87a457f17e6076c149465da3fa6c3a. Revert "Converted most nifstream "get multiple" functions to the templated version" This reverts commit 2619d57bb6afc5c31bf1a90b8c033d66f29a9a58. Revert "Add a templated option for getting vectors to NIFStream" This reverts commit f318ee0b8c68a46d53a0fdd216ae8d6b371eedc2. Revert "Made NIFStream getters templated" This reverts commit 4edc4142f3b4f1cde4d99392045d5d25858e6bf7. --- CMakeLists.txt | 2 +- components/nif/base.hpp | 12 +++---- components/nif/data.hpp | 16 ++++----- components/nif/nifstream.cpp | 64 ++++++++++++++++++++---------------- components/nif/nifstream.hpp | 25 ++++---------- components/nif/tests/test.sh | 2 +- 6 files changed, 58 insertions(+), 63 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fb89f4e91..d7c85818e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,7 +82,7 @@ option(BUILD_OPENCS "build OpenMW Construction Set" ON) option(BUILD_WIZARD "build Installation Wizard" ON) option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF) option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest and GMock frameworks" OFF) -option(BUILD_NIFTEST "build nif file tester" ON) +option(BUILD_NIFTEST "build nif file tester" OFF) option(BUILD_MYGUI_PLUGIN "build MyGUI plugin for OpenMW resources, to use with MyGUI tools" ON) # OS X deployment diff --git a/components/nif/base.hpp b/components/nif/base.hpp index 031000bcc..30c652b64 100644 --- a/components/nif/base.hpp +++ b/components/nif/base.hpp @@ -36,12 +36,12 @@ public: { next.read(nif); - flags = nif->get(); + flags = nif->getUShort(); - frequency = nif->get(); - phase = nif->get(); - timeStart = nif->get(); - timeStop = nif->get(); + frequency = nif->getFloat(); + phase = nif->getFloat(); + timeStart = nif->getFloat(); + timeStop = nif->getFloat(); target.read(nif); } @@ -81,7 +81,7 @@ public: void read(NIFStream *nif) { - name = nif->get(); + name = nif->getString(); Controlled::read(nif); } }; diff --git a/components/nif/data.hpp b/components/nif/data.hpp index e6d3370be..d9de12fb5 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -44,16 +44,16 @@ public: int verts = nif->getUShort(); if(nif->getInt()) - vertices = nif->getItems(verts); + nif->getVector3s(vertices, verts); if(nif->getInt()) - normals = nif->getItems(verts); + nif->getVector3s(normals, verts); center = nif->getVector3(); radius = nif->getFloat(); if(nif->getInt()) - colors = nif->getItems(verts); + nif->getVector4s(colors, verts); // Only the first 6 bits are used as a count. I think the rest are // flags of some sort. @@ -64,7 +64,7 @@ public: { uvlist.resize(uvs); for(int i = 0;i < uvs;i++) - uvlist[i] = nif->getItems(verts); + nif->getVector2s(uvlist[i], verts); } } }; @@ -84,7 +84,7 @@ public: // We have three times as many vertices as triangles, so this // is always equal to tris*3. int cnt = nif->getInt(); - triangles = nif->getItems(cnt); + nif->getShorts(triangles, cnt); // Read the match list, which lists the vertices that are equal to // vertices. We don't actually need need this for anything, so @@ -123,7 +123,7 @@ public: if(nif->getInt()) { // Particle sizes - sizes = nif->getItems(vertices.size()); + nif->getFloats(sizes, vertices.size()); } } }; @@ -140,7 +140,7 @@ public: if(nif->getInt()) { // Rotation quaternions. - rotations = nif->getItems(vertices.size()); + nif->getQuaternions(rotations, vertices.size()); } } }; @@ -341,7 +341,7 @@ struct NiMorphData : public Record for(int i = 0;i < morphCount;i++) { mMorphs[i].mData.read(nif, true); - mMorphs[i].mVertices = nif->getItems(vertCount); + nif->getVector3s(mMorphs[i].mVertices, vertCount); } } }; diff --git a/components/nif/nifstream.cpp b/components/nif/nifstream.cpp index 9eeee6a12..e5699db7b 100644 --- a/components/nif/nifstream.cpp +++ b/components/nif/nifstream.cpp @@ -106,33 +106,41 @@ std::string NIFStream::getVersionString() return inp->getLine(); } -template <> -char NIFStream::get(){ return getChar(); } -template <> -short NIFStream::get(){ return getShort(); } -template <> -unsigned short NIFStream::get(){ return getUShort(); } -template <> -int NIFStream::get(){ return getInt(); } -template <> -unsigned int NIFStream::get(){ return getUInt(); } -template <> -float NIFStream::get(){ return getFloat(); } - -template <> -Ogre::Vector2 NIFStream::get(){ return getVector2(); } -template <> -Ogre::Vector3 NIFStream::get(){ return getVector3(); } -template <> -Ogre::Vector4 NIFStream::get(){ return getVector4(); } -template <> -Ogre::Matrix3 NIFStream::get(){ return getMatrix3(); } -template <> -Ogre::Quaternion NIFStream::get(){ return getQuaternion(); } -template <> -Transformation NIFStream::get(){ return getTrafo(); } - -template <> -std::string NIFStream::get(){ return getString(); } +void NIFStream::getShorts(std::vector &vec, size_t size) +{ + vec.resize(size); + for(size_t i = 0;i < vec.size();i++) + vec[i] = getShort(); +} +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(); +} } diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index 0f9ec9085..cc14971fd 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -5,8 +5,6 @@ #include #include -#include -#include #include #include @@ -86,23 +84,12 @@ public: ///This is special since the version string doesn't start with a number, and ends with "\n" std::string getVersionString(); - //Templated functions to handle reads - template - T get(){throw std::runtime_error("Can not read a <"+std::string(typeid(T).name())+"> from a NIF File! The get() function was called with the wrong template!");} - - ///Return a vector of whatever object is needed - template - std::vector getItems(size_t number_of_items) - { - std::vector items; - items.reserve(number_of_items); - for(size_t i=0; i < number_of_items; ++i) - { - items.push_back(get()); - } - return items; - } - + void getShorts(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); }; } diff --git a/components/nif/tests/test.sh b/components/nif/tests/test.sh index 424e27b07..95ecdbfba 100755 --- a/components/nif/tests/test.sh +++ b/components/nif/tests/test.sh @@ -9,7 +9,7 @@ find "$DATAFILESDIR" -iname *nif >> nifs.txt sed -e 's/.*/\"&\"/' nifs.txt > quoted_nifs.txt -nice -n 10 xargs --arg-file=quoted_nifs.txt ../../../niftest +xargs --arg-file=quoted_nifs.txt ../../../niftest rm nifs.txt rm quoted_nifs.txt From e19ab77d00301108d06307142e201b4f6edbd813 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 6 Jan 2015 19:29:33 +0100 Subject: [PATCH 116/740] Store camera first person state in savegame (Fixes #2255) --- apps/openmw/mwstate/statemanagerimp.cpp | 3 +++ apps/openmw/mwworld/worldimp.cpp | 16 ++++++++++++++-- components/esm/defs.hpp | 1 + 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index f77a90d8e..30dba2aaa 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -355,6 +355,7 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl case ESM::REC_ENAB: case ESM::REC_LEVC: case ESM::REC_LEVI: + case ESM::REC_CAM_: MWBase::Environment::get().getWorld()->readRecord (reader, n.val, contentFileMap); break; @@ -406,6 +407,8 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl // Use detectWorldSpaceChange=false, otherwise some of the data we just loaded would be cleared again MWBase::Environment::get().getWorld()->changeToCell (cellId, ptr.getRefData().getPosition(), false); + // Vanilla MW will restart startup scripts when a save game is loaded. This is unintuive, + // but some mods may be using it as a reload detector. MWBase::Environment::get().getScriptManager()->getGlobalScripts().addStartup(); // Do not trigger erroneous cellChanged events diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1c9b8b996..a939a6db9 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -201,6 +201,7 @@ namespace MWWorld setupPlayer(); renderPlayer(); + mRendering->resetCamera(); MWBase::Environment::get().getWindowManager()->updatePlayer(); @@ -304,7 +305,8 @@ namespace MWWorld +1 // player record +1 // weather record +1 // actorId counter - +1; // levitation/teleport enabled state + +1 // levitation/teleport enabled state + +1; // camera } void World::write (ESM::ESMWriter& writer, Loading::Listener& progress) const @@ -333,6 +335,11 @@ namespace MWWorld writer.writeHNT("LEVT", mLevitationEnabled); writer.endRecord(ESM::REC_ENAB); progress.increaseProgress(); + + writer.startRecord(ESM::REC_CAM_); + writer.writeHNT("FIRS", isFirstPerson()); + writer.endRecord(ESM::REC_CAM_); + progress.increaseProgress(); } void World::readRecord (ESM::ESMReader& reader, int32_t type, @@ -347,6 +354,12 @@ namespace MWWorld reader.getHNT(mTeleportEnabled, "TELE"); reader.getHNT(mLevitationEnabled, "LEVT"); return; + case ESM::REC_CAM_: + bool firstperson; + reader.getHNT(firstperson, "FIRS"); + if (firstperson != isFirstPerson()) + togglePOV(); + break; default: if (!mStore.readRecord (reader, type) && !mGlobalVariables.readRecord (reader, type) && @@ -2073,7 +2086,6 @@ namespace MWWorld MWBase::Environment::get().getMechanicsManager()->add(mPlayer->getPlayer()); mPhysics->addActor(mPlayer->getPlayer()); - mRendering->resetCamera(); } int World::canRest () diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index d5ba919b0..fe45d6914 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -114,6 +114,7 @@ enum RecNameInts REC_DCOU = FourCC<'D','C','O','U'>::value, REC_MARK = FourCC<'M','A','R','K'>::value, REC_ENAB = FourCC<'E','N','A','B'>::value, + REC_CAM_ = FourCC<'C','A','M','_'>::value, // format 1 REC_FILT = 0x544C4946, From 4d9100091d3356dfadef0b55e83970da689ba406 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 6 Jan 2015 22:19:04 +0100 Subject: [PATCH 117/740] Reduce default pathing arrival tolerance to 32 units (Fixes #1605) --- apps/openmw/mwmechanics/aiwander.cpp | 2 +- apps/openmw/mwmechanics/pathfinding.cpp | 4 ++-- apps/openmw/mwmechanics/pathfinding.hpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 2df3762ab..94c4542f8 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -202,7 +202,7 @@ namespace MWMechanics // Are we there yet? bool& chooseAction = storage.mChooseAction; if(walking && - storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2])) + storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2], 64.f)) { stopWalking(actor, storage); moveNow = false; diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index f1279c415..f59167df7 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -297,13 +297,13 @@ namespace MWMechanics return false; } - bool PathFinder::checkPathCompleted(float x, float y, float z) + bool PathFinder::checkPathCompleted(float x, float y, float z, float tolerance) { if(mPath.empty()) return true; ESM::Pathgrid::Point nextPoint = *mPath.begin(); - if(sqrDistanceZCorrected(nextPoint, x, y, z) < 64*64) + if(sqrDistanceZCorrected(nextPoint, x, y, z) < tolerance*tolerance) { mPath.pop_front(); if(mPath.empty()) diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 482808dac..61008577c 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -39,8 +39,8 @@ namespace MWMechanics void buildPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint, const MWWorld::CellStore* cell, bool allowShortcuts = true); - bool checkPathCompleted(float x, float y, float z); - ///< \Returns true if the last point of the path has been reached. + bool checkPathCompleted(float x, float y, float z, float tolerance=32.f); + ///< \Returns true if we are within \a tolerance units of the last path point. bool checkWaypoint(float x, float y, float z); ///< \Returns true if a way point was reached From a17252eab3415d2b1d987ccc8c3a3ef3c1481b32 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 6 Jan 2015 23:23:58 +0100 Subject: [PATCH 118/740] Remove unused checkWaypoint function It was an almost exact copy of the checkPathCompleted function anyway. --- apps/openmw/mwmechanics/aicombat.cpp | 2 +- apps/openmw/mwmechanics/pathfinding.cpp | 15 --------------- apps/openmw/mwmechanics/pathfinding.hpp | 3 --- 3 files changed, 1 insertion(+), 19 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index a23634ea3..5d0470554 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -580,7 +580,7 @@ namespace MWMechanics buildNewPath(actor, target); //may fail to build a path, check before use //delete visited path node - mPathFinder.checkWaypoint(pos.pos[0],pos.pos[1],pos.pos[2]); + mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]); // This works on the borders between the path grid and areas with no waypoints. if(inLOS && mPathFinder.getPath().size() > 1) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index f59167df7..0634725a8 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -282,21 +282,6 @@ namespace MWMechanics return Ogre::Math::ATan2(directionX,directionY).valueDegrees(); } - bool PathFinder::checkWaypoint(float x, float y, float z) - { - if(mPath.empty()) - return true; - - ESM::Pathgrid::Point nextPoint = *mPath.begin(); - if(sqrDistanceZCorrected(nextPoint, x, y, z) < 64*64) - { - mPath.pop_front(); - if(mPath.empty()) mIsPathConstructed = false; - return true; - } - return false; - } - bool PathFinder::checkPathCompleted(float x, float y, float z, float tolerance) { if(mPath.empty()) diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 61008577c..7ba2d22ba 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -42,9 +42,6 @@ namespace MWMechanics bool checkPathCompleted(float x, float y, float z, float tolerance=32.f); ///< \Returns true if we are within \a tolerance units of the last path point. - bool checkWaypoint(float x, float y, float z); - ///< \Returns true if a way point was reached - float getZAngleToNext(float x, float y) const; bool isPathConstructed() const From d02e075bab885d805e8c6d7b994da75c69f69154 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 6 Jan 2015 23:54:53 +0100 Subject: [PATCH 119/740] Add setting for exterior cell grid size (Fixes #1537) --- apps/openmw/mwworld/scene.cpp | 16 +++++++++------- files/settings-default.cfg | 3 +++ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 02c9db9ea..efe88c406 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -296,15 +296,17 @@ namespace MWWorld std::string loadingExteriorText = "#{sLoadingMessage3}"; loadingListener->setLabel(loadingExteriorText); + const int halfGridSize = Settings::Manager::getInt("exterior grid size", "Cells")/2; + CellStoreCollection::iterator active = mActiveCells.begin(); while (active!=mActiveCells.end()) { if ((*active)->getCell()->isExterior()) { - if (std::abs (X-(*active)->getCell()->getGridX())<=1 && - std::abs (Y-(*active)->getCell()->getGridY())<=1) + if (std::abs (X-(*active)->getCell()->getGridX())<=halfGridSize && + std::abs (Y-(*active)->getCell()->getGridY())<=halfGridSize) { - // keep cells within the new 3x3 grid + // keep cells within the new grid ++active; continue; } @@ -314,9 +316,9 @@ namespace MWWorld int refsToLoad = 0; // get the number of refs to load - for (int x=X-1; x<=X+1; ++x) + for (int x=X-halfGridSize; x<=X+halfGridSize; ++x) { - for (int y=Y-1; y<=Y+1; ++y) + for (int y=Y-halfGridSize; y<=Y+halfGridSize; ++y) { CellStoreCollection::iterator iter = mActiveCells.begin(); @@ -339,9 +341,9 @@ namespace MWWorld loadingListener->setProgressRange(refsToLoad); // Load cells - for (int x=X-1; x<=X+1; ++x) + for (int x=X-halfGridSize; x<=X+halfGridSize; ++x) { - for (int y=Y-1; y<=Y+1; ++y) + for (int y=Y-halfGridSize; y<=Y+halfGridSize; ++y) { CellStoreCollection::iterator iter = mActiveCells.begin(); diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 6ec9b03e9..f91299a1f 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -123,6 +123,9 @@ local map resolution = 256 local map widget size = 512 local map hud widget size = 256 +[Cells] +exterior grid size = 3 + [Viewing distance] # Limit the rendering distance of small objects limit small object distance = false From dc5ed5b8613b9074ecc6a25e4a41b1825909abb6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 7 Jan 2015 01:11:39 +0100 Subject: [PATCH 120/740] Remove weather particles underwater (Fixes #2010) --- apps/openmw/mwrender/sky.cpp | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 761d3fd96..0b9dc091e 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -431,7 +432,10 @@ void SkyManager::updateRain(float dt) Ogre::Vector3 pos = it->first->getPosition(); pos.z -= mRainSpeed * dt; it->first->setPosition(pos); - if (pos.z < -minHeight) + if (pos.z < -minHeight + // Here we might want to add a "splash" effect later + || MWBase::Environment::get().getWorld()->isUnderwater( + MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(), it->first->_getDerivedPosition())) { it->second.setNull(); mSceneMgr->destroySceneNode(it->first); @@ -458,6 +462,12 @@ void SkyManager::updateRain(float dt) // Create a separate node to control the offset, since a node with setInheritOrientation(false) will still // consider the orientation of the parent node for its position, just not for its orientation float startHeight = 700; + Ogre::Vector3 worldPos = mParticleNode->_getDerivedPosition(); + worldPos += Ogre::Vector3(xOffs, yOffs, startHeight); + if (MWBase::Environment::get().getWorld()->isUnderwater( + MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(), worldPos)) + return; + Ogre::SceneNode* offsetNode = mParticleNode->createChildSceneNode(Ogre::Vector3(xOffs,yOffs,startHeight)); // Spawn a new rain object for each instance. @@ -490,6 +500,30 @@ void SkyManager::update(float duration) for (unsigned int i=0; imControllers.size(); ++i) mParticle->mControllers[i].update(); + for (unsigned int i=0; imParticles.size(); ++i) + { + Ogre::ParticleSystem* psys = mParticle->mParticles[i]; + Ogre::ParticleIterator pi = psys->_getIterator(); + while (!pi.end()) + { + Ogre::Particle *p = pi.getNext(); + #if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) + Ogre::Vector3 pos = p->mPosition; + Ogre::Real& timeToLive = p->mTimeToLive; + #else + Ogre::Vector3 pos = p->position; + Ogre::Real& timeToLive = p->timeToLive; + #endif + + if (psys->getKeepParticlesInLocalSpace() && psys->getParentNode()) + pos = psys->getParentNode()->convertLocalToWorldPosition(pos); + + if (MWBase::Environment::get().getWorld()->isUnderwater( + MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(), pos)) + timeToLive = 0; + } + } + if (mIsStorm) mParticleNode->setOrientation(Ogre::Vector3::UNIT_Y.getRotationTo(mStormDirection)); } From 157438460b1500ec2277d4f809b3fc383cba36d0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 7 Jan 2015 01:30:59 +0100 Subject: [PATCH 121/740] Fix being able to activate objects when paralyzed --- apps/openmw/engine.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 24e1388d0..c48f509b5 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -514,7 +514,8 @@ void OMW::Engine::activate() return; MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - if (player.getClass().getCreatureStats(player).getKnockedDown()) + if (player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0 + || player.getClass().getCreatureStats(player).getKnockedDown()) return; MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getFacedObject(); From 4e92f6ab48c5cefb5c4dc60d6ef8ee04fc2e6e70 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 7 Jan 2015 03:03:56 +0100 Subject: [PATCH 122/740] Add commandline option to load a save game on startup --- apps/openmw/engine.cpp | 13 +++++- apps/openmw/engine.hpp | 4 ++ apps/openmw/main.cpp | 4 ++ apps/openmw/mwbase/statemanager.hpp | 11 +++-- apps/openmw/mwgui/savegamedialog.cpp | 2 +- apps/openmw/mwstate/character.cpp | 5 +++ apps/openmw/mwstate/character.hpp | 6 +-- apps/openmw/mwstate/statemanagerimp.cpp | 53 ++++++++++++++++++++----- apps/openmw/mwstate/statemanagerimp.hpp | 11 +++-- 9 files changed, 85 insertions(+), 24 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 24e1388d0..43adedcee 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -472,9 +472,13 @@ void OMW::Engine::go() // Play some good 'ol tunes MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore")); - // start in main menu - if (!mSkipMenu) + if (!mSaveGameFile.empty()) + { + MWBase::Environment::get().getStateManager()->loadGame(mSaveGameFile); + } + else if (!mSkipMenu) { + // start in main menu MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); try { @@ -622,3 +626,8 @@ void OMW::Engine::enableFontExport(bool exportFonts) { mExportFonts = exportFonts; } + +void OMW::Engine::setSaveGameFile(const std::string &savegame) +{ + mSaveGameFile = savegame; +} diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 6cf31cba8..079dd922c 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -83,6 +83,7 @@ namespace OMW bool mScriptConsoleMode; std::string mStartupScript; int mActivationDistanceOverride; + std::string mSaveGameFile; // Grab mouse? bool mGrab; @@ -204,6 +205,9 @@ namespace OMW void enableFontExport(bool exportFonts); + /// Set the save game file to load after initialising the engine. + void setSaveGameFile(const std::string& savegame); + private: Files::ConfigurationManager& mCfgMgr; }; diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 9382e2516..74d434f63 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -152,6 +152,9 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("script-blacklist-use", bpo::value()->implicit_value(true) ->default_value(true), "enable script blacklisting") + ("load-savegame", bpo::value()->default_value(""), + "load a save game file on game startup") + ("skip-menu", bpo::value()->implicit_value(true) ->default_value(false), "skip main menu on game startup") @@ -274,6 +277,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat engine.setWarningsMode (variables["script-warn"].as()); engine.setScriptBlacklist (variables["script-blacklist"].as()); engine.setScriptBlacklistUse (variables["script-blacklist-use"].as()); + engine.setSaveGameFile (variables["load-savegame"].as()); // other settings engine.setSoundUsage(!variables["no-sound"].as()); diff --git a/apps/openmw/mwbase/statemanager.hpp b/apps/openmw/mwbase/statemanager.hpp index 006be921b..79ddbfa2a 100644 --- a/apps/openmw/mwbase/statemanager.hpp +++ b/apps/openmw/mwbase/statemanager.hpp @@ -62,10 +62,13 @@ namespace MWBase /// /// \note Slot must belong to the current character. - virtual void loadGame (const MWState::Character *character, const MWState::Slot *slot) = 0; - ///< Load a saved game file from \a slot. - /// - /// \note \a slot must belong to \a character. + virtual void loadGame (const std::string& filepath) = 0; + ///< Load a saved game directly from the given file path. This will search the CharacterManager + /// for a Character containing this save file, and set this Character current if one was found. + /// Otherwise, a new Character will be created. + + virtual void loadGame (const MWState::Character *character, const std::string& filepath) = 0; + ///< Load a saved game file belonging to the given character. ///Simple saver, writes over the file if already existing /** Used for quick save and autosave **/ diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 7b9777c81..3775f53dd 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -246,7 +246,7 @@ namespace MWGui else { assert (mCurrentCharacter && mCurrentSlot); - MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, mCurrentSlot); + MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, mCurrentSlot->mPath.string()); } } diff --git a/apps/openmw/mwstate/character.cpp b/apps/openmw/mwstate/character.cpp index f8fcfceec..c2ca5e095 100644 --- a/apps/openmw/mwstate/character.cpp +++ b/apps/openmw/mwstate/character.cpp @@ -190,3 +190,8 @@ ESM::SavedGame MWState::Character::getSignature() const return slot.mProfile; } + +const boost::filesystem::path& MWState::Character::getPath() const +{ + return mPath; +} diff --git a/apps/openmw/mwstate/character.hpp b/apps/openmw/mwstate/character.hpp index 4703f0cca..32c79a183 100644 --- a/apps/openmw/mwstate/character.hpp +++ b/apps/openmw/mwstate/character.hpp @@ -54,12 +54,12 @@ namespace MWState /// \attention The \a slot pointer will be invalidated by this call. SlotIterator begin() const; - ///< First slot is the most recent. Other slots follow in descending order of save date. - /// - /// Any call to createSlot and updateSlot can invalidate the returned iterator. + ///< Any call to createSlot and updateSlot can invalidate the returned iterator. SlotIterator end() const; + const boost::filesystem::path& getPath() const; + ESM::SavedGame getSignature() const; ///< Return signature information for this character. /// diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index f77a90d8e..03cb5d921 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -291,16 +291,47 @@ void MWState::StateManager::quickSave (std::string name) saveGame(name, slot); } -void MWState::StateManager::loadGame (const Character *character, const Slot *slot) +void MWState::StateManager::loadGame(const std::string& filepath) +{ + for (CharacterIterator it = mCharacterManager.begin(); it != mCharacterManager.end(); ++it) + { + const MWState::Character& character = *it; + for (MWState::Character::SlotIterator slotIt = character.begin(); slotIt != character.end(); ++slotIt) + { + const MWState::Slot& slot = *slotIt; + if (slot.mPath == boost::filesystem::path(filepath)) + { + loadGame(&character, slot.mPath.string()); + return; + } + } + } + + // have to peek into the save file to get the player name + ESM::ESMReader reader; + reader.open (filepath); + if (reader.getFormat()>ESM::Header::CurrentFormat) + return; // format is too new -> ignore + if (reader.getRecName()!=ESM::REC_SAVE) + return; // invalid save file -> ignore + reader.getRecHeader(); + ESM::SavedGame profile; + profile.load (reader); + reader.close(); + + MWState::Character* character = mCharacterManager.getCurrentCharacter(true, profile.mPlayerName); + loadGame(character, filepath); + mTimePlayed = profile.mTimePlayed; +} + +void MWState::StateManager::loadGame (const Character *character, const std::string& filepath) { try { cleanup(); - mTimePlayed = slot->mProfile.mTimePlayed; - ESM::ESMReader reader; - reader.open (slot->mPath.string()); + reader.open (filepath); std::map contentFileMap = buildContentFileIndexMap (reader); @@ -319,9 +350,11 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl switch (n.val) { case ESM::REC_SAVE: - - // don't need to read that here - reader.skipRecord(); + { + ESM::SavedGame profile; + profile.load(reader); + mTimePlayed = profile.mTimePlayed; + } break; case ESM::REC_JOUR: @@ -391,7 +424,7 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl mState = State_Running; Settings::Manager::setString ("character", "Saves", - slot->mPath.parent_path().filename().string()); + character->getPath().filename().string()); MWBase::Environment::get().getWindowManager()->setNewGame(false); MWBase::Environment::get().getWorld()->setupPlayer(); @@ -431,7 +464,7 @@ void MWState::StateManager::quickLoad() { if (Character* mCurrentCharacter = getCurrentCharacter (false)) if (const MWState::Slot* slot = &*mCurrentCharacter->begin()) //Get newest save - loadGame (mCurrentCharacter, slot); + loadGame (mCurrentCharacter, slot->mPath.string()); } void MWState::StateManager::deleteGame(const MWState::Character *character, const MWState::Slot *slot) @@ -472,7 +505,7 @@ void MWState::StateManager::update (float duration) //Load last saved game for current character MWState::Slot lastSave = *curCharacter->begin(); - loadGame(curCharacter, &lastSave); + loadGame(curCharacter, lastSave.mPath.string()); } else if(iButton==1) { diff --git a/apps/openmw/mwstate/statemanagerimp.hpp b/apps/openmw/mwstate/statemanagerimp.hpp index 40c36deb5..956a2d73c 100644 --- a/apps/openmw/mwstate/statemanagerimp.hpp +++ b/apps/openmw/mwstate/statemanagerimp.hpp @@ -61,10 +61,13 @@ namespace MWState /** Used for quickload **/ virtual void quickLoad(); - virtual void loadGame (const Character *character, const Slot *slot); - ///< Load a saved game file from \a slot. - /// - /// \note \a slot must belong to \a character. + virtual void loadGame (const std::string& filepath); + ///< Load a saved game directly from the given file path. This will search the CharacterManager + /// for a Character containing this save file, and set this Character current if one was found. + /// Otherwise, a new Character will be created. + + virtual void loadGame (const Character *character, const std::string &filepath); + ///< Load a saved game file belonging to the given character. virtual Character *getCurrentCharacter (bool create = true); ///< \param create Create a new character, if there is no current character. From ef1b0a191b0370a711377093b84ccbbbe676955b Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 7 Jan 2015 03:48:16 +0100 Subject: [PATCH 123/740] Revert "Enchanting: fix inverted self-enchant success chance" It wasn't inverted to begin with. The author of this commit is an idiot. --- apps/openmw/mwmechanics/enchanting.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 8c85e5eef..08df95fd9 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -65,7 +65,7 @@ namespace MWMechanics if(mSelfEnchanting) { - if(std::rand()/static_cast (RAND_MAX)*100 < getEnchantChance()) + if(getEnchantChance() (RAND_MAX)*100) return false; mEnchanter.getClass().skillUsageSucceeded (mEnchanter, ESM::Skill::Enchant, 2); From 13c5bd5cc27cde385285776d48cd9e1aff7b42eb Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 7 Jan 2015 04:28:56 +0100 Subject: [PATCH 124/740] Enchanting: fix skill-based cast cost bonus being applied twice --- apps/openmw/mwgui/enchantingdialog.cpp | 2 +- apps/openmw/mwgui/spellmodel.cpp | 4 +--- apps/openmw/mwmechanics/enchanting.cpp | 23 ++++++++++------------- apps/openmw/mwmechanics/enchanting.hpp | 3 ++- apps/openmw/mwmechanics/spellcasting.cpp | 16 +++++++++++++--- apps/openmw/mwmechanics/spellcasting.hpp | 2 ++ 6 files changed, 29 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 4744fd1a1..d2315be38 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -111,7 +111,7 @@ namespace MWGui mCharge->setCaption(boost::lexical_cast(mEnchanting.getGemCharge())); std::stringstream castCost; - castCost << mEnchanting.getCastCost(); + castCost << mEnchanting.getEffectiveCastCost(); mCastCost->setCaption(castCost.str()); mPrice->setCaption(boost::lexical_cast(mEnchanting.getEnchantPrice())); diff --git a/apps/openmw/mwgui/spellmodel.cpp b/apps/openmw/mwgui/spellmodel.cpp index ad9a913fa..4713720cd 100644 --- a/apps/openmw/mwgui/spellmodel.cpp +++ b/apps/openmw/mwgui/spellmodel.cpp @@ -103,9 +103,7 @@ namespace MWGui && item.getClass().canBeEquipped(item, mActor).first == 0) continue; - float enchantCost = enchant->mData.mCost; - int eSkill = mActor.getClass().getSkill(mActor, ESM::Skill::Enchant); - int castCost = std::max(1.f, enchantCost - (enchantCost / 100) * (eSkill - 10)); + int castCost = MWMechanics::getEffectiveEnchantmentCastCost(enchant->mData.mCost, mActor); std::string cost = boost::lexical_cast(castCost); int currentCharge = int(item.getCellRef().getEnchantmentCharge()); diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 08df95fd9..96afe2e2a 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -6,6 +6,7 @@ #include "creaturestats.hpp" #include "npcstats.hpp" +#include "spellcasting.hpp" namespace MWMechanics { @@ -55,7 +56,7 @@ namespace MWMechanics enchantment.mData.mCharge = getGemCharge(); enchantment.mData.mAutocalc = 0; enchantment.mData.mType = mCastStyle; - enchantment.mData.mCost = getCastCost(); + enchantment.mData.mCost = getBaseCastCost(); store.remove(mSoulGemPtr, 1, player); @@ -199,23 +200,19 @@ namespace MWMechanics } - int Enchanting::getCastCost() const + int Enchanting::getBaseCastCost() const { if (mCastStyle == ESM::Enchantment::ConstantEffect) return 0; - const float enchantCost = getEnchantPoints(); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - MWMechanics::NpcStats &stats = player.getClass().getNpcStats(player); - int eSkill = stats.getSkill(ESM::Skill::Enchant).getModified(); - - /* - * Each point of enchant skill above/under 10 subtracts/adds - * one percent of enchantment cost while minimum is 1. - */ - const float castCost = enchantCost - (enchantCost / 100) * (eSkill - 10); + return getEnchantPoints(); + } - return static_cast((castCost < 1) ? 1 : castCost); + int Enchanting::getEffectiveCastCost() const + { + int baseCost = getBaseCastCost(); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + return getEffectiveEnchantmentCastCost(baseCost, player); } diff --git a/apps/openmw/mwmechanics/enchanting.hpp b/apps/openmw/mwmechanics/enchanting.hpp index 2ee5ccce4..2c05d2d2e 100644 --- a/apps/openmw/mwmechanics/enchanting.hpp +++ b/apps/openmw/mwmechanics/enchanting.hpp @@ -36,7 +36,8 @@ namespace MWMechanics void nextCastStyle(); //Set enchant type to next possible type (for mOldItemPtr object) int getCastStyle() const; int getEnchantPoints() const; - int getCastCost() const; + int getBaseCastCost() const; // To be saved in the enchantment's record + int getEffectiveCastCost() const; // Effective cost taking player Enchant skill into account, used for preview purposes in the UI int getEnchantPrice() const; int getMaxEnchantValue() const; int getGemCharge() const; diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index b7c7e00a1..d9df1d00e 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -689,9 +689,7 @@ namespace MWMechanics // Check if there's enough charge left if (enchantment->mData.mType == ESM::Enchantment::WhenUsed || enchantment->mData.mType == ESM::Enchantment::WhenStrikes) { - const float enchantCost = enchantment->mData.mCost; - int eSkill = mCaster.getClass().getSkill(mCaster, ESM::Skill::Enchant); - const int castCost = std::max(1.f, enchantCost - (enchantCost / 100) * (eSkill - 10)); + const int castCost = getEffectiveEnchantmentCastCost(enchantment->mData.mCost, mCaster); if (item.getCellRef().getEnchantmentCharge() == -1) item.getCellRef().setEnchantmentCharge(enchantment->mData.mCharge); @@ -915,4 +913,16 @@ namespace MWMechanics return true; } + + int getEffectiveEnchantmentCastCost(float castCost, const MWWorld::Ptr &actor) + { + /* + * Each point of enchant skill above/under 10 subtracts/adds + * one percent of enchantment cost while minimum is 1. + */ + int eSkill = actor.getClass().getSkill(actor, ESM::Skill::Enchant); + const float result = castCost - (castCost / 100) * (eSkill - 10); + + return static_cast((result < 1) ? 1 : result); + } } diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 395ae043b..a79eeec6b 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -58,6 +58,8 @@ namespace MWMechanics float getEffectMultiplier(short effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster, const ESM::Spell* spell = NULL, const MagicEffects* effects = NULL); + int getEffectiveEnchantmentCastCost (float castCost, const MWWorld::Ptr& actor); + class CastSpell { private: From 4684014a83d1c8fef28cb7a25bb6528b03e4978a Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 7 Jan 2015 15:06:39 +0100 Subject: [PATCH 125/740] Use .omwsave extension for save game files --- apps/openmw/mwstate/character.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwstate/character.cpp b/apps/openmw/mwstate/character.cpp index c2ca5e095..f190565da 100644 --- a/apps/openmw/mwstate/character.cpp +++ b/apps/openmw/mwstate/character.cpp @@ -61,7 +61,8 @@ void MWState::Character::addSlot (const ESM::SavedGame& profile) stream << "_"; } - slot.mPath = mPath / stream.str(); + const std::string ext = ".omwsave"; + slot.mPath = mPath / (stream.str() + ext); // Append an index if necessary to ensure a unique file int i=0; @@ -70,7 +71,7 @@ void MWState::Character::addSlot (const ESM::SavedGame& profile) std::ostringstream test; test << stream.str(); test << " - " << ++i; - slot.mPath = mPath / test.str(); + slot.mPath = mPath / (test.str() + ext); } slot.mProfile = profile; From 94002b0758a8825215074b5341b6ec6b0cd28660 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 7 Jan 2015 15:07:08 +0100 Subject: [PATCH 126/740] Add freedesktop.org mimeinfo for OpenMW save game files This allows us to launch OpenMW when the user opens a save game file through the file manager. --- CMakeLists.txt | 3 +++ files/openmw-mimeinfo.xml | 11 +++++++++++ files/openmw.desktop | 13 +++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 files/openmw-mimeinfo.xml diff --git a/CMakeLists.txt b/CMakeLists.txt index fb89f4e91..0edf8cacd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -386,6 +386,8 @@ configure_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters if (NOT WIN32 AND NOT APPLE) configure_file(${OpenMW_SOURCE_DIR}/files/openmw.desktop "${OpenMW_BINARY_DIR}/openmw.desktop") + configure_file(${OpenMW_SOURCE_DIR}/files/openmw-mimeinfo.xml + "${OpenMW_BINARY_DIR}/openmw-mimeinfo.xml") configure_file(${OpenMW_SOURCE_DIR}/files/opencs.desktop "${OpenMW_BINARY_DIR}/opencs.desktop") endif() @@ -451,6 +453,7 @@ IF(NOT WIN32 AND NOT APPLE) # Install icon and desktop file INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-mimeinfo.xml" DESTINATION "${DATAROOTDIR}/mime/packages" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.png" DESTINATION "${ICONDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") IF(BUILD_OPENCS) INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.desktop" DESTINATION "${DATAROOTDIR}/applications" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs") diff --git a/files/openmw-mimeinfo.xml b/files/openmw-mimeinfo.xml new file mode 100644 index 000000000..1355383a5 --- /dev/null +++ b/files/openmw-mimeinfo.xml @@ -0,0 +1,11 @@ + + + + + + + OpenMW Savegame + + + + diff --git a/files/openmw.desktop b/files/openmw.desktop index 4a3a76f52..709304cb9 100644 --- a/files/openmw.desktop +++ b/files/openmw.desktop @@ -8,3 +8,16 @@ TryExec=omwlauncher Exec=omwlauncher Icon=openmw Categories=Game;RolePlaying; + +[Desktop Entry] +Type=Application +Name=OpenMW +GenericName=Role Playing Game +Comment=An engine replacement for The Elder Scrolls III: Morrowind +Keywords=Morrowind;Reimplementation Mods;esm;bsa; +Exec=openmw --load-savegame=%f +Icon=openmw +Categories=Game;RolePlaying; +Terminal=false +NoDisplay=true +MimeType=application/x-openmw-savegame; From 083de62be59ad0fe701af233eff2e8d0411ebb18 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 8 Jan 2015 11:18:42 +1300 Subject: [PATCH 127/740] Fixed issues found by Zinnschlag. 1. Errors found are added to default tool tip text. (Instead of replacing it.) 2. If multiple errors are found, all are shown in tool tip text, not just first one. 3. Load Order Errors are updated when files are activated/deactivated, not just when the files have their position in list changed. --- .../contentselector/model/contentmodel.cpp | 94 +++++++++++-------- .../contentselector/model/contentmodel.hpp | 17 +++- .../contentselector/model/loadordererror.cpp | 7 -- .../contentselector/model/loadordererror.hpp | 4 - 4 files changed, 65 insertions(+), 57 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 6366d7f54..57b231357 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -173,7 +173,7 @@ QVariant ContentSelectorModel::ContentModel::data(const QModelIndex &index, int { case Qt::ForegroundRole: { - if (isLoadOrderError(file->filePath())) + if (isLoadOrderError(file)) { QBrush redBackground(Qt::red, Qt::SolidPattern); return redBackground; @@ -213,7 +213,7 @@ QVariant ContentSelectorModel::ContentModel::data(const QModelIndex &index, int if (column != 0) return QVariant(); - return isLoadOrderError(file->filePath()) ? getLoadOrderError(file->filePath()).toolTip() : file->toolTip(); + return toolTip(file); break; } @@ -302,7 +302,7 @@ bool ContentSelectorModel::ContentModel::setData(const QModelIndex &index, const { setCheckState(file->filePath(), success); emit dataChanged(index, index); - + checkForLoadOrderErrors(); } else return success; @@ -543,26 +543,14 @@ bool ContentSelectorModel::ContentModel::isEnabled (QModelIndex index) const return (flags(index) & Qt::ItemIsEnabled); } -bool ContentSelectorModel::ContentModel::isLoadOrderError(const QString& filepath) const +bool ContentSelectorModel::ContentModel::isLoadOrderError(const EsmFile *file) const { - return !(getLoadOrderError(filepath) == LoadOrderError::sNoError); -} - -ContentSelectorModel::LoadOrderError ContentSelectorModel::ContentModel::getLoadOrderError(const QString& filepath) const -{ - return mLoadOrderErrors.contains(filepath) ? mLoadOrderErrors[filepath] : ContentSelectorModel::LoadOrderError::sNoError; -} - -void ContentSelectorModel::ContentModel::setLoadOrderError(const QString& filepath, const ContentSelectorModel::LoadOrderError& loadOrderError) -{ - mLoadOrderErrors[filepath] = loadOrderError; - int filePosition = indexFromItem(item(filepath)).row(); - emit dataChanged(index(filePosition, 0, QModelIndex()), index(filePosition, 0, QModelIndex())); + return mPluginsWithLoadOrderError.contains(file->filePath()); } void ContentSelectorModel::ContentModel::setContentList(const QStringList &fileList, bool isChecked) { - mLoadOrderErrors.clear(); + mPluginsWithLoadOrderError.clear(); int previousPosition = -1; foreach (const QString &filepath, fileList) { @@ -590,36 +578,60 @@ void ContentSelectorModel::ContentModel::checkForLoadOrderErrors() for (int row = 0; row < mFiles.count(); ++row) { EsmFile* file = item(row); - bool isRowInError = isLoadOrderError(file->filePath()); - LoadOrderError::ErrorCode error = LoadOrderError::ErrorCode_None; - foreach(QString dependentfileName, file->gameFiles()) + bool isRowInError = checkForLoadOrderErrors(file, row).count() != 0; + if (isRowInError) + { + mPluginsWithLoadOrderError.insert(file->filePath()); + } + else { - const EsmFile* dependentFile = item(dependentfileName); + mPluginsWithLoadOrderError.remove(file->filePath()); + } + } +} - if (!dependentFile) - { - error = LoadOrderError::ErrorCode_MissingDependency; - } - else if (!isChecked(dependentFile->filePath())) - { - error = LoadOrderError::ErrorCode_InactiveDependency; - } - else if (row < indexFromItem(dependentFile).row()) - { - error = LoadOrderError::ErrorCode_LoadOrder; - } +QList ContentSelectorModel::ContentModel::checkForLoadOrderErrors(const EsmFile *file, int row) const +{ + QList errors = QList(); + foreach(QString dependentfileName, file->gameFiles()) + { + const EsmFile* dependentFile = item(dependentfileName); - if (!isRowInError && (error != LoadOrderError::ErrorCode_None)) - { - setLoadOrderError(file->filePath(), LoadOrderError(error, dependentfileName)); - break; - } + if (!dependentFile) + { + errors.append(LoadOrderError(LoadOrderError::ErrorCode_MissingDependency, dependentfileName)); + } + if (!isChecked(dependentFile->filePath())) + { + errors.append(LoadOrderError(LoadOrderError::ErrorCode_InactiveDependency, dependentfileName)); } + if (row < indexFromItem(dependentFile).row()) + { + errors.append(LoadOrderError(LoadOrderError::ErrorCode_LoadOrder, dependentfileName)); + } + } + return errors; +} - if (isRowInError && (error == LoadOrderError::ErrorCode_None)) +QString ContentSelectorModel::ContentModel::toolTip(const EsmFile *file) const +{ + if (isLoadOrderError(file)) + { + QString text(""); + int index = indexFromItem(item(file->filePath())).row(); + foreach(const LoadOrderError& error, checkForLoadOrderErrors(file, index)) { - setLoadOrderError(file->filePath(), LoadOrderError::sNoError); + text += "

"; + text += error.toolTip(); + text += "

"; } + text += ("
"); + text += file->toolTip(); + return text; + } + else + { + return file->toolTip(); } } diff --git a/components/contentselector/model/contentmodel.hpp b/components/contentselector/model/contentmodel.hpp index 2a9f2c93b..f6e3d62bd 100644 --- a/components/contentselector/model/contentmodel.hpp +++ b/components/contentselector/model/contentmodel.hpp @@ -3,6 +3,7 @@ #include #include +#include #include "loadordererror.hpp" @@ -53,10 +54,6 @@ namespace ContentSelectorModel ContentFileList checkedItems() const; void uncheckAll(); - bool isLoadOrderError(const QString& filepath) const; - LoadOrderError getLoadOrderError(const QString& filepath) const; - void setLoadOrderError(const QString& filepath, const LoadOrderError& loadOrderError); - void refreshModel(); private: @@ -66,12 +63,22 @@ namespace ContentSelectorModel EsmFile *item(int row); void sortFiles(); + + /// Checks all plug-ins for load order errors and updates mPluginsWithLoadOrderError with plug-ins with issues void checkForLoadOrderErrors(); + /// Checks a specific plug-in for load order errors + /// \return all errors found for specific plug-in + QList checkForLoadOrderErrors(const EsmFile *file, int row) const; + + /// \return true if plug-in has a Load Order error + bool isLoadOrderError(const EsmFile *file) const; + + QString toolTip(const EsmFile *file) const; ContentFileList mFiles; QHash mCheckStates; - QHash mLoadOrderErrors; + QSet mPluginsWithLoadOrderError; QTextCodec *mCodec; QString mEncoding; diff --git a/components/contentselector/model/loadordererror.cpp b/components/contentselector/model/loadordererror.cpp index 0d02efbeb..aa69f330e 100644 --- a/components/contentselector/model/loadordererror.cpp +++ b/components/contentselector/model/loadordererror.cpp @@ -8,15 +8,8 @@ QString ContentSelectorModel::LoadOrderError::sErrorToolTips[ErrorCode_LoadOrder QString("This file needs to load after %1") }; -ContentSelectorModel::LoadOrderError ContentSelectorModel::LoadOrderError::sNoError = ContentSelectorModel::LoadOrderError(); - QString ContentSelectorModel::LoadOrderError::toolTip() const { assert(mErrorCode); return sErrorToolTips[mErrorCode - 1].arg(mFileName); } - -bool ContentSelectorModel::LoadOrderError::operator== (const ContentSelectorModel::LoadOrderError& rhs) const -{ - return (mErrorCode == rhs.mErrorCode) && ((mErrorCode == ErrorCode_None) || (mFileName == rhs.mFileName)); -} \ No newline at end of file diff --git a/components/contentselector/model/loadordererror.hpp b/components/contentselector/model/loadordererror.hpp index f3d3b0f8a..2b840cf69 100644 --- a/components/contentselector/model/loadordererror.hpp +++ b/components/contentselector/model/loadordererror.hpp @@ -25,12 +25,8 @@ namespace ContentSelectorModel } inline ErrorCode errorCode() const { return mErrorCode; } inline QString fileName() const { return mFileName; } - bool operator==(const LoadOrderError& rhs) const; QString toolTip() const; - /// Sentinel to represent a "No Load Order Error" condition - static LoadOrderError sNoError; - private: ErrorCode mErrorCode; QString mFileName; From 4b88ef58910c63cfef0fe6a1dac471980813f00c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 8 Jan 2015 13:59:03 +0100 Subject: [PATCH 128/740] fixed QuickFileParser handling of begin line (skip it instead of trying to make sense of it) --- components/compiler/quickfileparser.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/components/compiler/quickfileparser.cpp b/components/compiler/quickfileparser.cpp index 895b7ce65..f3d8063b2 100644 --- a/components/compiler/quickfileparser.cpp +++ b/components/compiler/quickfileparser.cpp @@ -19,12 +19,6 @@ bool Compiler::QuickFileParser::parseName (const std::string& name, const TokenL bool Compiler::QuickFileParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) { - if (keyword==Scanner::K_begin) - { - scanner.allowNameStartingwithDigit(); - return true; - } - if (keyword==Scanner::K_end) return false; From ef7e0070a62f1c90c9a9150c397d3666c61a0b0a Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 8 Jan 2015 02:34:37 +0100 Subject: [PATCH 129/740] Don't right-shift signed integers which is implementation-defined --- apps/openmw/mwgui/formatting.cpp | 2 +- apps/openmw/mwrender/animation.cpp | 2 +- components/esm/loadligh.hpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 583116003..765402a01 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -340,7 +340,7 @@ namespace MWGui { if (attr.find("color") != attr.end()) { - int color; + unsigned int color; std::stringstream ss; ss << attr.at("color"); ss >> std::hex >> color; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 1ef7a3533..ea40721cb 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -336,7 +336,7 @@ void Animation::addExtraLight(Ogre::SceneManager *sceneMgr, NifOgre::ObjectScene { const MWWorld::Fallback *fallback = MWBase::Environment::get().getWorld()->getFallback(); - const int clr = light->mData.mColor; + const unsigned int clr = light->mData.mColor; Ogre::ColourValue color(((clr >> 0) & 0xFF) / 255.0f, ((clr >> 8) & 0xFF) / 255.0f, ((clr >> 16) & 0xFF) / 255.0f); diff --git a/components/esm/loadligh.hpp b/components/esm/loadligh.hpp index ffc291609..2c83248f8 100644 --- a/components/esm/loadligh.hpp +++ b/components/esm/loadligh.hpp @@ -37,7 +37,7 @@ struct Light int mValue; int mTime; // Duration int mRadius; - int mColor; // 4-byte rgba value + unsigned int mColor; // 4-byte rgba value int mFlags; }; // Size = 24 bytes From 928b9ee41b2f3296426102d4df1fc9bf85d8ed91 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 8 Jan 2015 03:29:13 +0100 Subject: [PATCH 130/740] Fix missing GUI mode update when showing soulgem dialog --- apps/openmw/mwgui/windowmanagerimp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 72805dd31..5546480ec 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1455,6 +1455,8 @@ namespace MWGui void WindowManager::showSoulgemDialog(MWWorld::Ptr item) { mSoulgemDialog->show(item); + MWBase::Environment::get().getInputManager()->changeInputMode(isGuiMode()); + updateVisible(); } void WindowManager::frameStarted (float dt) From d31ae2b345e0058696a41308d370cb6e851f55a2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 8 Jan 2015 16:17:13 +0100 Subject: [PATCH 131/740] Fix mIds mapping for dynamic records being lost on save/reload --- apps/openmw/mwworld/esmstore.cpp | 10 +++++++++- apps/openmw/mwworld/store.hpp | 6 +++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 2a3fd9179..8e0f58a6b 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -192,7 +192,15 @@ void ESMStore::setUp() case ESM::REC_LEVI: case ESM::REC_LEVC: - mStores[type]->read (reader); + { + std::string id = reader.getHNString ("NAME"); + mStores[type]->read (reader, id); + + // FIXME: there might be stale dynamic IDs in mIds from an earlier savegame + // that really should be cleared instead of just overwritten + + mIds[id] = type; + } if (type==ESM::REC_NPC_) { diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index dcfbb4eb1..97ba4652f 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -30,7 +30,7 @@ namespace MWWorld virtual void write (ESM::ESMWriter& writer) const {} - virtual void read (ESM::ESMReader& reader) {} + virtual void read (ESM::ESMReader& reader, const std::string& id) {} ///< Read into dynamic storage }; @@ -329,10 +329,10 @@ namespace MWWorld } } - void read (ESM::ESMReader& reader) + void read (ESM::ESMReader& reader, const std::string& id) { T record; - record.mId = reader.getHNString ("NAME"); + record.mId = id; record.load (reader); insert (record); } From 2ddbe22da311b5f740a53fa1c4eecc39cbde4b9d Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 9 Jan 2015 00:44:22 +0100 Subject: [PATCH 132/740] Fix for NPC store clearDynamic bug It was clearing the whole mShared vector, instead of only the dynamic part. Actually, that whole overload was pointless to begin with. All it does is making sure the Player record isn't cleared, but ESMStore::clearDynamic re-inserts the player record anyway after clearing. --- apps/openmw/mwworld/store.hpp | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 97ba4652f..e94624ade 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -140,7 +140,8 @@ namespace MWWorld virtual void clearDynamic() { // remove the dynamic part of mShared - mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); + if (mShared.size() > mStatic.size()) + mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); mDynamic.clear(); } @@ -217,7 +218,8 @@ namespace MWWorld void setUp() { // remove the dynamic part of mShared - mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); + if (mShared.size() > mStatic.size()) + mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); } iterator begin() const { @@ -305,7 +307,8 @@ namespace MWWorld mDynamic.erase(it); // have to reinit the whole shared part - mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); + if (mShared.size() > mStatic.size()) + mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); for (it = mDynamic.begin(); it != mDynamic.end(); ++it) { mShared.push_back(&it->second); } @@ -338,20 +341,6 @@ namespace MWWorld } }; - template <> - inline void Store::clearDynamic() - { - std::map::iterator iter = mDynamic.begin(); - - while (iter!=mDynamic.end()) - if (iter->first=="player") - ++iter; - else - mDynamic.erase (iter++); - - mShared.clear(); - } - template <> inline void Store::load(ESM::ESMReader &esm, const std::string &id) { std::string idLower = Misc::StringUtils::lowerCase(id); From c77660ba206168cd186c26d03f170e3cee3d31a8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 9 Jan 2015 01:01:55 +0100 Subject: [PATCH 133/740] Remove some nonsense code --- apps/openmw/mwworld/esmstore.hpp | 3 --- apps/openmw/mwworld/store.cpp | 3 +-- apps/openmw/mwworld/store.hpp | 6 ------ 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index 5d794db89..01770e6b3 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -99,9 +99,6 @@ namespace MWWorld ESMStore() : mDynamicCount(0) { - // Cell store needs access to this for tracking moved references - mCells.mEsmStore = this; - mStores[ESM::REC_ACTI] = &mActivators; mStores[ESM::REC_ALCH] = &mPotions; mStores[ESM::REC_APPA] = &mAppas; diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index caf4083fe..7d58013e7 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -11,8 +11,7 @@ void Store::handleMovedCellRefs(ESM::ESMReader& esm, ESM::Cell* cell) ESM::MovedCellRef cMRef; cell->getNextMVRF(esm, cMRef); - MWWorld::Store &cStore = const_cast&>(mEsmStore->get()); - ESM::Cell *cellAlt = const_cast(cStore.searchOrCreate(cMRef.mTarget[0], cMRef.mTarget[1])); + ESM::Cell *cellAlt = const_cast(searchOrCreate(cMRef.mTarget[0], cMRef.mTarget[1])); // Get regular moved reference data. Adapted from CellStore::loadRefs. Maybe we can optimize the following // implementation when the oher implementation works as well. diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index e94624ade..71e77d0c7 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -582,14 +582,8 @@ namespace MWWorld void handleMovedCellRefs(ESM::ESMReader& esm, ESM::Cell* cell); public: - ESMStore *mEsmStore; - typedef SharedIterator iterator; - Store() - : mEsmStore(NULL) - {} - const ESM::Cell *search(const std::string &id) const { ESM::Cell cell; cell.mName = Misc::StringUtils::lowerCase(id); From ddd6e682bcf2bae8b8447b1203a2f5b8792ee3fc Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 9 Jan 2015 04:19:38 +0100 Subject: [PATCH 134/740] Dialogue: add conflict resolution for overlapping keywords (Fixes #2245) --- apps/openmw/mwdialogue/hypertextparser.cpp | 10 +++-- apps/openmw/mwdialogue/keywordsearch.hpp | 47 ++++++++++++++++++---- apps/openmw/mwgui/dialogue.cpp | 9 +++-- apps/openmw/mwgui/journalviewmodel.cpp | 10 +++-- 4 files changed, 58 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwdialogue/hypertextparser.cpp b/apps/openmw/mwdialogue/hypertextparser.cpp index 776edac94..aa748e772 100644 --- a/apps/openmw/mwdialogue/hypertextparser.cpp +++ b/apps/openmw/mwdialogue/hypertextparser.cpp @@ -56,13 +56,17 @@ namespace MWDialogue keywordList.sort(Misc::StringUtils::ciLess); KeywordSearch keywordSearch; - KeywordSearch::Match match; for (std::list::const_iterator it = keywordList.begin(); it != keywordList.end(); ++it) keywordSearch.seed(*it, 0 /*unused*/); - for (std::string::const_iterator it = text.begin(); it != text.end() && keywordSearch.search(it, text.end(), match, text.begin()); it = match.mEnd) - tokens.push_back(Token(std::string(match.mBeg, match.mEnd), Token::ImplicitKeyword)); + std::vector::Match> matches; + keywordSearch.highlightKeywords(text.begin(), text.end(), matches); + + for (std::vector::Match>::const_iterator it = matches.begin(); it != matches.end(); ++it) + { + tokens.push_back(Token(std::string(it->mBeg, it->mEnd), Token::ImplicitKeyword)); + } } size_t removePseudoAsterisks(std::string & phrase) diff --git a/apps/openmw/mwdialogue/keywordsearch.hpp b/apps/openmw/mwdialogue/keywordsearch.hpp index 51508890c..5ce492441 100644 --- a/apps/openmw/mwdialogue/keywordsearch.hpp +++ b/apps/openmw/mwdialogue/keywordsearch.hpp @@ -66,19 +66,20 @@ public: return false; } - bool search (Point beg, Point end, Match & match, Point start) + void highlightKeywords (Point beg, Point end, std::vector& out) { for (Point i = beg; i != end; ++i) { // check if previous character marked start of new word - if (i != start) + if (i != beg) { Point prev = i; - --prev; + --prev; if(isalpha(*prev)) continue; } + // check first character typename Entry::childen_t::iterator candidate = mRoot.mChildren.find (std::tolower (*i, mLocale)); @@ -137,16 +138,48 @@ public: if (t != candidate->second.mKeyword.end ()) continue; - // we did it, report the good news + // found a keyword, but there might still be longer keywords that start somewhere _within_ this keyword + // we will resolve these overlapping keywords later, choosing the longest one in case of conflict + Match match; match.mValue = candidate->second.mValue; match.mBeg = i; match.mEnd = k; - return true; + out.push_back(match); + break; } } - // no match in range, report the bad news - return false; + // resolve overlapping keywords + for (typename std::vector::iterator it = out.begin(); it != out.end();) + { + typename std::vector::iterator next = it; + ++next; + + if (next == out.end()) + break; + + if (it->mEnd <= next->mBeg) + { + ++it; + continue; // no overlap + } + else + { + // prefer the longer keyword + int size = it->mEnd - it->mBeg; + int nextSize = next->mEnd - next->mBeg; + if (size >= nextSize) // if both are the same length, then prefer the first keyword + { + out.erase(next); + continue; + } + else + { + it = out.erase(it); + continue; + } + } + } } private: diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index e1e016714..db9fa9f6b 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -177,11 +177,13 @@ namespace MWGui } else { - std::string::const_iterator i = text.begin (); - KeywordSearchT::Match match; + std::vector matches; + keywordSearch->highlightKeywords(text.begin(), text.end(), matches); - while (i != text.end () && keywordSearch->search (i, text.end (), match, text.begin ())) + std::string::const_iterator i = text.begin (); + for (std::vector::iterator it = matches.begin(); it != matches.end(); ++it) { + KeywordSearchT::Match match = *it; if (i != match.mBeg) addTopicLink (typesetter, 0, i - text.begin (), match.mBeg - text.begin ()); @@ -189,7 +191,6 @@ namespace MWGui i = match.mEnd; } - if (i != text.end ()) addTopicLink (typesetter, 0, i - text.begin (), text.size ()); } diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index 059af463f..add2ac62c 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -174,12 +174,14 @@ struct JournalViewModelImpl : JournalViewModel } else { - std::string::const_iterator i = utf8text.begin (); - - KeywordSearchT::Match match; + std::vector matches; + mModel->mKeywordSearch.highlightKeywords(utf8text.begin(), utf8text.end(), matches); - while (i != utf8text.end () && mModel->mKeywordSearch.search (i, utf8text.end (), match, utf8text.begin())) + std::string::const_iterator i = utf8text.begin (); + for (std::vector::const_iterator it = matches.begin(); it != matches.end(); ++it) { + const KeywordSearchT::Match& match = *it; + if (i != match.mBeg) visitor (0, i - utf8text.begin (), match.mBeg - utf8text.begin ()); From 65ab31eae6d069a9f835f637dc507780116e83b8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 9 Jan 2015 04:31:02 +0100 Subject: [PATCH 135/740] Remove now redundant Store::setUp implementation --- apps/openmw/mwworld/store.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 71e77d0c7..f3a5aad11 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -217,9 +217,6 @@ namespace MWWorld } void setUp() { - // remove the dynamic part of mShared - if (mShared.size() > mStatic.size()) - mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); } iterator begin() const { From 7fe2f86d06237a6f9d8f4c4289cec8e0143fc6b7 Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 9 Jan 2015 21:40:53 +1300 Subject: [PATCH 136/740] Slaughter fish attacks when player only knee deep in water (Fixes #2076) --- apps/openmw/mwbase/world.hpp | 1 + apps/openmw/mwclass/creature.cpp | 6 +++--- apps/openmw/mwmechanics/actors.cpp | 4 ++-- apps/openmw/mwmechanics/aicombat.cpp | 2 +- apps/openmw/mwworld/class.cpp | 10 ++++++++++ apps/openmw/mwworld/class.hpp | 2 ++ apps/openmw/mwworld/physicssystem.cpp | 4 ++-- apps/openmw/mwworld/worldimp.cpp | 27 ++++++++++++++++++--------- apps/openmw/mwworld/worldimp.hpp | 4 ++++ 9 files changed, 43 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index cdfdfc358..7432db734 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -392,6 +392,7 @@ namespace MWBase virtual bool isFlying(const MWWorld::Ptr &ptr) const = 0; virtual bool isSlowFalling(const MWWorld::Ptr &ptr) const = 0; virtual bool isSwimming(const MWWorld::Ptr &object) const = 0; + virtual bool isWading(const MWWorld::Ptr &object) const = 0; ///Is the head of the creature underwater? virtual bool isSubmerged(const MWWorld::Ptr &object) const = 0; virtual bool isUnderwater(const MWWorld::CellStore* cell, const Ogre::Vector3 &pos) const = 0; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 2146fdfde..e21676f10 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -348,9 +348,9 @@ namespace MWClass // Self defense bool setOnPcHitMe = true; // Note OnPcHitMe is not set for friendly hits. - if ((canWalk(ptr) || canFly(ptr) || canSwim(ptr)) // No retaliation for totally static creatures - // (they have no movement or attacks anyway) - && !attacker.isEmpty()) + + // No retaliation for totally static creatures (they have no movement or attacks anyway) + if (isMobile(ptr) && !attacker.isEmpty()) { setOnPcHitMe = MWBase::Environment::get().getMechanicsManager()->actorAttacked(ptr, attacker); } diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index c0fc80692..0a25ddd42 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -309,8 +309,8 @@ namespace MWMechanics // pure water creatures won't try to fight with the target on the ground // except that creature is already hostile if ((againstPlayer || !creatureStats.getAiSequence().isInCombat()) - && ((actor1.getClass().canSwim(actor1) && !actor1.getClass().canWalk(actor1) // pure water creature - && !MWBase::Environment::get().getWorld()->isSwimming(actor2)) + && ((actor1.getClass().isPureWaterCreature(actor1) + && !MWBase::Environment::get().getWorld()->isWading(actor2)) || (!actor1.getClass().canSwim(actor1) && MWBase::Environment::get().getWorld()->isSwimming(actor2)))) // creature can't swim to target return; diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 5d0470554..ce5963a91 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -209,7 +209,7 @@ namespace MWMechanics if (!actorClass.isNpc() && // 1. pure water creature and Player moved out of water ((target == world->getPlayerPtr() && - actorClass.canSwim(actor) && !actor.getClass().canWalk(actor) && !world->isSwimming(target)) + actorClass.isPureWaterCreature(actor) && !world->isWading(target)) // 2. creature can't swim to target || (!actorClass.canSwim(actor) && world->isSwimming(target)))) { diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 61c597517..939b72ddb 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -383,6 +383,16 @@ namespace MWWorld return false; } + bool Class::isPureWaterCreature(const MWWorld::Ptr& ptr) const + { + return canSwim(ptr) && !canWalk(ptr); + } + + bool Class::isMobile(const MWWorld::Ptr& ptr) const + { + return canSwim(ptr) || canWalk(ptr) || canFly(ptr); + } + int Class::getSkill(const MWWorld::Ptr& ptr, int skill) const { throw std::runtime_error("class does not support skills"); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index cc18d830c..b738cdd44 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -308,6 +308,8 @@ namespace MWWorld virtual bool canFly(const MWWorld::Ptr& ptr) const; virtual bool canSwim(const MWWorld::Ptr& ptr) const; virtual bool canWalk(const MWWorld::Ptr& ptr) const; + bool isPureWaterCreature(const MWWorld::Ptr& ptr) const; + bool isMobile(const MWWorld::Ptr& ptr) const; virtual int getSkill(const MWWorld::Ptr& ptr, int skill) const; diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 3a7aa0490..5b712648c 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -281,7 +281,7 @@ namespace MWWorld // Early-out for totally static creatures // (Not sure if gravity should still apply?) - if (!ptr.getClass().canWalk(ptr) && !ptr.getClass().canFly(ptr) && !ptr.getClass().canSwim(ptr)) + if (!ptr.getClass().isMobile(ptr)) return position; OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle()); @@ -434,7 +434,7 @@ namespace MWWorld if(result) { // don't let pure water creatures move out of water after stepMove - if((ptr.getClass().canSwim(ptr) && !ptr.getClass().canWalk(ptr)) + if (ptr.getClass().isPureWaterCreature(ptr) && newPosition.z > (waterlevel - halfExtents.z * 0.5)) newPosition = oldPosition; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a939a6db9..b99b4ff24 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1978,25 +1978,34 @@ namespace MWWorld bool World::isSubmerged(const MWWorld::Ptr &object) const { - const float *fpos = object.getRefData().getPosition().pos; - Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); - - const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(object.getRefData().getHandle()); - if(actor) pos.z += 1.85*actor->getHalfExtents().z; - - return isUnderwater(object.getCell(), pos); + return isUnderwater(object, 1.85f); } bool World::isSwimming(const MWWorld::Ptr &object) const { /// \todo add check ifActor() - only actors can swim + /// \fixme 3/4ths submerged? + return isUnderwater(object, 1.5f); + } + + bool + World::isWading(const MWWorld::Ptr &object) const + { + return isUnderwater(object, 0.5f); + } + + bool + World::isUnderwater(const MWWorld::Ptr &object, const float hightRatio) const + { const float *fpos = object.getRefData().getPosition().pos; Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); - /// \fixme 3/4ths submerged? const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(object.getRefData().getHandle()); - if(actor) pos.z += actor->getHalfExtents().z * 1.5; + if (actor) + { + pos.z += hightRatio*actor->getHalfExtents().z; + } return isUnderwater(object.getCell(), pos); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 5810fe42f..708a9abc3 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -139,6 +139,9 @@ namespace MWWorld void loadContentFiles(const Files::Collections& fileCollections, const std::vector& content, ContentLoader& contentLoader); + bool isUnderwater(const MWWorld::Ptr &object, const float hightRatio) const; + ///< helper function for implementing isSwimming(), isSubmerged(), isWading() + bool mTeleportEnabled; bool mLevitationEnabled; bool mGoToJail; @@ -454,6 +457,7 @@ namespace MWWorld virtual bool isSubmerged(const MWWorld::Ptr &object) const; virtual bool isSwimming(const MWWorld::Ptr &object) const; virtual bool isUnderwater(const MWWorld::CellStore* cell, const Ogre::Vector3 &pos) const; + virtual bool isWading(const MWWorld::Ptr &object) const; virtual bool isOnGround(const MWWorld::Ptr &ptr) const; virtual void togglePOV() { From 64cd1396ac0fcd9f18143dbdf142379b907a4e1f Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 9 Jan 2015 22:17:53 +1300 Subject: [PATCH 137/740] Fixed minor issues. 1. Renamed "hightRatio" to "heightRatio". 2. Replaced magic numbers with named constants. --- apps/openmw/mwworld/worldimp.cpp | 10 ++++++---- apps/openmw/mwworld/worldimp.hpp | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index b99b4ff24..f9642226b 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1978,7 +1978,8 @@ namespace MWWorld bool World::isSubmerged(const MWWorld::Ptr &object) const { - return isUnderwater(object, 1.85f); + const float neckDeep = 1.85f; + return isUnderwater(object, neckDeep); } bool @@ -1992,11 +1993,12 @@ namespace MWWorld bool World::isWading(const MWWorld::Ptr &object) const { - return isUnderwater(object, 0.5f); + const float kneeDeep = 0.5f; + return isUnderwater(object, kneeDeep); } bool - World::isUnderwater(const MWWorld::Ptr &object, const float hightRatio) const + World::isUnderwater(const MWWorld::Ptr &object, const float heightRatio) const { const float *fpos = object.getRefData().getPosition().pos; Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); @@ -2004,7 +2006,7 @@ namespace MWWorld const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(object.getRefData().getHandle()); if (actor) { - pos.z += hightRatio*actor->getHalfExtents().z; + pos.z += heightRatio*actor->getHalfExtents().z; } return isUnderwater(object.getCell(), pos); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 708a9abc3..dfaa9f789 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -139,7 +139,7 @@ namespace MWWorld void loadContentFiles(const Files::Collections& fileCollections, const std::vector& content, ContentLoader& contentLoader); - bool isUnderwater(const MWWorld::Ptr &object, const float hightRatio) const; + bool isUnderwater(const MWWorld::Ptr &object, const float heightRatio) const; ///< helper function for implementing isSwimming(), isSubmerged(), isWading() bool mTeleportEnabled; From ce2cbab4025204ccf643d6ef1ecd4dc4e18bad35 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 9 Jan 2015 20:08:52 +0100 Subject: [PATCH 138/740] Dialogue: improve conflict resolution for chains of overlapping keywords (unit test for such a case will follow) --- apps/openmw/mwdialogue/keywordsearch.hpp | 59 +++++++++++++++--------- 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwdialogue/keywordsearch.hpp b/apps/openmw/mwdialogue/keywordsearch.hpp index 5ce492441..c44139f32 100644 --- a/apps/openmw/mwdialogue/keywordsearch.hpp +++ b/apps/openmw/mwdialogue/keywordsearch.hpp @@ -66,8 +66,14 @@ public: return false; } + static bool sortMatches(const Match& left, const Match& right) + { + return left.mBeg < right.mBeg; + } + void highlightKeywords (Point beg, Point end, std::vector& out) { + std::vector matches; for (Point i = beg; i != end; ++i) { // check if previous character marked start of new word @@ -144,42 +150,51 @@ public: match.mValue = candidate->second.mValue; match.mBeg = i; match.mEnd = k; - out.push_back(match); + matches.push_back(match); break; } } // resolve overlapping keywords - for (typename std::vector::iterator it = out.begin(); it != out.end();) + while (matches.size()) { - typename std::vector::iterator next = it; - ++next; - - if (next == out.end()) - break; - - if (it->mEnd <= next->mBeg) - { - ++it; - continue; // no overlap - } - else + int longestKeywordSize = 0; + typename std::vector::iterator longestKeyword; + for (typename std::vector::iterator it = matches.begin(); it != matches.end(); ++it) { - // prefer the longer keyword int size = it->mEnd - it->mBeg; - int nextSize = next->mEnd - next->mBeg; - if (size >= nextSize) // if both are the same length, then prefer the first keyword + if (size > longestKeywordSize) { - out.erase(next); - continue; + longestKeywordSize = size; + longestKeyword = it; } - else + + typename std::vector::iterator next = it; + ++next; + + if (next == matches.end()) + break; + + if (it->mEnd <= next->mBeg) { - it = out.erase(it); - continue; + break; // no overlap } } + + Match keyword = *longestKeyword; + matches.erase(longestKeyword); + out.push_back(keyword); + // erase anything that overlaps with the keyword we just added to the output + for (typename std::vector::iterator it = matches.begin(); it != matches.end();) + { + if (it->mBeg < keyword.mEnd && it->mEnd > keyword.mBeg) + it = matches.erase(it); + else + ++it; + } } + + std::sort(out.begin(), out.end(), sortMatches); } private: From 9d07edda1394b479a5bf6bf6b751fc4ba073622c Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 9 Jan 2015 20:48:36 +0100 Subject: [PATCH 139/740] UnitTests: remove GMock which wasn't used anyway, and the gmock headers fail to compile together with gtest on ubuntu 14.04 --- CMakeLists.txt | 2 +- apps/openmw_test_suite/CMakeLists.txt | 11 +-- apps/openmw_test_suite/openmw_test_suite.cpp | 12 +-- cmake/FindGMock.cmake | 91 -------------------- 4 files changed, 6 insertions(+), 110 deletions(-) delete mode 100644 cmake/FindGMock.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 323b743bc..60c37d0f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,7 +61,7 @@ option(BUILD_MWINIIMPORTER "build MWiniImporter" 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 and GMock frameworks" 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) diff --git a/apps/openmw_test_suite/CMakeLists.txt b/apps/openmw_test_suite/CMakeLists.txt index 9fe7890ac..44354eac8 100644 --- a/apps/openmw_test_suite/CMakeLists.txt +++ b/apps/openmw_test_suite/CMakeLists.txt @@ -1,14 +1,7 @@ -# TODO: This should not be needed, check how it was done in FindGTEST -set(GMOCK_ROOT "/usr/include") -set(GMOCK_BUILD "/usr/lib") - find_package(GTest REQUIRED) -find_package(GMock REQUIRED) - -if (GTEST_FOUND AND GMOCK_FOUND) +if (GTEST_FOUND) include_directories(${GTEST_INCLUDE_DIRS}) - include_directories(${GMOCK_INCLUDE_DIRS}) file(GLOB UNITTEST_SRC_FILES components/misc/test_*.cpp @@ -18,7 +11,7 @@ if (GTEST_FOUND AND GMOCK_FOUND) add_executable(openmw_test_suite openmw_test_suite.cpp ${UNITTEST_SRC_FILES}) - target_link_libraries(openmw_test_suite ${GMOCK_BOTH_LIBRARIES} ${GTEST_BOTH_LIBRARIES} components) + 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}) diff --git a/apps/openmw_test_suite/openmw_test_suite.cpp b/apps/openmw_test_suite/openmw_test_suite.cpp index 81476325e..7cc76b25b 100644 --- a/apps/openmw_test_suite/openmw_test_suite.cpp +++ b/apps/openmw_test_suite/openmw_test_suite.cpp @@ -1,12 +1,6 @@ -#include #include - -int main(int argc, char** argv) { - // The following line causes Google Mock to throw an exception on failure, - // which will be interpreted by your testing framework as a test failure. - ::testing::GTEST_FLAG(throw_on_failure) = false; - ::testing::InitGoogleMock(&argc, argv); - - return RUN_ALL_TESTS(); +GTEST_API_ int main(int argc, char **argv) { + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); } diff --git a/cmake/FindGMock.cmake b/cmake/FindGMock.cmake deleted file mode 100644 index eda7d4d72..000000000 --- a/cmake/FindGMock.cmake +++ /dev/null @@ -1,91 +0,0 @@ -# Locate the Google C++ Mocking Framework. -# -# Defines the following variables: -# -# GMOCK_FOUND - Found the Google Mocking framework -# GMOCK_INCLUDE_DIRS - Include directories -# -# Also defines the library variables below as normal -# variables. These contain debug/optimized keywords when -# a debugging library is found. -# -# GMOCK_BOTH_LIBRARIES - Both libgmock & libgmock-main -# GMOCK_LIBRARIES - libgmock -# GMOCK_MAIN_LIBRARIES - libgmock-main -# -# Accepts the following variables as input: -# -# GMOCK_ROOT - (as CMake or env. variable) -# The root directory of the gmock install prefix -# -#----------------------- -# Example Usage: -# -# enable_testing(true) -# find_package(GMock REQUIRED) -# include_directories(${GMOCK_INCLUDE_DIRS}) -# -# add_executable(foo foo.cc) -# target_link_libraries(foo ${GMOCK_BOTH_LIBRARIES}) -# -# add_test(AllTestsInFoo foo) -# - -#set (GMOCK_FOUND FALSE) - - -#set (GMOCK_ROOT $ENV{GMOCK_ROOT} CACHE PATH "Path to the gmock root directory.") -if (NOT EXISTS ${GMOCK_ROOT}) - message (FATAL_ERROR "GMOCK_ROOT does not exist.") -endif () - -#set (GMOCK_BUILD ${GMOCK_ROOT}/build CACHE PATH "Path to the gmock build directory.") -if (NOT EXISTS ${GMOCK_BUILD}) - message (FATAL_ERROR "GMOCK_BUILD does not exist.") -endif () - -# Find the include directory -find_path(GMOCK_INCLUDE_DIRS gmock/gmock.h - HINTS - $ENV{GMOCK_ROOT}/include - ${GMOCK_ROOT}/include -) -mark_as_advanced(GMOCK_INCLUDE_DIRS) - -function(_gmock_find_library _name) - find_library(${_name} - NAMES ${ARGN} - HINTS - $ENV{GMOCK_BUILD} - ${GMOCK_BUILD} - ) - mark_as_advanced(${_name}) -endfunction() - -# Find the gmock libraries -if (MSVC) - _gmock_find_library (GMOCK_LIBRARIES_DEBUG gmock ${GMOCK_BUILD}/Debug) - _gmock_find_library (GMOCK_LIBRARIES_RELEASE gmock ${GMOCK_BUILD}/Release) - _gmock_find_library (GMOCK_MAIN_LIBRARIES_DEBUG gmock_main ${GMOCK_BUILD}/Debug) - _gmock_find_library (GMOCK_MAIN_LIBRARIES_RELEASE gmock_main ${GMOCK_BUILD}/Release) - set (GMOCK_LIBRARIES - debug ${GMOCK_LIBRARIES_DEBUG} - optimized ${GMOCK_LIBRARIES_RELEASE} - ) - set (GMOCK_MAIN_LIBRARIES - debug ${GMOCK_MAIN_LIBRARIES_DEBUG} - optimized ${GMOCK_MAIN_LIBRARIES_RELEASE} - ) -else () - _gmock_find_library (GMOCK_LIBRARIES gmock ${GMOCK_BUILD}) - _gmock_find_library (GMOCK_MAIN_LIBRARIES gmock_main ${GMOCK_BUILD} ${GMOCK_BUILD}/Debug) -endif () - -FIND_PACKAGE_HANDLE_STANDARD_ARGS(GMock DEFAULT_MSG GMOCK_LIBRARIES GMOCK_INCLUDE_DIRS GMOCK_MAIN_LIBRARIES) - -if(GMOCK_FOUND) - set(GMOCK_INCLUDE_DIRS ${GMOCK_INCLUDE_DIR}) - set(GMOCK_BOTH_LIBRARIES ${GMOCK_LIBRARIES} ${GMOCK_MAIN_LIBRARIES}) -endif() - - From 1b302b750cca4b6f88cb4794b97739acc140480c Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 9 Jan 2015 20:52:31 +0100 Subject: [PATCH 140/740] UnitTests: add tests for KeywordSearch conflict resolution --- apps/openmw_test_suite/CMakeLists.txt | 1 + .../mwdialogue/test_keywordsearch.cpp | 48 +++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 apps/openmw_test_suite/mwdialogue/test_keywordsearch.cpp diff --git a/apps/openmw_test_suite/CMakeLists.txt b/apps/openmw_test_suite/CMakeLists.txt index 44354eac8..2ffb7ffa0 100644 --- a/apps/openmw_test_suite/CMakeLists.txt +++ b/apps/openmw_test_suite/CMakeLists.txt @@ -5,6 +5,7 @@ if (GTEST_FOUND) file(GLOB UNITTEST_SRC_FILES components/misc/test_*.cpp + mwdialogue/test_*.cpp ) source_group(apps\\openmw_test_suite FILES openmw_test_suite.cpp ${UNITTEST_SRC_FILES}) diff --git a/apps/openmw_test_suite/mwdialogue/test_keywordsearch.cpp b/apps/openmw_test_suite/mwdialogue/test_keywordsearch.cpp new file mode 100644 index 000000000..c8ea9d01c --- /dev/null +++ b/apps/openmw_test_suite/mwdialogue/test_keywordsearch.cpp @@ -0,0 +1,48 @@ +#include +#include "apps/openmw/mwdialogue/keywordsearch.hpp" + +struct KeywordSearchTest : public ::testing::Test +{ + protected: + virtual void SetUp() + { + } + + virtual void TearDown() + { + } +}; + +TEST_F(KeywordSearchTest, keyword_test_conflict_resolution) +{ + // test to make sure the longest keyword in a chain of conflicting keywords gets chosen + MWDialogue::KeywordSearch search; + search.seed("foo bar", 0); + search.seed("bar lock", 0); + search.seed("lock switch", 0); + + std::string text = "foo bar lock switch"; + + std::vector::Match> matches; + search.highlightKeywords(text.begin(), text.end(), matches); + + // Should contain: "foo bar", "lock switch" + ASSERT_TRUE (matches.size() == 2); + ASSERT_TRUE (std::string(matches.front().mBeg, matches.front().mEnd) == "foo bar"); + ASSERT_TRUE (std::string(matches.rbegin()->mBeg, matches.rbegin()->mEnd) == "lock switch"); +} + +TEST_F(KeywordSearchTest, keyword_test_conflict_resolution2) +{ + MWDialogue::KeywordSearch search; + search.seed("the dwemer", 0); + search.seed("dwemer language", 0); + + std::string text = "the dwemer language"; + + std::vector::Match> matches; + search.highlightKeywords(text.begin(), text.end(), matches); + + ASSERT_TRUE (matches.size() == 1); + ASSERT_TRUE (std::string(matches.front().mBeg, matches.front().mEnd) == "dwemer language"); +} From dfdf26e95e93981f4fa6ff0b3a0de0215d89266e Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 9 Jan 2015 20:58:53 +0100 Subject: [PATCH 141/740] Add assertion to Store --- apps/openmw/mwworld/store.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index f3a5aad11..d9e4285fe 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -140,8 +140,8 @@ namespace MWWorld virtual void clearDynamic() { // remove the dynamic part of mShared - if (mShared.size() > mStatic.size()) - mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); + assert(mShared.size() >= mStatic.size()); + mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); mDynamic.clear(); } @@ -304,8 +304,8 @@ namespace MWWorld mDynamic.erase(it); // have to reinit the whole shared part - if (mShared.size() > mStatic.size()) - mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); + assert(mShared.size() >= mStatic.size()); + mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); for (it = mDynamic.begin(); it != mDynamic.end(); ++it) { mShared.push_back(&it->second); } From efbc8742a03b9037f465ce6bb350f9a4675bb34a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 9 Jan 2015 21:13:57 +0100 Subject: [PATCH 142/740] Remove some unnecessary includes --- components/misc/stringops.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/components/misc/stringops.cpp b/components/misc/stringops.cpp index 0f801e554..723c1c1e0 100644 --- a/components/misc/stringops.cpp +++ b/components/misc/stringops.cpp @@ -1,14 +1,5 @@ #include "stringops.hpp" -#include -#include -#include - -#include -#include - - - namespace Misc { From 2ac23008f5eec975f444a2cd72cba49745d1c579 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 00:07:40 +0100 Subject: [PATCH 143/740] Remove an old workaround (Fixes #2263) The workaround was added when we were still using OIS for input. It doesn't seem to be needed with SDL. --- apps/openmw/mwinput/inputmanagerimp.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 2f6149f09..ece189c75 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -409,8 +409,7 @@ namespace MWInput if (mControlSwitch["playerviewswitch"]) { - // work around preview mode toggle when pressing Alt+Tab - if (actionIsActive(A_TogglePOV) && !mInputManager->isModifierHeld(SDL_Keymod(KMOD_ALT))) { + if (actionIsActive(A_TogglePOV)) { if (mPreviewPOVDelay <= 0.5 && (mPreviewPOVDelay += dt) > 0.5) { From 66e7e0480717164fabbd4aae1e5190771db85d0c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 00:26:13 +0100 Subject: [PATCH 144/740] UnitTests: add another dialogue keyword test --- .../mwdialogue/test_keywordsearch.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/apps/openmw_test_suite/mwdialogue/test_keywordsearch.cpp b/apps/openmw_test_suite/mwdialogue/test_keywordsearch.cpp index c8ea9d01c..e0e1871d2 100644 --- a/apps/openmw_test_suite/mwdialogue/test_keywordsearch.cpp +++ b/apps/openmw_test_suite/mwdialogue/test_keywordsearch.cpp @@ -46,3 +46,22 @@ TEST_F(KeywordSearchTest, keyword_test_conflict_resolution2) ASSERT_TRUE (matches.size() == 1); ASSERT_TRUE (std::string(matches.front().mBeg, matches.front().mEnd) == "dwemer language"); } + + +TEST_F(KeywordSearchTest, keyword_test_conflict_resolution3) +{ + // testing that the longest keyword is chosen, rather than maximizing the + // amount of highlighted characters by highlighting the first and last keyword + MWDialogue::KeywordSearch search; + search.seed("foo bar", 0); + search.seed("bar lock", 0); + search.seed("lock so", 0); + + std::string text = "foo bar lock so"; + + std::vector::Match> matches; + search.highlightKeywords(text.begin(), text.end(), matches); + + ASSERT_TRUE (matches.size() == 1); + ASSERT_TRUE (std::string(matches.front().mBeg, matches.front().mEnd) == "bar lock"); +} From eb99ed697b0029f0e54ce915428c966478b4f92f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 01:00:52 +0100 Subject: [PATCH 145/740] Reduce includes --- apps/openmw/mwgui/alchemywindow.cpp | 27 +++++++++++++------------ apps/openmw/mwgui/alchemywindow.hpp | 9 ++++++--- apps/openmw/mwgui/charactercreation.cpp | 18 +++++++++++------ apps/openmw/mwgui/charactercreation.hpp | 5 +++-- apps/openmw/mwgui/travelwindow.hpp | 4 +++- apps/openmw/mwgui/videowidget.cpp | 19 +++++++++-------- apps/openmw/mwgui/videowidget.hpp | 7 +++++-- apps/openmw/mwworld/class.hpp | 1 - apps/openmw/mwworld/containerstore.hpp | 1 + apps/openmw/mwworld/esmloader.hpp | 6 +++++- apps/openmw/mwworld/ptr.hpp | 2 +- 11 files changed, 61 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index bb201e2dd..1715c49f8 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -1,7 +1,6 @@ #include "alchemywindow.hpp" #include -#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -9,6 +8,7 @@ #include "../mwbase/windowmanager.hpp" #include "../mwmechanics/magiceffects.hpp" +#include "../mwmechanics/alchemy.hpp" #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" @@ -27,6 +27,7 @@ namespace MWGui , mApparatus (4) , mIngredients (4) , mSortModel(NULL) + , mAlchemy(new MWMechanics::Alchemy()) { getWidget(mCreateButton, "CreateButton"); getWidget(mCancelButton, "CancelButton"); @@ -66,7 +67,7 @@ namespace MWGui std::string name = mNameEdit->getCaption(); boost::algorithm::trim(name); - MWMechanics::Alchemy::Result result = mAlchemy.create (mNameEdit->getCaption ()); + MWMechanics::Alchemy::Result result = mAlchemy->create (mNameEdit->getCaption ()); if (result == MWMechanics::Alchemy::Result_NoName) { @@ -121,7 +122,7 @@ namespace MWGui void AlchemyWindow::open() { - mAlchemy.setAlchemist (MWBase::Environment::get().getWorld()->getPlayerPtr()); + mAlchemy->setAlchemist (MWBase::Environment::get().getWorld()->getPlayerPtr()); InventoryItemModel* model = new InventoryItemModel(MWBase::Environment::get().getWorld()->getPlayerPtr()); mSortModel = new SortFilterItemModel(model); @@ -132,10 +133,10 @@ namespace MWGui int index = 0; - mAlchemy.setAlchemist (MWBase::Environment::get().getWorld()->getPlayerPtr()); + mAlchemy->setAlchemist (MWBase::Environment::get().getWorld()->getPlayerPtr()); - for (MWMechanics::Alchemy::TToolsIterator iter (mAlchemy.beginTools()); - iter!=mAlchemy.endTools() && index (mApparatus.size()); ++iter, ++index) + for (MWMechanics::Alchemy::TToolsIterator iter (mAlchemy->beginTools()); + iter!=mAlchemy->endTools() && index (mApparatus.size()); ++iter, ++index) { mApparatus.at (index)->setItem(*iter); mApparatus.at (index)->clearUserStrings(); @@ -150,7 +151,7 @@ namespace MWGui } void AlchemyWindow::exit() { - mAlchemy.clear(); + mAlchemy->clear(); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Alchemy); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Inventory); } @@ -164,7 +165,7 @@ namespace MWGui void AlchemyWindow::onSelectedItem(int index) { MWWorld::Ptr item = mSortModel->getItem(index).mBase; - int res = mAlchemy.addIngredient(item); + int res = mAlchemy->addIngredient(item); if (res != -1) { @@ -177,20 +178,20 @@ namespace MWGui void AlchemyWindow::update() { - std::string suggestedName = mAlchemy.suggestPotionName(); + std::string suggestedName = mAlchemy->suggestPotionName(); if (suggestedName != mSuggestedPotionName) mNameEdit->setCaptionWithReplacing(suggestedName); mSuggestedPotionName = suggestedName; mSortModel->clearDragItems(); - MWMechanics::Alchemy::TIngredientsIterator it = mAlchemy.beginIngredients (); + MWMechanics::Alchemy::TIngredientsIterator it = mAlchemy->beginIngredients (); for (int i=0; i<4; ++i) { ItemWidget* ingredient = mIngredients[i]; MWWorld::Ptr item; - if (it != mAlchemy.endIngredients ()) + if (it != mAlchemy->endIngredients ()) { item = *it; ++it; @@ -217,7 +218,7 @@ namespace MWGui mItemView->update(); - std::set effectIds = mAlchemy.listEffects(); + std::set effectIds = mAlchemy->listEffects(); Widgets::SpellEffectList list; for (std::set::iterator it = effectIds.begin(); it != effectIds.end(); ++it) { @@ -252,7 +253,7 @@ namespace MWGui { for (int i=0; i<4; ++i) if (mIngredients[i] == ingredient) - mAlchemy.removeIngredient (i); + mAlchemy->removeIngredient (i); update(); } diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index 36f540c1b..69fff8c67 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -3,11 +3,14 @@ #include -#include "../mwmechanics/alchemy.hpp" - #include "widgets.hpp" #include "windowbase.hpp" +namespace MWMechanics +{ + class Alchemy; +} + namespace MWGui { class ItemView; @@ -45,7 +48,7 @@ namespace MWGui void update(); - MWMechanics::Alchemy mAlchemy; + std::auto_ptr mAlchemy; std::vector mApparatus; std::vector mIngredients; diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 33d0c4907..3df8da942 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -1,20 +1,26 @@ #include "charactercreation.hpp" -#include "textinput.hpp" -#include "race.hpp" -#include "class.hpp" -#include "birth.hpp" -#include "review.hpp" -#include "inventorywindow.hpp" #include + #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/windowmanager.hpp" + #include "../mwmechanics/npcstats.hpp" + #include "../mwworld/class.hpp" #include "../mwworld/fallback.hpp" #include "../mwworld/esmstore.hpp" +#include "textinput.hpp" +#include "race.hpp" +#include "class.hpp" +#include "birth.hpp" +#include "review.hpp" +#include "inventorywindow.hpp" + namespace { struct Step diff --git a/apps/openmw/mwgui/charactercreation.hpp b/apps/openmw/mwgui/charactercreation.hpp index 03898093d..c2486c7f0 100644 --- a/apps/openmw/mwgui/charactercreation.hpp +++ b/apps/openmw/mwgui/charactercreation.hpp @@ -4,8 +4,9 @@ #include #include -#include "../mwbase/world.hpp" -#include "../mwbase/windowmanager.hpp" +#include + +#include "../mwmechanics/stat.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/travelwindow.hpp b/apps/openmw/mwgui/travelwindow.hpp index 3f1949256..3230f897f 100644 --- a/apps/openmw/mwgui/travelwindow.hpp +++ b/apps/openmw/mwgui/travelwindow.hpp @@ -1,7 +1,9 @@ #ifndef MWGUI_TravelWINDOW_H #define MWGUI_TravelWINDOW_H -#include "container.hpp" + +#include "windowbase.hpp" +#include "referenceinterface.hpp" namespace MyGUI { diff --git a/apps/openmw/mwgui/videowidget.cpp b/apps/openmw/mwgui/videowidget.cpp index f8054925b..2ade0f4c5 100644 --- a/apps/openmw/mwgui/videowidget.cpp +++ b/apps/openmw/mwgui/videowidget.cpp @@ -1,5 +1,7 @@ #include "videowidget.hpp" +#include + #include "../mwsound/movieaudiofactory.hpp" namespace MWGui @@ -7,40 +9,41 @@ namespace MWGui VideoWidget::VideoWidget() { + mPlayer.reset(new Video::VideoPlayer()); setNeedKeyFocus(true); } void VideoWidget::playVideo(const std::string &video) { - mPlayer.setAudioFactory(new MWSound::MovieAudioFactory()); - mPlayer.playVideo(video); + mPlayer->setAudioFactory(new MWSound::MovieAudioFactory()); + mPlayer->playVideo(video); - setImageTexture(mPlayer.getTextureName()); + setImageTexture(mPlayer->getTextureName()); } int VideoWidget::getVideoWidth() { - return mPlayer.getVideoWidth(); + return mPlayer->getVideoWidth(); } int VideoWidget::getVideoHeight() { - return mPlayer.getVideoHeight(); + return mPlayer->getVideoHeight(); } bool VideoWidget::update() { - return mPlayer.update(); + return mPlayer->update(); } void VideoWidget::stop() { - mPlayer.close(); + mPlayer->close(); } bool VideoWidget::hasAudioStream() { - return mPlayer.hasAudioStream(); + return mPlayer->hasAudioStream(); } } diff --git a/apps/openmw/mwgui/videowidget.hpp b/apps/openmw/mwgui/videowidget.hpp index 79e1c26bb..e350573c4 100644 --- a/apps/openmw/mwgui/videowidget.hpp +++ b/apps/openmw/mwgui/videowidget.hpp @@ -3,7 +3,10 @@ #include -#include +namespace Video +{ + class VideoPlayer; +} namespace MWGui { @@ -33,7 +36,7 @@ namespace MWGui void stop(); private: - Video::VideoPlayer mPlayer; + std::auto_ptr mPlayer; }; } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index cc18d830c..df9ca6a36 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -43,7 +43,6 @@ namespace ESM namespace MWWorld { - class Ptr; class ContainerStore; class InventoryStore; class PhysicsSystem; diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 1863984b2..2849463c9 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -18,6 +18,7 @@ #include #include "ptr.hpp" +#include "cellreflist.hpp" namespace ESM { diff --git a/apps/openmw/mwworld/esmloader.hpp b/apps/openmw/mwworld/esmloader.hpp index d799c3f15..b96af707c 100644 --- a/apps/openmw/mwworld/esmloader.hpp +++ b/apps/openmw/mwworld/esmloader.hpp @@ -4,13 +4,17 @@ #include #include "contentloader.hpp" -#include "components/esm/esmreader.hpp" namespace ToUTF8 { class Utf8Encoder; } +namespace ESM +{ + class ESMReader; +} + namespace MWWorld { diff --git a/apps/openmw/mwworld/ptr.hpp b/apps/openmw/mwworld/ptr.hpp index 2f37a1cfd..4d928dacf 100644 --- a/apps/openmw/mwworld/ptr.hpp +++ b/apps/openmw/mwworld/ptr.hpp @@ -6,7 +6,7 @@ #include #include -#include "cellreflist.hpp" +#include "livecellref.hpp" namespace MWWorld { From 4b704f665fc33f1dbdc26138146d7bc3e377942b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 01:21:17 +0100 Subject: [PATCH 146/740] Reduce includes, move DragAndDrop to separate file --- apps/openmw/CMakeLists.txt | 1 + apps/openmw/mwgui/companionwindow.cpp | 2 +- apps/openmw/mwgui/container.cpp | 114 +--------------------- apps/openmw/mwgui/container.hpp | 19 ---- apps/openmw/mwgui/draganddrop.cpp | 130 +++++++++++++++++++++++++ apps/openmw/mwgui/draganddrop.hpp | 38 ++++++++ apps/openmw/mwgui/enchantingdialog.cpp | 1 - apps/openmw/mwgui/hud.cpp | 2 +- apps/openmw/mwgui/inventorywindow.cpp | 2 +- apps/openmw/mwgui/itemselection.hpp | 9 +- apps/openmw/mwgui/tradewindow.hpp | 3 +- apps/openmw/mwgui/windowbase.cpp | 4 +- apps/openmw/mwgui/windowmanagerimp.cpp | 2 + 13 files changed, 187 insertions(+), 140 deletions(-) create mode 100644 apps/openmw/mwgui/draganddrop.cpp create mode 100644 apps/openmw/mwgui/draganddrop.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 97ab13012..cb6cc301b 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -41,6 +41,7 @@ add_openmw_dir (mwgui itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview + draganddrop ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index 2dd130b0d..c53e1697e 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -13,7 +13,7 @@ #include "itemview.hpp" #include "sortfilteritemmodel.hpp" #include "companionitemmodel.hpp" -#include "container.hpp" +#include "draganddrop.hpp" #include "countdialog.hpp" namespace MWGui diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index ee1d28592..85882ec13 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -24,123 +24,11 @@ #include "inventoryitemmodel.hpp" #include "sortfilteritemmodel.hpp" #include "pickpocketitemmodel.hpp" +#include "draganddrop.hpp" namespace MWGui { - DragAndDrop::DragAndDrop() - : mDraggedWidget(NULL) - , mDraggedCount(0) - , mSourceModel(NULL) - , mSourceView(NULL) - , mSourceSortModel(NULL) - , mIsOnDragAndDrop(false) - { - } - - void DragAndDrop::startDrag (int index, SortFilterItemModel* sortModel, ItemModel* sourceModel, ItemView* sourceView, int count) - { - mItem = sourceModel->getItem(index); - mDraggedCount = count; - mSourceModel = sourceModel; - mSourceView = sourceView; - mSourceSortModel = sortModel; - mIsOnDragAndDrop = true; - - // If picking up an item that isn't from the player's inventory, the item gets added to player inventory backend - // immediately, even though it's still floating beneath the mouse cursor. A bit counterintuitive, - // but this is how it works in vanilla, and not doing so would break quests (BM_beasts for instance). - ItemModel* playerModel = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getModel(); - if (mSourceModel != playerModel) - { - MWWorld::Ptr item = mSourceModel->moveItem(mItem, mDraggedCount, playerModel); - - playerModel->update(); - - ItemModel::ModelIndex newIndex = -1; - for (unsigned int i=0; igetItemCount(); ++i) - { - if (playerModel->getItem(i).mBase == item) - { - newIndex = i; - break; - } - } - mItem = playerModel->getItem(newIndex); - mSourceModel = playerModel; - - SortFilterItemModel* playerFilterModel = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getSortFilterModel(); - mSourceSortModel = playerFilterModel; - } - - std::string sound = mItem.mBase.getClass().getUpSoundId(mItem.mBase); - MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); - - if (mSourceSortModel) - { - mSourceSortModel->clearDragItems(); - mSourceSortModel->addDragItem(mItem.mBase, count); - } - - ItemWidget* baseWidget = MyGUI::Gui::getInstance().createWidget("MW_ItemIcon", 0, 0, 42, 42, MyGUI::Align::Default, "DragAndDrop"); - - Controllers::ControllerFollowMouse* controller = - MyGUI::ControllerManager::getInstance().createItem(Controllers::ControllerFollowMouse::getClassTypeName()) - ->castType(); - MyGUI::ControllerManager::getInstance().addItem(baseWidget, controller); - - mDraggedWidget = baseWidget; - baseWidget->setItem(mItem.mBase); - baseWidget->setNeedMouseFocus(false); - baseWidget->setCount(count); - - sourceView->update(); - - MWBase::Environment::get().getWindowManager()->setDragDrop(true); - } - - void DragAndDrop::drop(ItemModel *targetModel, ItemView *targetView) - { - std::string sound = mItem.mBase.getClass().getDownSoundId(mItem.mBase); - MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); - - // We can't drop a conjured item to the ground; the target container should always be the source container - if (mItem.mFlags & ItemStack::Flag_Bound && targetModel != mSourceModel) - { - MWBase::Environment::get().getWindowManager()->messageBox("#{sBarterDialog12}"); - return; - } - - // If item is dropped where it was taken from, we don't need to do anything - - // otherwise, do the transfer - if (targetModel != mSourceModel) - { - mSourceModel->moveItem(mItem, mDraggedCount, targetModel); - } - - mSourceModel->update(); - - finish(); - if (targetView) - targetView->update(); - - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView(); - - // We need to update the view since an other item could be auto-equipped. - mSourceView->update(); - } - - void DragAndDrop::finish() - { - mIsOnDragAndDrop = false; - mSourceSortModel->clearDragItems(); - - MyGUI::Gui::getInstance().destroyWidget(mDraggedWidget); - mDraggedWidget = 0; - MWBase::Environment::get().getWindowManager()->setDragDrop(false); - } - - ContainerWindow::ContainerWindow(DragAndDrop* dragAndDrop) : WindowBase("openmw_container_window.layout") , mDragAndDrop(dragAndDrop) diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index e32c6efaf..87ae993a5 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -28,25 +28,6 @@ namespace MWGui namespace MWGui { - class DragAndDrop - { - public: - bool mIsOnDragAndDrop; - MyGUI::Widget* mDraggedWidget; - ItemModel* mSourceModel; - ItemView* mSourceView; - SortFilterItemModel* mSourceSortModel; - ItemStack mItem; - int mDraggedCount; - - DragAndDrop(); - - void startDrag (int index, SortFilterItemModel* sortModel, ItemModel* sourceModel, ItemView* sourceView, int count); - void drop (ItemModel* targetModel, ItemView* targetView); - - void finish(); - }; - class ContainerWindow : public WindowBase, public ReferenceInterface { public: diff --git a/apps/openmw/mwgui/draganddrop.cpp b/apps/openmw/mwgui/draganddrop.cpp new file mode 100644 index 000000000..452d862f0 --- /dev/null +++ b/apps/openmw/mwgui/draganddrop.cpp @@ -0,0 +1,130 @@ +#include "draganddrop.hpp" + +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/soundmanager.hpp" + +#include "../mwworld/class.hpp" + +#include "sortfilteritemmodel.hpp" +#include "inventorywindow.hpp" +#include "itemwidget.hpp" +#include "itemview.hpp" + +namespace MWGui +{ + + +DragAndDrop::DragAndDrop() + : mDraggedWidget(NULL) + , mDraggedCount(0) + , mSourceModel(NULL) + , mSourceView(NULL) + , mSourceSortModel(NULL) + , mIsOnDragAndDrop(false) +{ +} + +void DragAndDrop::startDrag (int index, SortFilterItemModel* sortModel, ItemModel* sourceModel, ItemView* sourceView, int count) +{ + mItem = sourceModel->getItem(index); + mDraggedCount = count; + mSourceModel = sourceModel; + mSourceView = sourceView; + mSourceSortModel = sortModel; + mIsOnDragAndDrop = true; + + // If picking up an item that isn't from the player's inventory, the item gets added to player inventory backend + // immediately, even though it's still floating beneath the mouse cursor. A bit counterintuitive, + // but this is how it works in vanilla, and not doing so would break quests (BM_beasts for instance). + ItemModel* playerModel = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getModel(); + if (mSourceModel != playerModel) + { + MWWorld::Ptr item = mSourceModel->moveItem(mItem, mDraggedCount, playerModel); + + playerModel->update(); + + ItemModel::ModelIndex newIndex = -1; + for (unsigned int i=0; igetItemCount(); ++i) + { + if (playerModel->getItem(i).mBase == item) + { + newIndex = i; + break; + } + } + mItem = playerModel->getItem(newIndex); + mSourceModel = playerModel; + + SortFilterItemModel* playerFilterModel = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getSortFilterModel(); + mSourceSortModel = playerFilterModel; + } + + std::string sound = mItem.mBase.getClass().getUpSoundId(mItem.mBase); + MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); + + if (mSourceSortModel) + { + mSourceSortModel->clearDragItems(); + mSourceSortModel->addDragItem(mItem.mBase, count); + } + + ItemWidget* baseWidget = MyGUI::Gui::getInstance().createWidget("MW_ItemIcon", 0, 0, 42, 42, MyGUI::Align::Default, "DragAndDrop"); + + Controllers::ControllerFollowMouse* controller = + MyGUI::ControllerManager::getInstance().createItem(Controllers::ControllerFollowMouse::getClassTypeName()) + ->castType(); + MyGUI::ControllerManager::getInstance().addItem(baseWidget, controller); + + mDraggedWidget = baseWidget; + baseWidget->setItem(mItem.mBase); + baseWidget->setNeedMouseFocus(false); + baseWidget->setCount(count); + + sourceView->update(); + + MWBase::Environment::get().getWindowManager()->setDragDrop(true); +} + +void DragAndDrop::drop(ItemModel *targetModel, ItemView *targetView) +{ + std::string sound = mItem.mBase.getClass().getDownSoundId(mItem.mBase); + MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); + + // We can't drop a conjured item to the ground; the target container should always be the source container + if (mItem.mFlags & ItemStack::Flag_Bound && targetModel != mSourceModel) + { + MWBase::Environment::get().getWindowManager()->messageBox("#{sBarterDialog12}"); + return; + } + + // If item is dropped where it was taken from, we don't need to do anything - + // otherwise, do the transfer + if (targetModel != mSourceModel) + { + mSourceModel->moveItem(mItem, mDraggedCount, targetModel); + } + + mSourceModel->update(); + + finish(); + if (targetView) + targetView->update(); + + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView(); + + // We need to update the view since an other item could be auto-equipped. + mSourceView->update(); +} + +void DragAndDrop::finish() +{ + mIsOnDragAndDrop = false; + mSourceSortModel->clearDragItems(); + + MyGUI::Gui::getInstance().destroyWidget(mDraggedWidget); + mDraggedWidget = 0; + MWBase::Environment::get().getWindowManager()->setDragDrop(false); +} + +} diff --git a/apps/openmw/mwgui/draganddrop.hpp b/apps/openmw/mwgui/draganddrop.hpp new file mode 100644 index 000000000..a356fe4e2 --- /dev/null +++ b/apps/openmw/mwgui/draganddrop.hpp @@ -0,0 +1,38 @@ +#ifndef OPENMW_MWGUI_DRAGANDDROP_H +#define OPENMW_MWGUI_DRAGANDDROP_H + +#include "itemmodel.hpp" + +namespace MyGUI +{ + class Widget; +} + +namespace MWGui +{ + + class ItemView; + class SortFilterItemModel; + + class DragAndDrop + { + public: + bool mIsOnDragAndDrop; + MyGUI::Widget* mDraggedWidget; + ItemModel* mSourceModel; + ItemView* mSourceView; + SortFilterItemModel* mSourceSortModel; + ItemStack mItem; + int mDraggedCount; + + DragAndDrop(); + + void startDrag (int index, SortFilterItemModel* sortModel, ItemModel* sourceModel, ItemView* sourceView, int count); + void drop (ItemModel* targetModel, ItemView* targetView); + + void finish(); + }; + +} + +#endif diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index d2315be38..5bd799dac 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -15,7 +15,6 @@ #include "../mwworld/esmstore.hpp" #include "itemselection.hpp" -#include "container.hpp" #include "itemwidget.hpp" #include "sortfilteritemmodel.hpp" diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index f4c1f524a..b7035ee35 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -19,7 +19,7 @@ #include "console.hpp" #include "spellicons.hpp" #include "itemmodel.hpp" -#include "container.hpp" +#include "draganddrop.hpp" #include "itemmodel.hpp" #include "itemwidget.hpp" diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 60f40e6fb..0588d5002 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -25,7 +25,7 @@ #include "tradeitemmodel.hpp" #include "countdialog.hpp" #include "tradewindow.hpp" -#include "container.hpp" +#include "draganddrop.hpp" namespace { diff --git a/apps/openmw/mwgui/itemselection.hpp b/apps/openmw/mwgui/itemselection.hpp index 28c45c605..50e15a3fe 100644 --- a/apps/openmw/mwgui/itemselection.hpp +++ b/apps/openmw/mwgui/itemselection.hpp @@ -1,7 +1,14 @@ #ifndef OPENMW_GAME_MWGUI_ITEMSELECTION_H #define OPENMW_GAME_MWGUI_ITEMSELECTION_H -#include "container.hpp" +#include + +#include "windowbase.hpp" + +namespace MWWorld +{ + class Ptr; +} namespace MWGui { diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index b8bdfe648..61587e3df 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -1,7 +1,8 @@ #ifndef MWGUI_TRADEWINDOW_H #define MWGUI_TRADEWINDOW_H -#include "container.hpp" +#include "referenceinterface.hpp" +#include "windowbase.hpp" namespace Gui { diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index 9c12b04ef..d164320dd 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -1,9 +1,9 @@ #include "windowbase.hpp" #include "../mwbase/windowmanager.hpp" -#include "container.hpp" #include "../mwbase/environment.hpp" -#include "../mwgui/windowmanagerimp.hpp" + +#include "draganddrop.hpp" using namespace MWGui; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 5546480ec..5531a4980 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -74,6 +74,8 @@ #include "screenfader.hpp" #include "debugwindow.hpp" #include "spellview.hpp" +#include "draganddrop.hpp" +#include "container.hpp" namespace MWGui { From eecea4131f18cb400fc74afba2b9d6e20a62b714 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 02:50:43 +0100 Subject: [PATCH 147/740] Reduce MyGUI includes --- CMakeLists.txt | 2 +- apps/openmw/mwgui/alchemywindow.cpp | 2 + apps/openmw/mwgui/birth.cpp | 4 + apps/openmw/mwgui/bookwindow.cpp | 2 + apps/openmw/mwgui/class.cpp | 4 + apps/openmw/mwgui/companionwindow.cpp | 2 + apps/openmw/mwgui/confirmationdialog.cpp | 3 + apps/openmw/mwgui/console.cpp | 2 + apps/openmw/mwgui/container.cpp | 3 + apps/openmw/mwgui/controllers.cpp | 1 + apps/openmw/mwgui/controllers.hpp | 6 +- apps/openmw/mwgui/countdialog.cpp | 4 +- apps/openmw/mwgui/debugwindow.cpp | 4 + apps/openmw/mwgui/dialogue.cpp | 4 + apps/openmw/mwgui/dialogue.hpp | 2 +- apps/openmw/mwgui/draganddrop.cpp | 4 + apps/openmw/mwgui/formatting.cpp | 18 ++-- apps/openmw/mwgui/formatting.hpp | 2 +- apps/openmw/mwgui/hud.cpp | 9 ++ apps/openmw/mwgui/inventorywindow.cpp | 13 +++ apps/openmw/mwgui/inventorywindow.hpp | 19 ++-- apps/openmw/mwgui/itemselection.cpp | 3 + apps/openmw/mwgui/journalwindow.cpp | 15 +-- apps/openmw/mwgui/levelupdialog.cpp | 18 ++-- apps/openmw/mwgui/loadingscreen.cpp | 5 + apps/openmw/mwgui/mainmenu.cpp | 4 + apps/openmw/mwgui/mapwindow.cpp | 11 +- apps/openmw/mwgui/merchantrepair.cpp | 4 + apps/openmw/mwgui/messagebox.cpp | 8 +- apps/openmw/mwgui/quickkeysmenu.cpp | 4 + apps/openmw/mwgui/race.cpp | 5 + apps/openmw/mwgui/recharge.cpp | 3 + apps/openmw/mwgui/repair.cpp | 3 + apps/openmw/mwgui/review.cpp | 14 +++ apps/openmw/mwgui/savegamedialog.cpp | 5 + apps/openmw/mwgui/screenfader.cpp | 2 + apps/openmw/mwgui/scrollwindow.cpp | 2 + apps/openmw/mwgui/settingswindow.cpp | 8 +- apps/openmw/mwgui/spellbuyingwindow.cpp | 4 + apps/openmw/mwgui/spellcreationdialog.cpp | 3 + apps/openmw/mwgui/spellicons.cpp | 6 +- apps/openmw/mwgui/spellwindow.cpp | 2 + apps/openmw/mwgui/statswindow.cpp | 6 ++ apps/openmw/mwgui/textinput.cpp | 14 +++ apps/openmw/mwgui/textinput.hpp | 4 +- apps/openmw/mwgui/tooltips.cpp | 5 + apps/openmw/mwgui/tradewindow.cpp | 8 +- apps/openmw/mwgui/tradewindow.hpp | 5 +- apps/openmw/mwgui/trainingwindow.cpp | 2 + apps/openmw/mwgui/travelwindow.cpp | 4 + apps/openmw/mwgui/waitdialog.cpp | 2 + apps/openmw/mwgui/widgets.cpp | 11 +- apps/openmw/mwgui/widgets.hpp | 2 +- apps/openmw/mwgui/windowbase.cpp | 2 + apps/openmw/mwgui/windowmanagerimp.cpp | 16 ++- apps/openmw/mwgui/windowpinnablebase.cpp | 2 + libs/openengine/gui/layout.cpp | 103 ++++++++++++++++++ libs/openengine/gui/layout.hpp | 121 +++++----------------- 58 files changed, 395 insertions(+), 151 deletions(-) create mode 100644 libs/openengine/gui/layout.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 60c37d0f5..79fc7471f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -101,7 +101,7 @@ set(OENGINE_OGRE set(OENGINE_GUI ${LIBS_DIR}/openengine/gui/loglistener.cpp ${LIBS_DIR}/openengine/gui/manager.cpp - ${LIBS_DIR}/openengine/gui/layout.hpp + ${LIBS_DIR}/openengine/gui/layout.cpp ) set(OENGINE_BULLET diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 1715c49f8..b28e4de09 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -2,6 +2,8 @@ #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 50c6639dd..f6e8ec0a8 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -1,5 +1,9 @@ #include "birth.hpp" +#include +#include +#include + #include #include diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 92e876708..69d4a7288 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -1,5 +1,7 @@ #include "bookwindow.hpp" +#include + #include #include diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 4e72a3f59..3e8734c71 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -1,5 +1,9 @@ #include "class.hpp" +#include +#include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index c53e1697e..a863000ff 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -2,6 +2,8 @@ #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/dialoguemanager.hpp" diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp index a4e10749a..83650b195 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -1,5 +1,8 @@ #include "confirmationdialog.hpp" +#include +#include + namespace MWGui { ConfirmationDialog::ConfirmationDialog() : diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 97f11f4f3..5629c25f1 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -1,5 +1,7 @@ #include "console.hpp" +#include + #include #include diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 85882ec13..cb256e0fd 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -2,6 +2,9 @@ #include +#include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" diff --git a/apps/openmw/mwgui/controllers.cpp b/apps/openmw/mwgui/controllers.cpp index 5ebd2b1e7..ad804997a 100644 --- a/apps/openmw/mwgui/controllers.cpp +++ b/apps/openmw/mwgui/controllers.cpp @@ -1,6 +1,7 @@ #include "controllers.hpp" #include +#include namespace MWGui { diff --git a/apps/openmw/mwgui/controllers.hpp b/apps/openmw/mwgui/controllers.hpp index 003027a46..4208f048c 100644 --- a/apps/openmw/mwgui/controllers.hpp +++ b/apps/openmw/mwgui/controllers.hpp @@ -1,9 +1,13 @@ #ifndef MWGUI_CONTROLLERS_H #define MWGUI_CONTROLLERS_H -#include +#include #include +namespace MyGUI +{ + class Widget; +} namespace MWGui { diff --git a/apps/openmw/mwgui/countdialog.cpp b/apps/openmw/mwgui/countdialog.cpp index 24d0af0d7..c6f2180c9 100644 --- a/apps/openmw/mwgui/countdialog.cpp +++ b/apps/openmw/mwgui/countdialog.cpp @@ -1,6 +1,8 @@ #include "countdialog.hpp" -#include +#include +#include +#include #include diff --git a/apps/openmw/mwgui/debugwindow.cpp b/apps/openmw/mwgui/debugwindow.cpp index fab386bda..a6dab66c1 100644 --- a/apps/openmw/mwgui/debugwindow.cpp +++ b/apps/openmw/mwgui/debugwindow.cpp @@ -1,5 +1,9 @@ #include "debugwindow.hpp" +#include +#include +#include +#include #include diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index db9fa9f6b..1e8e06dc0 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -3,6 +3,10 @@ #include #include +#include +#include +#include + #include #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 23709e8fe..4ab88c06f 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -171,7 +171,7 @@ namespace MWGui BookPage* mHistory; Gui::MWList* mTopicsList; MyGUI::ScrollBar* mScrollBar; - MyGUI::Progress* mDispositionBar; + MyGUI::ProgressBar* mDispositionBar; MyGUI::EditBox* mDispositionText; PersuasionDialog mPersuasionDialog; diff --git a/apps/openmw/mwgui/draganddrop.cpp b/apps/openmw/mwgui/draganddrop.cpp index 452d862f0..fcb381b95 100644 --- a/apps/openmw/mwgui/draganddrop.cpp +++ b/apps/openmw/mwgui/draganddrop.cpp @@ -1,5 +1,8 @@ #include "draganddrop.hpp" +#include +#include + #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" @@ -10,6 +13,7 @@ #include "inventorywindow.hpp" #include "itemwidget.hpp" #include "itemview.hpp" +#include "controllers.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 765402a01..3f2b7d228 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -1,19 +1,23 @@ #include "formatting.hpp" -#include -#include -#include +#include +#include -#include "../mwscript/interpretercontext.hpp" +#include +#include +#include +#include +#include #include #include #include -#include -#include +#include +#include +#include -#include +#include "../mwscript/interpretercontext.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/formatting.hpp b/apps/openmw/mwgui/formatting.hpp index 0d0f74b72..d525baace 100644 --- a/apps/openmw/mwgui/formatting.hpp +++ b/apps/openmw/mwgui/formatting.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_FORMATTING_H #define MWGUI_FORMATTING_H -#include +#include #include namespace MWGui diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index b7035ee35..053106043 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -2,6 +2,15 @@ #include +#include + +#include +#include +#include +#include +#include +#include + #include #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 0588d5002..bc39c36d2 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -2,6 +2,12 @@ #include +#include +#include +#include +#include +#include + #include #include "../mwbase/world.hpp" @@ -15,6 +21,7 @@ #include "../mwworld/action.hpp" #include "../mwscript/interpretercontext.hpp" #include "../mwbase/scriptmanager.hpp" +#include "../mwrender/characterpreview.hpp" #include "bookwindow.hpp" #include "scrollwindow.hpp" @@ -26,6 +33,7 @@ #include "countdialog.hpp" #include "tradewindow.hpp" #include "draganddrop.hpp" +#include "widgets.hpp" namespace { @@ -667,4 +675,9 @@ namespace MWGui useItem(model.getItem(cycled).mBase); } + + void InventoryWindow::rebuildAvatar() + { + mPreview->rebuild(); + } } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 4f53a1e24..ee71d9b04 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -1,14 +1,23 @@ #ifndef MGUI_Inventory_H #define MGUI_Inventory_H -#include "../mwrender/characterpreview.hpp" - #include "windowpinnablebase.hpp" -#include "widgets.hpp" #include "mode.hpp" +#include "../mwworld/ptr.hpp" + +namespace MWRender +{ + class InventoryPreview; +} + namespace MWGui { + namespace Widgets + { + class MWDynamicStat; + } + class ItemView; class SortFilterItemModel; class TradeItemModel; @@ -33,9 +42,7 @@ namespace MWGui MWWorld::Ptr getAvatarSelectedItem(int x, int y); - void rebuildAvatar() { - mPreview->rebuild(); - } + void rebuildAvatar(); SortFilterItemModel* getSortFilterModel(); TradeItemModel* getTradeModel(); diff --git a/apps/openmw/mwgui/itemselection.cpp b/apps/openmw/mwgui/itemselection.cpp index 1b197f6d8..916f13360 100644 --- a/apps/openmw/mwgui/itemselection.cpp +++ b/apps/openmw/mwgui/itemselection.cpp @@ -1,5 +1,8 @@ #include "itemselection.hpp" +#include +#include + #include "itemview.hpp" #include "inventoryitemmodel.hpp" #include "sortfilteritemmodel.hpp" diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 0bcd5062d..c4b80b5fe 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -1,22 +1,25 @@ #include "journalwindow.hpp" -#include "../mwbase/environment.hpp" -#include "../mwbase/soundmanager.hpp" -#include "../mwbase/windowmanager.hpp" -#include "../mwbase/journal.hpp" - #include #include #include #include #include + +#include + #include #include -#include "boost/lexical_cast.hpp" +#include #include #include +#include "../mwbase/environment.hpp" +#include "../mwbase/soundmanager.hpp" +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/journal.hpp" + #include "bookpage.hpp" #include "windowbase.hpp" #include "journalviewmodel.hpp" diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index 56a231947..8553811aa 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -1,6 +1,8 @@ #include "levelupdialog.hpp" -#include +#include +#include +#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" @@ -34,17 +36,17 @@ namespace MWGui for (int i=1; i<9; ++i) { MyGUI::TextBox* t; - getWidget(t, "AttribVal" + boost::lexical_cast(i)); + getWidget(t, "AttribVal" + MyGUI::utility::toString(i)); MyGUI::Button* b; - getWidget(b, "Attrib" + boost::lexical_cast(i)); + getWidget(b, "Attrib" + MyGUI::utility::toString(i)); b->setUserData (i-1); b->eventMouseButtonClick += MyGUI::newDelegate(this, &LevelupDialog::onAttributeClicked); mAttributes.push_back(b); mAttributeValues.push_back(t); - getWidget(t, "AttribMultiplier" + boost::lexical_cast(i)); + getWidget(t, "AttribMultiplier" + MyGUI::utility::toString(i)); mAttributeMultipliers.push_back(t); } @@ -76,7 +78,7 @@ namespace MWGui if (val >= 100) val = 100; - mAttributeValues[i]->setCaption(boost::lexical_cast(val)); + mAttributeValues[i]->setCaption(MyGUI::utility::toString(val)); } } @@ -154,13 +156,13 @@ namespace MWGui mClassImage->setImageTexture ("textures\\levelup\\" + cls->mId + ".dds"); int level = creatureStats.getLevel ()+1; - mLevelText->setCaptionWithReplacing("#{sLevelUpMenu1} " + boost::lexical_cast(level)); + mLevelText->setCaptionWithReplacing("#{sLevelUpMenu1} " + MyGUI::utility::toString(level)); std::string levelupdescription; if(level > 20) levelupdescription=world->getFallback()->getFallbackString("Level_Up_Default"); else - levelupdescription=world->getFallback()->getFallbackString("Level_Up_Level"+boost::lexical_cast(level)); + levelupdescription=world->getFallback()->getFallbackString("Level_Up_Level"+MyGUI::utility::toString(level)); mLevelDescription->setCaption (levelupdescription); @@ -174,7 +176,7 @@ namespace MWGui availableAttributes++; int mult = pcStats.getLevelupAttributeMultiplier (i); - text->setCaption(mult <= 1 ? "" : "x" + boost::lexical_cast(mult)); + text->setCaption(mult <= 1 ? "" : "x" + MyGUI::utility::toString(mult)); } else { diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 4ff6b0c89..855a6fc84 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -9,6 +9,11 @@ #include #include +#include +#include +#include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/statemanager.hpp" diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index f1e7b4fc5..c7855b367 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -2,6 +2,10 @@ #include +#include +#include +#include + #include #include diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 729ee9277..cf8326b5c 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -5,6 +5,15 @@ #include #include +#include +#include +#include +#include +#include +#include +#include +#include + #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" @@ -15,7 +24,7 @@ #include "../mwrender/globalmap.hpp" -#include "../components/esm/globalmap.hpp" +#include #include "widgets.hpp" #include "confirmationdialog.hpp" diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index e85681c04..3f2f2ba02 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -4,6 +4,10 @@ #include +#include +#include +#include + #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index d4520aad7..43debd0e5 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -1,6 +1,12 @@ +#include "messagebox.hpp" + +#include +#include +#include +#include + #include -#include "messagebox.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/inputmanager.hpp" diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index d59b29f0f..6e10e4a97 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -2,6 +2,10 @@ #include +#include +#include +#include + #include #include diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 62bdd7f6b..9c5091b2b 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -1,5 +1,10 @@ #include "race.hpp" +#include +#include +#include +#include + #include #include diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 7458a6eff..81e36c958 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -3,6 +3,9 @@ #include #include +#include +#include + #include #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index 019f341b5..56ce09c84 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -4,6 +4,9 @@ #include +#include +#include + #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index ca1b6ed5d..2f52aae85 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -1,5 +1,9 @@ #include "review.hpp" +#include +#include +#include + #include #include "../mwbase/environment.hpp" @@ -12,6 +16,16 @@ #undef min #undef max +namespace +{ + void adjustButtonSize(MyGUI::Button *button) + { + // adjust size of button to fit its text + MyGUI::IntSize size = button->getTextSize(); + button->setSize(size.width + 24, button->getSize().height); + } +} + namespace MWGui { diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 3775f53dd..d022c8e25 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -4,6 +4,11 @@ #include #include +#include +#include +#include +#include + #include #include diff --git a/apps/openmw/mwgui/screenfader.cpp b/apps/openmw/mwgui/screenfader.cpp index a0421ec28..473776a82 100644 --- a/apps/openmw/mwgui/screenfader.cpp +++ b/apps/openmw/mwgui/screenfader.cpp @@ -1,5 +1,7 @@ #include "screenfader.hpp" +#include + namespace MWGui { diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index 038d91ca9..d49d5ad5f 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -1,5 +1,7 @@ #include "scrollwindow.hpp" +#include + #include #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 05664386b..f170559b0 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -1,7 +1,13 @@ #include "settingswindow.hpp" #include -#include + +#include +#include +#include +#include +#include +#include #include #include diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 38b1bce7b..9c3534d4a 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -2,6 +2,10 @@ #include +#include +#include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 0db2e30ce..275762d15 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -2,6 +2,9 @@ #include +#include +#include + #include #include diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index d23f1a235..7edc6c8da 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -1,10 +1,12 @@ #include "spellicons.hpp" -#include - #include #include +#include + +#include + #include #include diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 98ee588b1..6d3c79b34 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -2,6 +2,8 @@ #include +#include + #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index dcf85ddb7..e565b6f0e 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -1,5 +1,11 @@ #include "statswindow.hpp" +#include +#include +#include +#include +#include + #include #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/textinput.cpp b/apps/openmw/mwgui/textinput.cpp index 80652b430..958b52dc0 100644 --- a/apps/openmw/mwgui/textinput.cpp +++ b/apps/openmw/mwgui/textinput.cpp @@ -3,6 +3,9 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" +#include +#include + namespace MWGui { @@ -64,4 +67,15 @@ namespace MWGui onOkClicked(_sender); } + std::string TextInputDialog::getTextInput() const + { + return mTextEdit->getCaption(); + } + + void TextInputDialog::setTextInput(const std::string &text) + { + mTextEdit->setCaption(text); + } + + } diff --git a/apps/openmw/mwgui/textinput.hpp b/apps/openmw/mwgui/textinput.hpp index c83e3ffa9..57dd34dd6 100644 --- a/apps/openmw/mwgui/textinput.hpp +++ b/apps/openmw/mwgui/textinput.hpp @@ -15,8 +15,8 @@ namespace MWGui public: TextInputDialog(); - std::string getTextInput() const { return mTextEdit->getCaption(); } - void setTextInput(const std::string &text) { mTextEdit->setCaption(text); } + std::string getTextInput() const; + void setTextInput(const std::string &text); void setNextButtonShow(bool shown); void setTextLabel(const std::string &label); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index aafea1178..3f3540a21 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -2,6 +2,11 @@ #include +#include +#include +#include +#include + #include #include diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 6f0074e7e..bafa89d5b 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -1,6 +1,8 @@ #include "tradewindow.hpp" -#include +#include +#include +#include #include @@ -484,7 +486,7 @@ namespace MWGui MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); - mPlayerGold->setCaptionWithReplacing("#{sYourGold} " + boost::lexical_cast(playerGold)); + mPlayerGold->setCaptionWithReplacing("#{sYourGold} " + MyGUI::utility::toString(playerGold)); if (mCurrentBalance > 0) { @@ -497,7 +499,7 @@ namespace MWGui mTotalBalance->setValue(std::abs(mCurrentBalance)); - mMerchantGold->setCaptionWithReplacing("#{sSellerGold} " + boost::lexical_cast(getMerchantGold())); + mMerchantGold->setCaptionWithReplacing("#{sSellerGold} " + MyGUI::utility::toString(getMerchantGold())); } void TradeWindow::updateOffer() diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 61587e3df..a23196d70 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -9,12 +9,11 @@ namespace Gui class NumericEditBox; } -namespace MWGui +namespace MyGUI { - class WindowManager; + class ControllerItem; } - namespace MWGui { class ItemView; diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 56c9dff98..fc9167f3c 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -2,6 +2,8 @@ #include +#include + #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 6a0c99b8a..3d37d0ab0 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -2,6 +2,10 @@ #include +#include +#include +#include + #include #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index f2f4a1f91..6f87bffe0 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -2,6 +2,8 @@ #include +#include + #include #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 6af7714cb..381fc301e 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -1,21 +1,24 @@ #include "widgets.hpp" -#include "../mwworld/esmstore.hpp" - -#include #include #include -#include +#include #include #include #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwworld/esmstore.hpp" + +#include "controllers.hpp" + #undef min #undef max diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index 6ce114131..09a3c11ac 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -2,7 +2,6 @@ #define MWGUI_WIDGETS_H #include "../mwmechanics/stat.hpp" -#include "controllers.hpp" #include #include @@ -14,6 +13,7 @@ namespace MyGUI { class ImageBox; + class ControllerItem; } namespace MWBase diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index d164320dd..7f2eaec2e 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -1,5 +1,7 @@ #include "windowbase.hpp" +#include + #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 5531a4980..aa80e69fc 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -6,10 +6,17 @@ #include #include -#include "MyGUI_UString.h" -#include "MyGUI_IPointer.h" -#include "MyGUI_ResourceImageSetPointer.h" -#include "MyGUI_TextureUtility.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include @@ -76,6 +83,7 @@ #include "spellview.hpp" #include "draganddrop.hpp" #include "container.hpp" +#include "controllers.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/windowpinnablebase.cpp b/apps/openmw/mwgui/windowpinnablebase.cpp index f9bbca665..7307ece2d 100644 --- a/apps/openmw/mwgui/windowpinnablebase.cpp +++ b/apps/openmw/mwgui/windowpinnablebase.cpp @@ -1,5 +1,7 @@ #include "windowpinnablebase.hpp" +#include + #include "exposedwindow.hpp" namespace MWGui diff --git a/libs/openengine/gui/layout.cpp b/libs/openengine/gui/layout.cpp new file mode 100644 index 000000000..238c4232b --- /dev/null +++ b/libs/openengine/gui/layout.cpp @@ -0,0 +1,103 @@ +#include "layout.hpp" + +#include +#include +#include +#include +#include + +namespace OEngine +{ +namespace GUI +{ + void Layout::initialise(const std::string& _layout, MyGUI::Widget* _parent) + { + const std::string MAIN_WINDOW = "_Main"; + mLayoutName = _layout; + + if (mLayoutName.empty()) + mMainWidget = _parent; + else + { + mPrefix = MyGUI::utility::toString(this, "_"); + mListWindowRoot = MyGUI::LayoutManager::getInstance().loadLayout(mLayoutName, mPrefix, _parent); + + const std::string main_name = mPrefix + MAIN_WINDOW; + for (MyGUI::VectorWidgetPtr::iterator iter=mListWindowRoot.begin(); iter!=mListWindowRoot.end(); ++iter) + { + if ((*iter)->getName() == main_name) + { + mMainWidget = (*iter); + break; + } + } + MYGUI_ASSERT(mMainWidget, "root widget name '" << MAIN_WINDOW << "' in layout '" << mLayoutName << "' not found."); + } + } + + void Layout::shutdown() + { + MyGUI::Gui::getInstance().destroyWidget(mMainWidget); + mListWindowRoot.clear(); + } + + void Layout::setCoord(int x, int y, int w, int h) + { + mMainWidget->setCoord(x,y,w,h); + } + + void Layout::adjustWindowCaption() + { + MyGUI::TextBox* box = mMainWidget->castType(mMainWidget)->getCaptionWidget(); + box->setSize(box->getTextSize().width + 24, box->getSize().height); + + // in order to trigger alignment updates, we need to update the parent + // mygui doesn't provide a proper way of doing this, so we are just changing size + box->getParent()->setCoord(MyGUI::IntCoord( + box->getParent()->getCoord().left, + box->getParent()->getCoord().top, + box->getParent()->getCoord().width, + box->getParent()->getCoord().height+1 + )); + box->getParent()->setCoord(MyGUI::IntCoord( + box->getParent()->getCoord().left, + box->getParent()->getCoord().top, + box->getParent()->getCoord().width, + box->getParent()->getCoord().height-1 + )); + } + + void Layout::setVisible(bool b) + { + mMainWidget->setVisible(b); + } + + void Layout::setText(const std::string &name, const std::string &caption) + { + MyGUI::Widget* pt; + getWidget(pt, name); + static_cast(pt)->setCaption(caption); + } + + void Layout::setTitle(const std::string& title) + { + static_cast(mMainWidget)->setCaptionWithReplacing(title); + adjustWindowCaption(); + } + + MyGUI::Widget* Layout::getWidget(const std::string &_name) + { + for (MyGUI::VectorWidgetPtr::iterator iter=mListWindowRoot.begin(); + iter!=mListWindowRoot.end(); ++iter) + { + MyGUI::Widget* find = (*iter)->findWidget(mPrefix + _name); + if (nullptr != find) + { + return find; + } + } + MYGUI_EXCEPT("widget name '" << _name << "' in layout '" << mLayoutName << "' not found."); + } + +} +} diff --git a/libs/openengine/gui/layout.hpp b/libs/openengine/gui/layout.hpp index cd530a1d9..eb9205b82 100644 --- a/libs/openengine/gui/layout.hpp +++ b/libs/openengine/gui/layout.hpp @@ -1,7 +1,9 @@ #ifndef OENGINE_MYGUI_LAYOUT_H #define OENGINE_MYGUI_LAYOUT_H -#include +#include +#include +#include namespace OEngine { namespace GUI @@ -17,118 +19,43 @@ namespace GUI { initialise(_layout, _parent); } virtual ~Layout() { shutdown(); } + MyGUI::Widget* getWidget(const std::string& _name); + template - void getWidget(T * & _widget, const std::string & _name, bool _throw = true) + void getWidget(T * & _widget, const std::string & _name) { - _widget = nullptr; - for (MyGUI::VectorWidgetPtr::iterator iter=mListWindowRoot.begin(); - iter!=mListWindowRoot.end(); ++iter) + MyGUI::Widget* w = getWidget(_name); + T* cast = w->castType(false); + if (!cast) { - MyGUI::Widget* find = (*iter)->findWidget(mPrefix + _name); - if (nullptr != find) - { - T * cast = find->castType(false); - if (nullptr != cast) - _widget = cast; - else if (_throw) - { - MYGUI_EXCEPT("Error cast : dest type = '" << T::getClassTypeName() - << "' source name = '" << find->getName() - << "' source type = '" << find->getTypeName() << "' in layout '" << mLayoutName << "'"); - } - return; - } + MYGUI_EXCEPT("Error cast : dest type = '" << T::getClassTypeName() + << "' source name = '" << w->getName() + << "' source type = '" << w->getTypeName() << "' in layout '" << mLayoutName << "'"); } - MYGUI_ASSERT( ! _throw, "widget name '" << _name << "' in layout '" << mLayoutName << "' not found."); + else + _widget = cast; } private: void initialise(const std::string & _layout, - MyGUI::Widget* _parent = nullptr) - { - const std::string MAIN_WINDOW = "_Main"; - mLayoutName = _layout; - - if (mLayoutName.empty()) - mMainWidget = _parent; - else - { - mPrefix = MyGUI::utility::toString(this, "_"); - mListWindowRoot = MyGUI::LayoutManager::getInstance().loadLayout(mLayoutName, mPrefix, _parent); + MyGUI::Widget* _parent = nullptr); - const std::string main_name = mPrefix + MAIN_WINDOW; - for (MyGUI::VectorWidgetPtr::iterator iter=mListWindowRoot.begin(); iter!=mListWindowRoot.end(); ++iter) - { - if ((*iter)->getName() == main_name) - { - mMainWidget = (*iter); - break; - } - } - MYGUI_ASSERT(mMainWidget, "root widget name '" << MAIN_WINDOW << "' in layout '" << mLayoutName << "' not found."); - } - } - - void shutdown() - { - MyGUI::Gui::getInstance().destroyWidget(mMainWidget); - mListWindowRoot.clear(); - } + void shutdown(); public: - void setCoord(int x, int y, int w, int h) - { - mMainWidget->setCoord(x,y,w,h); - } + void setCoord(int x, int y, int w, int h); - void adjustWindowCaption() - { - // adjust the size of the window caption so that all text is visible - // NOTE: this assumes that mMainWidget is of type Window. - MyGUI::TextBox* box = static_cast(mMainWidget)->getCaptionWidget(); - box->setSize(box->getTextSize().width + 24, box->getSize().height); + // adjust the size of the window caption so that all text is visible + // NOTE: this assumes that mMainWidget is of type Window. + void adjustWindowCaption(); - // in order to trigger alignment updates, we need to update the parent - // mygui doesn't provide a proper way of doing this, so we are just changing size - box->getParent()->setCoord(MyGUI::IntCoord( - box->getParent()->getCoord().left, - box->getParent()->getCoord().top, - box->getParent()->getCoord().width, - box->getParent()->getCoord().height+1 - )); - box->getParent()->setCoord(MyGUI::IntCoord( - box->getParent()->getCoord().left, - box->getParent()->getCoord().top, - box->getParent()->getCoord().width, - box->getParent()->getCoord().height-1 - )); - } + virtual void setVisible(bool b); - virtual void setVisible(bool b) - { - mMainWidget->setVisible(b); - } + void setText(const std::string& name, const std::string& caption); - void setText(const std::string& name, const std::string& caption) - { - MyGUI::Widget* pt; - getWidget(pt, name); - static_cast(pt)->setCaption(caption); - } + // NOTE: this assume that mMainWidget is of type Window. + void setTitle(const std::string& title); - void setTitle(const std::string& title) - { - // NOTE: this assume that mMainWidget is of type Window. - static_cast(mMainWidget)->setCaptionWithReplacing(title); - adjustWindowCaption(); - } - - void adjustButtonSize(MyGUI::Button* button) - { - // adjust size of button to fit its text - MyGUI::IntSize size = button->getTextSize(); - button->setSize(size.width + 24, button->getSize().height); - } MyGUI::Widget* mMainWidget; protected: From 728b842e72c748afd9fe4a173ba924d378edbe97 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 03:01:01 +0100 Subject: [PATCH 148/740] Use MyGUI::utility in favor of boost lexical_cast --- apps/openmw/mwgui/birth.cpp | 4 +-- apps/openmw/mwgui/bookwindow.cpp | 6 ++--- apps/openmw/mwgui/charactercreation.cpp | 12 ++++----- apps/openmw/mwgui/companionwindow.cpp | 4 +-- apps/openmw/mwgui/container.cpp | 2 -- apps/openmw/mwgui/dialogue.cpp | 7 +++-- apps/openmw/mwgui/enchantingdialog.cpp | 6 ++--- apps/openmw/mwgui/formatting.cpp | 9 +++---- apps/openmw/mwgui/hud.cpp | 10 +++---- apps/openmw/mwgui/inventorywindow.cpp | 6 ++--- apps/openmw/mwgui/itemview.cpp | 2 -- apps/openmw/mwgui/itemwidget.cpp | 6 ++--- apps/openmw/mwgui/journalwindow.cpp | 3 +-- apps/openmw/mwgui/mapwindow.cpp | 10 +++---- apps/openmw/mwgui/merchantrepair.cpp | 10 +++---- apps/openmw/mwgui/quickkeysmenu.cpp | 6 ++--- apps/openmw/mwgui/race.cpp | 5 ++-- apps/openmw/mwgui/recharge.cpp | 3 +-- apps/openmw/mwgui/repair.cpp | 4 +-- apps/openmw/mwgui/review.cpp | 14 +++++----- apps/openmw/mwgui/settingswindow.cpp | 25 +++++++++--------- apps/openmw/mwgui/spellbuyingwindow.cpp | 6 ++--- apps/openmw/mwgui/spellcreationdialog.cpp | 20 +++++++------- apps/openmw/mwgui/spellicons.cpp | 4 +-- apps/openmw/mwgui/statswindow.cpp | 32 +++++++++++------------ apps/openmw/mwgui/tooltips.cpp | 4 +-- apps/openmw/mwgui/trainingwindow.cpp | 6 ++--- apps/openmw/mwgui/travelwindow.cpp | 6 ++--- apps/openmw/mwgui/waitdialog.cpp | 12 ++++----- apps/openmw/mwgui/widgets.cpp | 14 +++++----- 30 files changed, 103 insertions(+), 155 deletions(-) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index f6e8ec0a8..668253712 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -4,8 +4,6 @@ #include #include -#include - #include #include @@ -234,7 +232,7 @@ namespace MWGui for (std::vector::const_iterator it = categories[category].spells.begin(); it != end; ++it) { const std::string &spellId = *it; - spellWidget = mSpellArea->createWidget("MW_StatName", coord, MyGUI::Align::Default, std::string("Spell") + boost::lexical_cast(i)); + spellWidget = mSpellArea->createWidget("MW_StatName", coord, MyGUI::Align::Default, std::string("Spell") + MyGUI::utility::toString(i)); spellWidget->setSpellId(spellId); mSpellItems.push_back(spellWidget); diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 69d4a7288..da0d1950e 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -2,8 +2,6 @@ #include -#include - #include #include "../mwbase/environment.hpp" @@ -142,8 +140,8 @@ namespace MWGui void BookWindow::updatePages() { - mLeftPageNumber->setCaption( boost::lexical_cast(mCurrentPage*2 + 1) ); - mRightPageNumber->setCaption( boost::lexical_cast(mCurrentPage*2 + 2) ); + 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() diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 3df8da942..ab412f63b 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -1,7 +1,5 @@ #include "charactercreation.hpp" -#include - #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -34,11 +32,11 @@ namespace Step sGenerateClassSteps(int number) { number++; const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); - Step step = {fallback->getFallbackString("Question_"+boost::lexical_cast(number)+"_Question"), - {fallback->getFallbackString("Question_"+boost::lexical_cast(number)+"_AnswerOne"), - fallback->getFallbackString("Question_"+boost::lexical_cast(number)+"_AnswerTwo"), - fallback->getFallbackString("Question_"+boost::lexical_cast(number)+"_AnswerThree")}, - "vo\\misc\\chargen qa"+boost::lexical_cast(number)+".wav" + Step step = {fallback->getFallbackString("Question_"+MyGUI::utility::toString(number)+"_Question"), + {fallback->getFallbackString("Question_"+MyGUI::utility::toString(number)+"_AnswerOne"), + fallback->getFallbackString("Question_"+MyGUI::utility::toString(number)+"_AnswerTwo"), + fallback->getFallbackString("Question_"+MyGUI::utility::toString(number)+"_AnswerThree")}, + "vo\\misc\\chargen qa"+MyGUI::utility::toString(number)+".wav" }; return step; } diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index a863000ff..758316030 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -1,7 +1,5 @@ #include "companionwindow.hpp" -#include - #include #include "../mwbase/environment.hpp" @@ -122,7 +120,7 @@ void CompanionWindow::updateEncumbranceBar() else { MWMechanics::NpcStats& stats = mPtr.getClass().getNpcStats(mPtr); - mProfitLabel->setCaptionWithReplacing("#{sProfitValue} " + boost::lexical_cast(stats.getProfit())); + mProfitLabel->setCaptionWithReplacing("#{sProfitValue} " + MyGUI::utility::toString(stats.getProfit())); } } diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index cb256e0fd..49e641aed 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -1,7 +1,5 @@ #include "container.hpp" -#include - #include #include diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 1e8e06dc0..eee86c6d2 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -1,7 +1,6 @@ #include "dialogue.hpp" #include -#include #include #include @@ -100,7 +99,7 @@ namespace MWGui mBribe100Button->setEnabled (playerGold >= 100); mBribe1000Button->setEnabled (playerGold >= 1000); - mGoldLabel->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(playerGold)); + mGoldLabel->setCaptionWithReplacing("#{sGold}: " + MyGUI::utility::toString(playerGold)); } void PersuasionDialog::exit() @@ -630,7 +629,7 @@ namespace MWGui dispositionVisible = true; mDispositionBar->setProgressRange(100); mDispositionBar->setProgressPosition(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr)); - mDispositionText->setCaption(boost::lexical_cast(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr))+std::string("/100")); + mDispositionText->setCaption(MyGUI::utility::toString(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr))+std::string("/100")); } bool dispositionWasVisible = mDispositionBar->getVisible(); @@ -672,7 +671,7 @@ namespace MWGui + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange())); mDispositionBar->setProgressRange(100); mDispositionBar->setProgressPosition(disp); - mDispositionText->setCaption(boost::lexical_cast(disp)+std::string("/100")); + mDispositionText->setCaption(MyGUI::utility::toString(disp)+std::string("/100")); } } } diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 5bd799dac..a17c0d0e6 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -105,15 +105,15 @@ namespace MWGui { std::stringstream enchantCost; enchantCost << std::setprecision(1) << std::fixed << mEnchanting.getEnchantPoints(); - mEnchantmentPoints->setCaption(enchantCost.str() + " / " + boost::lexical_cast(mEnchanting.getMaxEnchantValue())); + mEnchantmentPoints->setCaption(enchantCost.str() + " / " + MyGUI::utility::toString(mEnchanting.getMaxEnchantValue())); - mCharge->setCaption(boost::lexical_cast(mEnchanting.getGemCharge())); + mCharge->setCaption(MyGUI::utility::toString(mEnchanting.getGemCharge())); std::stringstream castCost; castCost << mEnchanting.getEffectiveCastCost(); mCastCost->setCaption(castCost.str()); - mPrice->setCaption(boost::lexical_cast(mEnchanting.getEnchantPrice())); + mPrice->setCaption(MyGUI::utility::toString(mEnchanting.getEnchantPrice())); switch(mEnchanting.getCastStyle()) { diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 3f2b7d228..761a89ca6 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -11,7 +11,6 @@ #include #include -#include #include #include @@ -284,8 +283,8 @@ namespace MWGui continue; std::string src = attr.at("src"); - int width = boost::lexical_cast(attr.at("width")); - int height = boost::lexical_cast(attr.at("height")); + int width = MyGUI::utility::parseInt(attr.at("width")); + int height = MyGUI::utility::parseInt(attr.at("height")); ImageElement elem(paper, pag, mBlockStyle, src, width, height); @@ -397,7 +396,7 @@ namespace MWGui { MyGUI::EditBox* box = parent->createWidget("NormalText", MyGUI::IntCoord(0, pag.getCurrentTop(), pag.getPageWidth(), 0), MyGUI::Align::Left | MyGUI::Align::Top, - parent->getName() + boost::lexical_cast(parent->getChildCount())); + parent->getName() + MyGUI::utility::toString(parent->getChildCount())); box->setProperty("Static", "true"); box->setProperty("MultiLine", "true"); box->setProperty("WordWrap", "true"); @@ -465,7 +464,7 @@ namespace MWGui mImageBox = parent->createWidget ("ImageBox", MyGUI::IntCoord(left, pag.getCurrentTop(), width, mImageHeight), MyGUI::Align::Left | MyGUI::Align::Top, - parent->getName() + boost::lexical_cast(parent->getChildCount())); + parent->getName() + MyGUI::utility::toString(parent->getChildCount())); std::string image = Misc::ResourceHelpers::correctBookartPath(src, width, mImageHeight); mImageBox->setImageTexture(image); diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 053106043..b4312dc40 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -1,7 +1,5 @@ #include "hud.hpp" -#include - #include #include @@ -214,17 +212,17 @@ namespace MWGui void HUD::setFPS(float fps) { if (mFpsCounter) - mFpsCounter->setCaption(boost::lexical_cast((int)fps)); + mFpsCounter->setCaption(MyGUI::utility::toString((int)fps)); } void HUD::setTriangleCount(unsigned int count) { - mTriangleCounter->setCaption(boost::lexical_cast(count)); + mTriangleCounter->setCaption(MyGUI::utility::toString(count)); } void HUD::setBatchCount(unsigned int count) { - mBatchCounter->setCaption(boost::lexical_cast(count)); + mBatchCounter->setCaption(MyGUI::utility::toString(count)); } void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat& value) @@ -233,7 +231,7 @@ namespace MWGui int modified = static_cast(value.getModified()); MyGUI::Widget* w; - std::string valStr = boost::lexical_cast(current) + "/" + boost::lexical_cast(modified); + std::string valStr = MyGUI::utility::toString(current) + "/" + MyGUI::utility::toString(modified); if (id == "HBar") { mHealth->setProgressRange(modified); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index bc39c36d2..ed0f505f5 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -8,8 +8,6 @@ #include #include -#include - #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" @@ -542,9 +540,9 @@ namespace MWGui if (mPreviewResize || mPreviewDirty) { mArmorRating->setCaptionWithReplacing ("#{sArmor}: " - + boost::lexical_cast(static_cast(mPtr.getClass().getArmorRating(mPtr)))); + + MyGUI::utility::toString(static_cast(mPtr.getClass().getArmorRating(mPtr)))); if (mArmorRating->getTextSize().width > mArmorRating->getSize().width) - mArmorRating->setCaptionWithReplacing (boost::lexical_cast(static_cast(mPtr.getClass().getArmorRating(mPtr)))); + mArmorRating->setCaptionWithReplacing (MyGUI::utility::toString(static_cast(mPtr.getClass().getArmorRating(mPtr)))); } if (mPreviewResize) { diff --git a/apps/openmw/mwgui/itemview.cpp b/apps/openmw/mwgui/itemview.cpp index bf8bf1adf..41c3604b4 100644 --- a/apps/openmw/mwgui/itemview.cpp +++ b/apps/openmw/mwgui/itemview.cpp @@ -2,8 +2,6 @@ #include -#include - #include #include #include diff --git a/apps/openmw/mwgui/itemwidget.cpp b/apps/openmw/mwgui/itemwidget.cpp index b6a288078..36940113e 100644 --- a/apps/openmw/mwgui/itemwidget.cpp +++ b/apps/openmw/mwgui/itemwidget.cpp @@ -4,8 +4,6 @@ #include #include -#include - #include #include "../mwworld/class.hpp" @@ -17,9 +15,9 @@ namespace if (count == 1) return ""; if (count > 9999) - return boost::lexical_cast(int(count/1000.f)) + "k"; + return MyGUI::utility::toString(int(count/1000.f)) + "k"; else - return boost::lexical_cast(count); + return MyGUI::utility::toString(count); } } diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index c4b80b5fe..afff5601a 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -10,7 +10,6 @@ #include #include -#include #include #include @@ -74,7 +73,7 @@ namespace void setText (char const * name, value_type const & value) { getWidget (name) -> - setCaption (boost::lexical_cast (value)); + setCaption (MyGUI::utility::toString (value)); } void setVisible (char const * name, bool visible) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index cf8326b5c..0f9fa2775 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -1,7 +1,5 @@ #include "mapwindow.hpp" -#include - #include #include @@ -235,8 +233,8 @@ namespace MWGui { for (int my=0; my<3; ++my) { - std::string image = mPrefix+"_"+ boost::lexical_cast(mCurX + (mx-1)) + "_" - + boost::lexical_cast(mCurY + (-1*(my-1))); + std::string image = mPrefix+"_"+ MyGUI::utility::toString(mCurX + (mx-1)) + "_" + + MyGUI::utility::toString(mCurY + (-1*(my-1))); MyGUI::ImageBox* fog = mFogWidgets[my + 3*mx]; fog->setImageTexture(mFogOfWar ? ((MyGUI::RenderManager::getInstance().getTexture(image+"_fog") != 0) ? image+"_fog" @@ -362,8 +360,8 @@ namespace MWGui for (int my=0; my<3; ++my) { // map - std::string image = mPrefix+"_"+ boost::lexical_cast(x + (mx-1)) + "_" - + boost::lexical_cast(y + (-1*(my-1))); + std::string image = mPrefix+"_"+ MyGUI::utility::toString(x + (mx-1)) + "_" + + MyGUI::utility::toString(y + (-1*(my-1))); MyGUI::ImageBox* box = mMapWidgets[my + 3*mx]; diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 3f2f2ba02..907c664b1 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -2,8 +2,6 @@ #include -#include - #include #include #include @@ -71,7 +69,7 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor) std::string name = iter->getClass().getName(*iter) - + " - " + boost::lexical_cast(price) + + " - " + MyGUI::utility::toString(price) + MWBase::Environment::get().getWorld()->getStore().get() .find("sgp")->getString(); @@ -87,7 +85,7 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor) currentY += 18; - button->setUserString("Price", boost::lexical_cast(price)); + button->setUserString("Price", MyGUI::utility::toString(price)); button->setUserData(*iter); button->setCaptionWithReplacing(name); button->setSize(button->getTextSize().width,18); @@ -102,7 +100,7 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor) mList->setVisibleVScroll(true); mGoldLabel->setCaptionWithReplacing("#{sGold}: " - + boost::lexical_cast(playerGold)); + + MyGUI::utility::toString(playerGold)); } void MerchantRepair::onMouseWheel(MyGUI::Widget* _sender, int _rel) @@ -127,7 +125,7 @@ void MerchantRepair::onRepairButtonClick(MyGUI::Widget *sender) { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - int price = boost::lexical_cast(sender->getUserString("Price")); + int price = MyGUI::utility::parseInt(sender->getUserString("Price")); if (price > player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId)) return; diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 6e10e4a97..deba64434 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -1,7 +1,5 @@ #include "quickkeysmenu.hpp" -#include - #include #include #include @@ -57,7 +55,7 @@ namespace MWGui for (int i = 0; i < 10; ++i) { ItemWidget* button; - getWidget(button, "QuickKey" + boost::lexical_cast(i+1)); + getWidget(button, "QuickKey" + MyGUI::utility::toString(i+1)); button->eventMouseButtonClick += MyGUI::newDelegate(this, &QuickKeysMenu::onQuickKeyButtonClicked); @@ -100,7 +98,7 @@ namespace MWGui MyGUI::TextBox* textBox = key->createWidgetReal("SandText", MyGUI::FloatCoord(0,0,1,1), MyGUI::Align::Default); textBox->setTextAlign (MyGUI::Align::Center); - textBox->setCaption (boost::lexical_cast(index+1)); + textBox->setCaption (MyGUI::utility::toString(index+1)); textBox->setNeedMouseFocus (false); } diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 9c5091b2b..f6aa8ee4c 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -5,7 +5,6 @@ #include #include -#include #include #include "../mwworld/esmstore.hpp" @@ -402,7 +401,7 @@ namespace MWGui continue; skillWidget = mSkillList->createWidget("MW_StatNameValue", coord1, MyGUI::Align::Default, - std::string("Skill") + boost::lexical_cast(i)); + std::string("Skill") + MyGUI::utility::toString(i)); skillWidget->setSkillNumber(skillId); skillWidget->setSkillValue(Widgets::MWSkill::SkillValue(race->mData.mBonus[i].mBonus)); ToolTips::createSkillToolTip(skillWidget, skillId); @@ -436,7 +435,7 @@ namespace MWGui for (int i = 0; it != end; ++it) { const std::string &spellpower = *it; - Widgets::MWSpellPtr spellPowerWidget = mSpellPowerList->createWidget("MW_StatName", coord, MyGUI::Align::Default, std::string("SpellPower") + boost::lexical_cast(i)); + Widgets::MWSpellPtr spellPowerWidget = mSpellPowerList->createWidget("MW_StatName", coord, MyGUI::Align::Default, std::string("SpellPower") + MyGUI::utility::toString(i)); spellPowerWidget->setSpellId(spellpower); spellPowerWidget->setUserString("ToolTipType", "Spell"); spellPowerWidget->setUserString("Spell", spellpower); diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 81e36c958..2c854a8f5 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -1,6 +1,5 @@ #include "recharge.hpp" -#include #include #include @@ -66,7 +65,7 @@ void Recharge::updateView() std::string soul = gem.getCellRef().getSoul(); const ESM::Creature *creature = MWBase::Environment::get().getWorld()->getStore().get().find(soul); - mChargeLabel->setCaptionWithReplacing("#{sCharges} " + boost::lexical_cast(creature->mData.mSoul)); + mChargeLabel->setCaptionWithReplacing("#{sCharges} " + MyGUI::utility::toString(creature->mData.mSoul)); bool toolBoxVisible = (gem.getRefData().getCount() != 0); mGemBox->setVisible(toolBoxVisible); diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index 56ce09c84..c3c971400 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -2,8 +2,6 @@ #include -#include - #include #include @@ -68,7 +66,7 @@ void Repair::updateRepairView() std::stringstream qualityStr; qualityStr << std::setprecision(3) << quality; - mUsesLabel->setCaptionWithReplacing("#{sUses} " + boost::lexical_cast(uses)); + mUsesLabel->setCaptionWithReplacing("#{sUses} " + MyGUI::utility::toString(uses)); mQualityLabel->setCaptionWithReplacing("#{sQuality} " + qualityStr.str()); bool toolBoxVisible = (mRepair.getTool().getRefData().getCount() != 0); diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 2f52aae85..1bcd2d31a 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -4,8 +4,6 @@ #include #include -#include - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" @@ -77,7 +75,7 @@ namespace MWGui Widgets::MWAttributePtr attribute; for (int idx = 0; idx < ESM::Attribute::Length; ++idx) { - getWidget(attribute, std::string("Attribute") + boost::lexical_cast(idx)); + getWidget(attribute, std::string("Attribute") + MyGUI::utility::toString(idx)); mAttributeWidgets.insert(std::make_pair(static_cast(ESM::Attribute::sAttributeIds[idx]), attribute)); attribute->setAttributeId(ESM::Attribute::sAttributeIds[idx]); attribute->setAttributeValue(Widgets::MWAttribute::AttributeValue()); @@ -149,21 +147,21 @@ namespace MWGui void ReviewDialog::setHealth(const MWMechanics::DynamicStat& value) { mHealth->setValue(value.getCurrent(), value.getModified()); - std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); + std::string valStr = MyGUI::utility::toString(value.getCurrent()) + "/" + MyGUI::utility::toString(value.getModified()); mHealth->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); } void ReviewDialog::setMagicka(const MWMechanics::DynamicStat& value) { mMagicka->setValue(value.getCurrent(), value.getModified()); - std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); + std::string valStr = MyGUI::utility::toString(value.getCurrent()) + "/" + MyGUI::utility::toString(value.getModified()); mMagicka->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); } void ReviewDialog::setFatigue(const MWMechanics::DynamicStat& value) { mFatigue->setValue(value.getCurrent(), value.getModified()); - std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); + std::string valStr = MyGUI::utility::toString(value.getCurrent()) + "/" + MyGUI::utility::toString(value.getModified()); mFatigue->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); } @@ -183,7 +181,7 @@ namespace MWGui if (widget) { float modified = value.getModified(), base = value.getBase(); - std::string text = boost::lexical_cast(std::floor(modified)); + std::string text = MyGUI::utility::toString(std::floor(modified)); std::string state = "normal"; if (modified > base) state = "increased"; @@ -303,7 +301,7 @@ namespace MWGui state = "increased"; else if (modified < base) state = "decreased"; - MyGUI::TextBox* widget = addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString(skillNameId, skillNameId), boost::lexical_cast(static_cast(modified)), state, coord1, coord2); + MyGUI::TextBox* widget = addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString(skillNameId, skillNameId), MyGUI::utility::toString(static_cast(modified)), state, coord1, coord2); for (int i=0; i<2; ++i) { diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index f170559b0..f8741a67a 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -9,7 +9,6 @@ #include #include -#include #include #include @@ -54,8 +53,8 @@ namespace assert (split.size() >= 2); boost::trim(split[0]); boost::trim(split[1]); - x = boost::lexical_cast (split[0]); - y = boost::lexical_cast (split[1]); + x = MyGUI::utility::parseInt (split[0]); + y = MyGUI::utility::parseInt (split[1]); } bool sortResolutions (std::pair left, std::pair right) @@ -73,7 +72,7 @@ namespace // special case: 8 : 5 is usually referred to as 16:10 if (xaspect == 8 && yaspect == 5) return "16 : 10"; - return boost::lexical_cast(xaspect) + " : " + boost::lexical_cast(yaspect); + return MyGUI::utility::toString(xaspect) + " : " + MyGUI::utility::toString(yaspect); } std::string hlslGlsl () @@ -111,9 +110,9 @@ namespace min = 0.f; max = 1.f; if (!widget->getUserString(settingMin).empty()) - min = boost::lexical_cast(widget->getUserString(settingMin)); + min = MyGUI::utility::parseFloat(widget->getUserString(settingMin)); if (!widget->getUserString(settingMax).empty()) - max = boost::lexical_cast(widget->getUserString(settingMax)); + max = MyGUI::utility::parseFloat(widget->getUserString(settingMax)); } } @@ -230,7 +229,7 @@ namespace MWGui for (std::vector < std::pair >::const_iterator it=resolutions.begin(); it!=resolutions.end(); ++it) { - std::string str = boost::lexical_cast(it->first) + " x " + boost::lexical_cast(it->second) + std::string str = MyGUI::utility::toString(it->first) + " x " + MyGUI::utility::toString(it->second) + " (" + getAspect(it->first,it->second) + ")"; if (mResolutionList->findItemIndexWith(str) == MyGUI::ITEM_NONE) @@ -239,7 +238,7 @@ namespace MWGui std::string tf = Settings::Manager::getString("texture filtering", "General"); mTextureFilteringButton->setCaption(textureFilteringToStr(tf)); - mAnisotropyLabel->setCaption("Anisotropy (" + boost::lexical_cast(Settings::Manager::getInt("anisotropy", "General")) + ")"); + mAnisotropyLabel->setCaption("Anisotropy (" + MyGUI::utility::toString(Settings::Manager::getInt("anisotropy", "General")) + ")"); mShadowsTextureSize->setCaption (Settings::Manager::getString ("texture size", "Shadows")); @@ -255,11 +254,11 @@ namespace MWGui MyGUI::TextBox* fovText; getWidget(fovText, "FovText"); - fovText->setCaption("Field of View (" + boost::lexical_cast(int(Settings::Manager::getInt("field of view", "General"))) + ")"); + fovText->setCaption("Field of View (" + MyGUI::utility::toString(int(Settings::Manager::getInt("field of view", "General"))) + ")"); MyGUI::TextBox* diffText; getWidget(diffText, "DifficultyText"); - diffText->setCaptionWithReplacing("#{sDifficulty} (" + boost::lexical_cast(int(Settings::Manager::getInt("difficulty", "Game"))) + ")"); + diffText->setCaptionWithReplacing("#{sDifficulty} (" + MyGUI::utility::toString(int(Settings::Manager::getInt("difficulty", "Game"))) + ")"); mWindowBorderButton->setEnabled(!Settings::Manager::getBool("fullscreen", "Video")); } @@ -431,13 +430,13 @@ namespace MWGui { MyGUI::TextBox* fovText; getWidget(fovText, "FovText"); - fovText->setCaption("Field of View (" + boost::lexical_cast(int(value)) + ")"); + fovText->setCaption("Field of View (" + MyGUI::utility::toString(int(value)) + ")"); } if (scroller == mDifficultySlider) { MyGUI::TextBox* diffText; getWidget(diffText, "DifficultyText"); - diffText->setCaptionWithReplacing("#{sDifficulty} (" + boost::lexical_cast(int(value)) + ")"); + diffText->setCaptionWithReplacing("#{sDifficulty} (" + MyGUI::utility::toString(int(value)) + ")"); } } else @@ -445,7 +444,7 @@ namespace MWGui Settings::Manager::setInt(getSettingName(scroller), getSettingCategory(scroller), pos); if (scroller == mAnisotropySlider) { - mAnisotropyLabel->setCaption("Anisotropy (" + boost::lexical_cast(pos) + ")"); + mAnisotropyLabel->setCaption("Anisotropy (" + MyGUI::utility::toString(pos) + ")"); } } apply(); diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 9c3534d4a..54094b606 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -1,7 +1,5 @@ #include "spellbuyingwindow.hpp" -#include - #include #include #include @@ -69,7 +67,7 @@ namespace MWGui mCurrentY += sLineHeight; toAdd->setUserData(price); - toAdd->setCaptionWithReplacing(spell->mName+" - "+boost::lexical_cast(price)+"#{sgp}"); + toAdd->setCaptionWithReplacing(spell->mName+" - "+MyGUI::utility::toString(price)+"#{sgp}"); toAdd->setSize(toAdd->getTextSize().width,sLineHeight); toAdd->eventMouseWheel += MyGUI::newDelegate(this, &SpellBuyingWindow::onMouseWheel); toAdd->setUserString("ToolTipType", "Spell"); @@ -170,7 +168,7 @@ namespace MWGui MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); - mPlayerGold->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(playerGold)); + mPlayerGold->setCaptionWithReplacing("#{sGold}: " + MyGUI::utility::toString(playerGold)); mPlayerGold->setCoord(8, mPlayerGold->getTop(), mPlayerGold->getTextSize().width, diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 275762d15..1ff379c0b 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -1,7 +1,5 @@ #include "spellcreationdialog.hpp" -#include - #include #include @@ -269,7 +267,7 @@ namespace MWGui void EditEffectDialog::onMagnitudeMinChanged (MyGUI::ScrollBar* sender, size_t pos) { - mMagnitudeMinValue->setCaption(boost::lexical_cast(pos+1)); + mMagnitudeMinValue->setCaption(MyGUI::utility::toString(pos+1)); mEffect.mMagnMin = pos+1; // trigger the check again (see below) @@ -289,21 +287,21 @@ namespace MWGui mEffect.mMagnMax = pos+1; - mMagnitudeMaxValue->setCaption("- " + boost::lexical_cast(pos+1)); + mMagnitudeMaxValue->setCaption("- " + MyGUI::utility::toString(pos+1)); eventEffectModified(mEffect); } void EditEffectDialog::onDurationChanged (MyGUI::ScrollBar* sender, size_t pos) { - mDurationValue->setCaption(boost::lexical_cast(pos+1)); + mDurationValue->setCaption(MyGUI::utility::toString(pos+1)); mEffect.mDuration = pos+1; eventEffectModified(mEffect); } void EditEffectDialog::onAreaChanged (MyGUI::ScrollBar* sender, size_t pos) { - mAreaValue->setCaption(boost::lexical_cast(pos)); + mAreaValue->setCaption(MyGUI::utility::toString(pos)); mEffect.mArea = pos; eventEffectModified(mEffect); } @@ -365,7 +363,7 @@ namespace MWGui MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); - if (boost::lexical_cast(mPriceLabel->getCaption()) > playerGold) + if (MyGUI::utility::parseInt(mPriceLabel->getCaption()) > playerGold) { MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage18}"); return; @@ -373,7 +371,7 @@ namespace MWGui mSpell.mName = mNameEdit->getCaption(); - int price = boost::lexical_cast(mPriceLabel->getCaption()); + int price = MyGUI::utility::parseInt(mPriceLabel->getCaption()); player.getClass().getContainerStore(player).remove(MWWorld::ContainerStore::sGoldId, price, player); @@ -451,17 +449,17 @@ namespace MWGui mSpell.mData.mType = ESM::Spell::ST_Spell; mSpell.mData.mFlags = 0; - mMagickaCost->setCaption(boost::lexical_cast(int(y))); + mMagickaCost->setCaption(MyGUI::utility::toString(int(y))); float fSpellMakingValueMult = store.get().find("fSpellMakingValueMult")->getFloat(); int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,int(y) * fSpellMakingValueMult,true); - mPriceLabel->setCaption(boost::lexical_cast(int(price))); + mPriceLabel->setCaption(MyGUI::utility::toString(int(price))); float chance = MWMechanics::getSpellSuccessChance(&mSpell, MWBase::Environment::get().getWorld()->getPlayerPtr()); - mSuccessChance->setCaption(boost::lexical_cast(int(chance))); + mSuccessChance->setCaption(MyGUI::utility::toString(int(chance))); } // ------------------------------------------------------------------------------------------------ diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index 7edc6c8da..20c6f3ba8 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -3,8 +3,6 @@ #include #include -#include - #include #include @@ -117,7 +115,7 @@ namespace MWGui } else if ( displayType != ESM::MagicEffect::MDT_None ) { - sourcesDescription += ": " + boost::lexical_cast(effectIt->mMagnitude); + sourcesDescription += ": " + MyGUI::utility::toString(effectIt->mMagnitude); if ( displayType == ESM::MagicEffect::MDT_Percentage ) sourcesDescription += MWBase::Environment::get().getWindowManager()->getGameSettingString("spercent", ""); diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index e565b6f0e..b5abf91fd 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -6,8 +6,6 @@ #include #include -#include - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" @@ -151,7 +149,7 @@ namespace MWGui // health, magicka, fatigue tooltip MyGUI::Widget* w; - std::string valStr = boost::lexical_cast(current) + "/" + boost::lexical_cast(modified); + std::string valStr = MyGUI::utility::toString(current) + "/" + MyGUI::utility::toString(modified); if (id == "HBar") { getWidget(w, "Health"); @@ -196,7 +194,7 @@ namespace MWGui if (widget) { int modified = value.getModified(), base = value.getBase(); - std::string text = boost::lexical_cast(modified); + std::string text = MyGUI::utility::toString(modified); std::string state = "normal"; if (modified > base) state = "increased"; @@ -245,10 +243,10 @@ namespace MWGui { int max = MWBase::Environment::get().getWorld()->getStore().get().find("iLevelUpTotal")->getInt(); getWidget(levelWidget, i==0 ? "Level_str" : "LevelText"); - levelWidget->setUserString("RangePosition_LevelProgress", boost::lexical_cast(PCstats.getLevelProgress())); - levelWidget->setUserString("Range_LevelProgress", boost::lexical_cast(max)); - levelWidget->setUserString("Caption_LevelProgressText", boost::lexical_cast(PCstats.getLevelProgress()) + "/" - + boost::lexical_cast(max)); + levelWidget->setUserString("RangePosition_LevelProgress", MyGUI::utility::toString(PCstats.getLevelProgress())); + levelWidget->setUserString("Range_LevelProgress", MyGUI::utility::toString(max)); + levelWidget->setUserString("Caption_LevelProgressText", MyGUI::utility::toString(PCstats.getLevelProgress()) + "/" + + MyGUI::utility::toString(max)); } setFactions(PCstats.getFactionRanks()); @@ -403,7 +401,7 @@ namespace MWGui else if (modified < base) state = "decreased"; MyGUI::TextBox* widget = addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString(skillNameId, skillNameId), - boost::lexical_cast(static_cast(modified)), state, coord1, coord2); + MyGUI::utility::toString(static_cast(modified)), state, coord1, coord2); for (int i=0; i<2; ++i) { @@ -421,9 +419,9 @@ namespace MWGui mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Visible_SkillProgressVBox", "true"); mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("UserData^Hidden_SkillProgressVBox", "false"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillProgressText", boost::lexical_cast(progressPercent)+"/100"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillProgressText", MyGUI::utility::toString(progressPercent)+"/100"); mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Range_SkillProgress", "100"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("RangePosition_SkillProgress", boost::lexical_cast(progressPercent)); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("RangePosition_SkillProgress", MyGUI::utility::toString(progressPercent)); } else { mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Visible_SkillMaxed", "true"); mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("UserData^Hidden_SkillMaxed", "false"); @@ -534,8 +532,8 @@ namespace MWGui const ESM::Attribute* attr1 = store.get().find(faction->mData.mAttribute[0]); const ESM::Attribute* attr2 = store.get().find(faction->mData.mAttribute[1]); - text += "\n#{fontcolourhtml=normal}#{" + attr1->mName + "}: " + boost::lexical_cast(rankData.mAttribute1) - + ", #{" + attr2->mName + "}: " + boost::lexical_cast(rankData.mAttribute2); + text += "\n#{fontcolourhtml=normal}#{" + attr1->mName + "}: " + MyGUI::utility::toString(rankData.mAttribute1) + + ", #{" + attr2->mName + "}: " + MyGUI::utility::toString(rankData.mAttribute2); text += "\n\n#{fontcolourhtml=header}#{sFavoriteSkills}"; text += "\n#{fontcolourhtml=normal}"; @@ -556,9 +554,9 @@ namespace MWGui text += "\n"; if (rankData.mSkill1 > 0) - text += "\n#{sNeedOneSkill} " + boost::lexical_cast(rankData.mSkill1); + text += "\n#{sNeedOneSkill} " + MyGUI::utility::toString(rankData.mSkill1); if (rankData.mSkill2 > 0) - text += "\n#{sNeedTwoSkills} " + boost::lexical_cast(rankData.mSkill2); + text += "\n#{sNeedTwoSkills} " + MyGUI::utility::toString(rankData.mSkill2); } } @@ -587,7 +585,7 @@ namespace MWGui addSeparator(coord1, coord2); addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString("sReputation", "Reputation"), - boost::lexical_cast(static_cast(mReputation)), "normal", coord1, coord2); + MyGUI::utility::toString(static_cast(mReputation)), "normal", coord1, coord2); for (int i=0; i<2; ++i) { @@ -597,7 +595,7 @@ namespace MWGui } addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString("sBounty", "Bounty"), - boost::lexical_cast(static_cast(mBounty)), "normal", coord1, coord2); + MyGUI::utility::toString(static_cast(mBounty)), "normal", coord1, coord2); for (int i=0; i<2; ++i) { diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 3f3540a21..303b8819f 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -7,8 +7,6 @@ #include #include -#include - #include #include "../mwbase/world.hpp" @@ -556,7 +554,7 @@ namespace MWGui if (value == 1) return ""; else - return " (" + boost::lexical_cast(value) + ")"; + return " (" + MyGUI::utility::toString(value) + ")"; } std::string ToolTips::getCellRefString(const MWWorld::CellRef& cellref) diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index fc9167f3c..88ba62cc1 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -1,7 +1,5 @@ #include "trainingwindow.hpp" -#include - #include #include "../mwbase/windowmanager.hpp" @@ -67,7 +65,7 @@ namespace MWGui MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); - mPlayerGold->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(playerGold)); + mPlayerGold->setCaptionWithReplacing("#{sGold}: " + MyGUI::utility::toString(playerGold)); MWMechanics::NpcStats& npcStats = actor.getClass().getNpcStats (actor); @@ -102,7 +100,7 @@ namespace MWGui button->setUserData(skills[i].first); button->eventMouseButtonClick += MyGUI::newDelegate(this, &TrainingWindow::onTrainingSelected); - button->setCaptionWithReplacing("#{" + ESM::Skill::sSkillNameIds[skills[i].first] + "} - " + boost::lexical_cast(price)); + button->setCaptionWithReplacing("#{" + ESM::Skill::sSkillNameIds[skills[i].first] + "} - " + MyGUI::utility::toString(price)); button->setSize(button->getTextSize ().width+12, button->getSize().height); diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 3d37d0ab0..50e08223e 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -1,7 +1,5 @@ #include "travelwindow.hpp" -#include - #include #include #include @@ -91,7 +89,7 @@ namespace MWGui oss << price; toAdd->setUserString("price",oss.str()); - toAdd->setCaptionWithReplacing("#{sCell=" + name + "} - " + boost::lexical_cast(price)+"#{sgp}"); + toAdd->setCaptionWithReplacing("#{sCell=" + name + "} - " + MyGUI::utility::toString(price)+"#{sgp}"); toAdd->setSize(toAdd->getTextSize().width,sLineHeight); toAdd->eventMouseWheel += MyGUI::newDelegate(this, &TravelWindow::onMouseWheel); toAdd->setUserString("Destination", name); @@ -196,7 +194,7 @@ namespace MWGui MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); - mPlayerGold->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(playerGold)); + mPlayerGold->setCaptionWithReplacing("#{sGold}: " + MyGUI::utility::toString(playerGold)); mPlayerGold->setCoord(8, mPlayerGold->getTop(), mPlayerGold->getTextSize().width, diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 6f87bffe0..c53a887c9 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -1,7 +1,5 @@ #include "waitdialog.hpp" -#include - #include #include @@ -40,7 +38,7 @@ namespace MWGui { mProgressBar->setProgressRange (total); mProgressBar->setProgressPosition (cur); - mProgressText->setCaption(boost::lexical_cast(cur) + "/" + boost::lexical_cast(total)); + mProgressText->setCaption(MyGUI::utility::toString(cur) + "/" + MyGUI::utility::toString(total)); } // --------------------------------------------------------------------------------------------------------- @@ -106,9 +104,9 @@ namespace MWGui if (hour == 0) hour = 12; std::string dateTimeText = - boost::lexical_cast(MWBase::Environment::get().getWorld ()->getDay ()) + " " - + month + " (#{sDay} " + boost::lexical_cast(MWBase::Environment::get().getWorld ()->getTimeStamp ().getDay()) - + ") " + boost::lexical_cast(hour) + " " + (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}"); + MyGUI::utility::toString(MWBase::Environment::get().getWorld ()->getDay ()) + " " + + month + " (#{sDay} " + MyGUI::utility::toString(MWBase::Environment::get().getWorld ()->getTimeStamp ().getDay()) + + ") " + MyGUI::utility::toString(hour) + " " + (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}"); mDateTimeText->setCaptionWithReplacing (dateTimeText); } @@ -174,7 +172,7 @@ namespace MWGui void WaitDialog::onHourSliderChangedPosition(MyGUI::ScrollBar* sender, size_t position) { - mHourText->setCaptionWithReplacing (boost::lexical_cast(position+1) + " #{sRestMenu2}"); + mHourText->setCaptionWithReplacing (MyGUI::utility::toString(position+1) + " #{sRestMenu2}"); mManualHours = position+1; } diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 381fc301e..26fe31567 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -3,8 +3,6 @@ #include #include -#include - #include #include #include @@ -74,7 +72,7 @@ namespace MWGui if (mSkillValueWidget) { SkillValue::Type modified = mValue.getModified(), base = mValue.getBase(); - mSkillValueWidget->setCaption(boost::lexical_cast(modified)); + mSkillValueWidget->setCaption(MyGUI::utility::toString(modified)); if (modified > base) mSkillValueWidget->_setWidgetState("increased"); else if (modified < base) @@ -170,7 +168,7 @@ namespace MWGui if (mAttributeValueWidget) { int modified = mValue.getModified(), base = mValue.getBase(); - mAttributeValueWidget->setCaption(boost::lexical_cast(modified)); + mAttributeValueWidget->setCaption(MyGUI::utility::toString(modified)); if (modified > base) mAttributeValueWidget->_setWidgetState("increased"); else if (modified < base) @@ -432,9 +430,9 @@ namespace MWGui spellLine += formatter.str(); } else if ( displayType != ESM::MagicEffect::MDT_None ) { - spellLine += " " + boost::lexical_cast(mEffectParams.mMagnMin); + spellLine += " " + MyGUI::utility::toString(mEffectParams.mMagnMin); if (mEffectParams.mMagnMin != mEffectParams.mMagnMax) - spellLine += to + boost::lexical_cast(mEffectParams.mMagnMax); + spellLine += to + MyGUI::utility::toString(mEffectParams.mMagnMax); if ( displayType == ESM::MagicEffect::MDT_Percentage ) spellLine += pct; @@ -452,12 +450,12 @@ namespace MWGui { if (mEffectParams.mDuration > 0 && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)) { - spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sfor", "") + " " + boost::lexical_cast(mEffectParams.mDuration) + ((mEffectParams.mDuration == 1) ? sec : secs); + spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sfor", "") + " " + MyGUI::utility::toString(mEffectParams.mDuration) + ((mEffectParams.mDuration == 1) ? sec : secs); } if (mEffectParams.mArea > 0) { - spellLine += " #{sin} " + boost::lexical_cast(mEffectParams.mArea) + " #{sfootarea}"; + spellLine += " #{sin} " + MyGUI::utility::toString(mEffectParams.mArea) + " #{sfootarea}"; } // potions have no target From 063388e0eb6113d617a437ec5ef0f52fb601cdc1 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 10 Jan 2015 15:04:45 +1300 Subject: [PATCH 149/740] Change "Profile" to "Content List" in user visible strings in Launcher. (Fixes #810) --- apps/launcher/datafilespage.cpp | 10 +++++----- apps/launcher/settingspage.cpp | 2 +- files/ui/datafilespage.ui | 18 +++++++++--------- files/ui/playpage.ui | 2 +- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index a0ef97ff9..8fca73c89 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -30,7 +30,7 @@ Launcher::DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, Config: setObjectName ("DataFilesPage"); mSelector = new ContentSelectorView::ContentSelector (ui.contentSelectorWidget); - mProfileDialog = new TextInputDialog(tr("New Profile"), tr("Profile name:"), this); + mProfileDialog = new TextInputDialog(tr("New Content List"), tr("Content List name:"), this); connect(mProfileDialog->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(updateOkButton(QString))); @@ -44,12 +44,12 @@ void Launcher::DataFilesPage::buildView() ui.verticalLayout->insertWidget (0, mSelector->uiWidget()); //tool buttons - ui.newProfileButton->setToolTip ("Create a new profile"); - ui.deleteProfileButton->setToolTip ("Delete an existing profile"); + ui.newProfileButton->setToolTip ("Create a new Content List"); + ui.deleteProfileButton->setToolTip ("Delete an existing Content List"); //combo box ui.profilesComboBox->addItem ("Default"); - ui.profilesComboBox->setPlaceholderText (QString("Select a profile...")); + ui.profilesComboBox->setPlaceholderText (QString("Select a Content List...")); ui.profilesComboBox->setCurrentIndex(ui.profilesComboBox->findText(QLatin1String("Default"))); // Add the actions to the toolbuttons @@ -306,7 +306,7 @@ void Launcher::DataFilesPage::checkForDefaultProfile() bool Launcher::DataFilesPage::showDeleteMessageBox (const QString &text) { QMessageBox msgBox(this); - msgBox.setWindowTitle(tr("Delete Profile")); + msgBox.setWindowTitle(tr("Delete Content List")); msgBox.setIcon(QMessageBox::Warning); msgBox.setStandardButtons(QMessageBox::Cancel); msgBox.setText(tr("Are you sure you want to delete %0?").arg(text)); diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index 5422e7957..26908746b 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -51,7 +51,7 @@ Launcher::SettingsPage::SettingsPage(Files::ConfigurationManager &cfg, connect(mImporterInvoker->getProcess(), SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(importerFinished(int,QProcess::ExitStatus))); - mProfileDialog = new TextInputDialog(tr("New Profile"), tr("Profile name:"), this); + mProfileDialog = new TextInputDialog(tr("New Content List"), tr("Content List name:"), this); connect(mProfileDialog->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(updateOkButton(QString))); diff --git a/files/ui/datafilespage.ui b/files/ui/datafilespage.ui index eb5ebc61d..5a6b7265a 100644 --- a/files/ui/datafilespage.ui +++ b/files/ui/datafilespage.ui @@ -29,7 +29,7 @@ Qt::NoFocus
- Profile + Content List false @@ -69,10 +69,10 @@ - New Profile + New Content List - &New Profile + &New Content List true @@ -82,10 +82,10 @@ - Delete Profile + Delete Content List - Delete Profile + Delete Content List Ctrl+D @@ -106,10 +106,10 @@ - New Profile + New Content List - New Profile + New Content List Ctrl+N @@ -125,10 +125,10 @@ - Delete Profile + Delete Content List - Delete Profile + Delete Content List diff --git a/files/ui/playpage.ui b/files/ui/playpage.ui index bf883b96e..1d529e2d7 100644 --- a/files/ui/playpage.ui +++ b/files/ui/playpage.ui @@ -101,7 +101,7 @@
- Current Profile: + Current Content List: From 5b9d10f85156a41581ea29bbcbc9e5ce2f3e48b5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 03:56:06 +0100 Subject: [PATCH 150/740] Reduce includes in MWGui --- apps/openmw/mwgui/birth.hpp | 5 ----- apps/openmw/mwgui/class.hpp | 5 ----- apps/openmw/mwgui/companionwindow.cpp | 1 + apps/openmw/mwgui/dialogue.hpp | 5 ----- apps/openmw/mwgui/enchantingdialog.cpp | 5 +++++ apps/openmw/mwgui/hud.hpp | 6 +++++- apps/openmw/mwgui/journalwindow.hpp | 1 - apps/openmw/mwgui/loadingscreen.cpp | 1 + apps/openmw/mwgui/loadingscreen.hpp | 7 ++++++- apps/openmw/mwgui/merchantrepair.hpp | 2 -- apps/openmw/mwgui/messagebox.cpp | 1 + apps/openmw/mwgui/messagebox.hpp | 2 -- apps/openmw/mwgui/race.cpp | 6 ++++++ apps/openmw/mwgui/race.hpp | 17 ++++++++++------- apps/openmw/mwgui/recharge.hpp | 5 ++++- apps/openmw/mwgui/review.hpp | 5 ----- apps/openmw/mwgui/scrollwindow.cpp | 1 + apps/openmw/mwgui/scrollwindow.hpp | 7 +++++-- apps/openmw/mwgui/soulgemdialog.cpp | 1 + apps/openmw/mwgui/spellcreationdialog.cpp | 2 ++ apps/openmw/mwgui/spellcreationdialog.hpp | 7 +++++-- apps/openmw/mwgui/statswindow.cpp | 1 + apps/openmw/mwgui/statswindow.hpp | 4 ++-- apps/openmw/mwgui/waitdialog.cpp | 2 ++ apps/openmw/mwgui/waitdialog.hpp | 6 +++++- apps/openmw/mwgui/windowmanagerimp.cpp | 2 ++ 26 files changed, 65 insertions(+), 42 deletions(-) diff --git a/apps/openmw/mwgui/birth.hpp b/apps/openmw/mwgui/birth.hpp index 257dc6fef..0a84bb4e9 100644 --- a/apps/openmw/mwgui/birth.hpp +++ b/apps/openmw/mwgui/birth.hpp @@ -3,11 +3,6 @@ #include "windowbase.hpp" -/* - This file contains the dialog for choosing a birth sign. - Layout is defined by resources/mygui/openmw_chargen_race.layout. - */ - namespace MWGui { class BirthDialog : public WindowModal diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index 9d529ece0..e36a9a98b 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -6,11 +6,6 @@ #include "widgets.hpp" #include "windowbase.hpp" -/* - This file contains the dialogs for choosing a class. - Layout is defined by resources/mygui/openmw_chargen_class.layout. - */ - namespace MWGui { class InfoBoxDialog : public WindowModal diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index 758316030..53b14691b 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -4,6 +4,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/dialoguemanager.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwmechanics/npcstats.hpp" diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 4ab88c06f..769c32af7 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -18,11 +18,6 @@ namespace MWGui class WindowManager; } -/* - This file contains the dialouge window - Layout is defined by resources/mygui/openmw_dialogue_window.layout. - */ - namespace MWGui { class DialogueHistoryViewModel; diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index a17c0d0e6..3376858c1 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -3,7 +3,12 @@ #include #include + +#include +#include + #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index ca68d907a..41a535a08 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -4,7 +4,11 @@ #include "mapwindow.hpp" #include "../mwmechanics/stat.hpp" -#include "../mwworld/ptr.hpp" + +namespace MWWorld +{ + class Ptr; +} namespace MWGui { diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index 63770ec1a..5d2a5318a 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -1,7 +1,6 @@ #ifndef MWGUI_JOURNAL_H #define MWGUI_JOURNAL_H -#include #include namespace MWBase { class WindowManager; } diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 855a6fc84..d10a295c1 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 892710433..0d3ffbbec 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -1,13 +1,18 @@ #ifndef MWGUI_LOADINGSCREEN_H #define MWGUI_LOADINGSCREEN_H -#include #include +#include #include "windowbase.hpp" #include +namespace Ogre +{ + class SceneManager; +} + namespace MWGui { class BackgroundImage; diff --git a/apps/openmw/mwgui/merchantrepair.hpp b/apps/openmw/mwgui/merchantrepair.hpp index 2f1387365..231d11089 100644 --- a/apps/openmw/mwgui/merchantrepair.hpp +++ b/apps/openmw/mwgui/merchantrepair.hpp @@ -4,8 +4,6 @@ #include "windowbase.hpp" #include "../mwworld/ptr.hpp" - - namespace MWGui { diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 43debd0e5..c45136eb3 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -10,6 +10,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/inputmanager.hpp" +#include "../mwbase/windowmanager.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index 5f180df20..59804e097 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -3,8 +3,6 @@ #include "windowbase.hpp" -#include "../mwbase/windowmanager.hpp" - #undef MessageBox namespace MyGUI diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index f6aa8ee4c..b03bf758a 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -11,6 +11,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwrender/characterpreview.hpp" #include "tooltips.hpp" @@ -446,4 +447,9 @@ namespace MWGui ++i; } } + + const ESM::NPC& RaceDialog::getResult() const + { + return mPreview->getPrototype(); + } } diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index 454c1d0b6..be16af5d1 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -1,8 +1,6 @@ #ifndef MWGUI_RACE_H #define MWGUI_RACE_H -#include "../mwrender/characterpreview.hpp" - #include "windowbase.hpp" @@ -11,10 +9,15 @@ namespace MWGui class WindowManager; } -/* - This file contains the dialog for choosing a race. - Layout is defined by resources/mygui/openmw_chargen_race.layout. - */ +namespace MWRender +{ + class RaceSelectionPreview; +} + +namespace ESM +{ + struct NPC; +} namespace MWGui { @@ -29,7 +32,7 @@ namespace MWGui GM_Female }; - const ESM::NPC &getResult() const { return mPreview->getPrototype(); } + const ESM::NPC &getResult() const; const std::string &getRaceId() const { return mCurrentRaceId; } Gender getGender() const { return mGenderIndex == 0 ? GM_Male : GM_Female; } // getFace() diff --git a/apps/openmw/mwgui/recharge.hpp b/apps/openmw/mwgui/recharge.hpp index 17d700649..3e8e1269e 100644 --- a/apps/openmw/mwgui/recharge.hpp +++ b/apps/openmw/mwgui/recharge.hpp @@ -3,7 +3,10 @@ #include "windowbase.hpp" -#include "../mwworld/ptr.hpp" +namespace MWWorld +{ + class Ptr; +} namespace MWGui { diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index 1419925b5..111d7de1d 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -11,11 +11,6 @@ namespace MWGui class WindowManager; } -/* -This file contains the dialog for reviewing the generated character. -Layout is defined by resources/mygui/openmw_chargen_review.layout. -*/ - namespace MWGui { class ReviewDialog : public WindowModal diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index d49d5ad5f..d61693d39 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -3,6 +3,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index 08ce6a905..e1f86529a 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -3,10 +3,13 @@ #include "windowbase.hpp" -#include - #include "../mwworld/ptr.hpp" +namespace Gui +{ + class ImageButton; +} + namespace MWGui { class ScrollWindow : public WindowBase diff --git a/apps/openmw/mwgui/soulgemdialog.cpp b/apps/openmw/mwgui/soulgemdialog.cpp index 6d70c85d9..0232eb7b3 100644 --- a/apps/openmw/mwgui/soulgemdialog.cpp +++ b/apps/openmw/mwgui/soulgemdialog.cpp @@ -1,6 +1,7 @@ #include "soulgemdialog.hpp" #include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" #include "messagebox.hpp" diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 1ff379c0b..a00afdab8 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -5,6 +5,7 @@ #include #include +#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" @@ -22,6 +23,7 @@ #include "tooltips.hpp" #include "class.hpp" +#include "widgets.hpp" namespace { diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index 72e581c87..6cdf74d10 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -3,11 +3,14 @@ #include #include -#include #include "windowbase.hpp" #include "referenceinterface.hpp" -#include "widgets.hpp" + +namespace Gui +{ + class MWList; +} namespace MWGui { diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index b5abf91fd..19f9c749c 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -12,6 +12,7 @@ #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwmechanics/npcstats.hpp" diff --git a/apps/openmw/mwgui/statswindow.hpp b/apps/openmw/mwgui/statswindow.hpp index f41995ac0..2cf4ca819 100644 --- a/apps/openmw/mwgui/statswindow.hpp +++ b/apps/openmw/mwgui/statswindow.hpp @@ -1,11 +1,11 @@ #ifndef MWGUI_STATS_WINDOW_H #define MWGUI_STATS_WINDOW_H -#include "../mwworld/esmstore.hpp" - #include "../mwmechanics/stat.hpp" #include "windowpinnablebase.hpp" +#include + namespace MWGui { class WindowManager; diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index c53a887c9..718e04e52 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -19,6 +19,8 @@ #include "../mwstate/charactermanager.hpp" +#include "widgets.hpp" + namespace MWGui { diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index 1cf05bb06..435c1cb54 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -2,11 +2,15 @@ #define MWGUI_WAIT_DIALOG_H #include "windowbase.hpp" -#include "widgets.hpp" namespace MWGui { + namespace Widgets + { + class MWScrollBar; + } + class WaitDialogProgressBar : public WindowBase { public: diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index aa80e69fc..5d737ec41 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -34,6 +35,7 @@ #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" #include "../mwworld/cellstore.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwmechanics/npcstats.hpp" From 05b89be8bfc19a653287a90b05eb54f63b8a5609 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 10 Jan 2015 18:46:47 +1300 Subject: [PATCH 151/740] Launcher sets content list to match values in openmw.cfg (Fixes #811) I took the liberty to add accessor & mutator functions for classes ContentListsGameSettings and LauncherSettings , as existing code can reverse order of entries. Also replaced some "magic strings" with named constants. --- apps/launcher/datafilespage.cpp | 31 +++--- apps/launcher/maindialog.cpp | 10 +- apps/launcher/settingspage.cpp | 17 +--- apps/wizard/mainwizard.cpp | 4 +- components/config/gamesettings.cpp | 30 ++++-- components/config/gamesettings.hpp | 7 +- components/config/launchersettings.cpp | 134 +++++++++++++++++++++---- components/config/launchersettings.hpp | 43 +++++++- components/config/settingsbase.hpp | 4 +- 9 files changed, 207 insertions(+), 73 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 8fca73c89..8429aaadc 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -82,8 +82,8 @@ bool Launcher::DataFilesPage::loadSettings() paths.insert (0, mDataLocal); PathIterator pathIterator (paths); - QStringList profiles = mLauncherSettings.subKeys(QString("Profiles/")); - QString currentProfile = mLauncherSettings.getSettings().value("Profiles/currentprofile"); + QStringList profiles = mLauncherSettings.getContentLists(); + QString currentProfile = mLauncherSettings.getCurrentContentListName(); qDebug() << "current profile is: " << currentProfile; @@ -101,15 +101,12 @@ bool Launcher::DataFilesPage::loadSettings() QStringList Launcher::DataFilesPage::filesInProfile(const QString& profileName, PathIterator& pathIterator) { - QStringList files = mLauncherSettings.values(QString("Profiles/") + profileName + QString("/content"), Qt::MatchExactly); + QStringList files = mLauncherSettings.getContentListFiles(profileName); QStringList filepaths; - // mLauncherSettings.values() returns the files in reverse load order - QListIterator i(files); - i.toBack(); - while (i.hasPrevious()) + foreach(const QString& file, files) { - QString filepath = pathIterator.findFirstPath(i.previous()); + QString filepath = pathIterator.findFirstPath(file); if (!filepath.isEmpty()) filepaths << filepath; @@ -128,24 +125,20 @@ void Launcher::DataFilesPage::saveSettings(const QString &profile) //retrieve the files selected for the profile ContentSelectorModel::ContentFileList items = mSelector->selectedFiles(); - removeProfile (profileName); - - mGameSettings.remove(QString("content")); - //set the value of the current profile (not necessarily the profile being saved!) - mLauncherSettings.setValue(QString("Profiles/currentprofile"), ui.profilesComboBox->currentText()); + mLauncherSettings.setCurrentContentListName(ui.profilesComboBox->currentText()); + QStringList fileNames; foreach(const ContentSelectorModel::EsmFile *item, items) { - mLauncherSettings.setMultiValue(QString("Profiles/") + profileName + QString("/content"), item->fileName()); - mGameSettings.setMultiValue(QString("content"), item->fileName()); + fileNames.append(item->fileName()); } - + mLauncherSettings.setContentList(profileName, fileNames); + mGameSettings.setContentList(fileNames); } void Launcher::DataFilesPage::removeProfile(const QString &profile) { - mLauncherSettings.remove(QString("Profiles/") + profile); - mLauncherSettings.remove(QString("Profiles/") + profile + QString("/content")); + mLauncherSettings.removeContentList(profile); } QAbstractItemModel *Launcher::DataFilesPage::profilesModel() const @@ -233,7 +226,7 @@ void Launcher::DataFilesPage::on_newProfileAction_triggered() saveSettings(); - mLauncherSettings.setValue(QString("Profiles/currentprofile"), profile); + mLauncherSettings.setCurrentContentListName(profile); addProfile(profile, true); mSelector->clearCheckStates(); diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 975958d7a..00c549969 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -209,6 +209,8 @@ bool Launcher::MainDialog::setup() if (!setupGameSettings()) return false; + mLauncherSettings.setContentList(mGameSettings); + if (!setupGraphicsSettings()) return false; @@ -232,6 +234,8 @@ bool Launcher::MainDialog::reloadSettings() if (!setupGameSettings()) return false; + mLauncherSettings.setContentList(mGameSettings); + if (!setupGraphicsSettings()) return false; @@ -280,8 +284,8 @@ bool Launcher::MainDialog::setupLauncherSettings() QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); QStringList paths; - paths.append(QString("launcher.cfg")); - paths.append(userPath + QString("launcher.cfg")); + paths.append(QString(Config::LauncherSettings::sLauncherConfigFileName)); + paths.append(userPath + QString(Config::LauncherSettings::sLauncherConfigFileName)); foreach (const QString &path, paths) { qDebug() << "Loading config file:" << qPrintable(path); @@ -562,7 +566,7 @@ bool Launcher::MainDialog::writeSettings() file.close(); // Launcher settings - file.setFileName(userPath + QString("launcher.cfg")); + file.setFileName(userPath + QString(Config::LauncherSettings::sLauncherConfigFileName)); if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) { // File cannot be opened or created diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index 26908746b..ace8f4310 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -207,18 +207,9 @@ void Launcher::SettingsPage::importerFinished(int exitCode, QProcess::ExitStatus if (mProfileDialog->exec() == QDialog::Accepted) { const QString profile(mProfileDialog->lineEdit()->text()); - const QStringList files(mGameSettings.values(QLatin1String("content"))); - - qDebug() << "Profile " << profile << files; - - // Doesn't quite work right now - mLauncherSettings.setValue(QLatin1String("Profiles/currentprofile"), profile); - - foreach (const QString &file, files) { - mLauncherSettings.setMultiValue(QLatin1String("Profiles/") + profile + QLatin1String("/content"), file); - } - - mGameSettings.remove(QLatin1String("content")); + const QStringList files(mGameSettings.getContentList()); + mLauncherSettings.setCurrentContentListName(profile); + mLauncherSettings.setContentList(profile, files); } } @@ -234,7 +225,7 @@ void Launcher::SettingsPage::updateOkButton(const QString &text) return; } - const QStringList profiles(mLauncherSettings.subKeys(QString("Profiles/"))); + const QStringList profiles(mLauncherSettings.getContentLists()); (profiles.contains(text)) ? mProfileDialog->setOkButtonEnabled(false) diff --git a/apps/wizard/mainwizard.cpp b/apps/wizard/mainwizard.cpp index e68070c4d..9a8ec2056 100644 --- a/apps/wizard/mainwizard.cpp +++ b/apps/wizard/mainwizard.cpp @@ -182,7 +182,7 @@ void Wizard::MainWizard::setupGameSettings() void Wizard::MainWizard::setupLauncherSettings() { QString path(QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str())); - path.append(QLatin1String("launcher.cfg")); + path.append(QLatin1String(Config::LauncherSettings::sLauncherConfigFileName)); QString message(tr("

Could not open %1 for reading

\

Please make sure you have the right permissions \ @@ -427,7 +427,7 @@ void Wizard::MainWizard::writeSettings() file.close(); // Launcher settings - file.setFileName(userPath + QLatin1String("launcher.cfg")); + file.setFileName(userPath + QLatin1String(Config::LauncherSettings::sLauncherConfigFileName)); if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) { // File cannot be opened or created diff --git a/components/config/gamesettings.cpp b/components/config/gamesettings.cpp index 1e7f716e2..0481235c7 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -1,4 +1,5 @@ #include "gamesettings.hpp" +#include "launchersettings.hpp" #include #include @@ -26,6 +27,7 @@ namespace boost } /* namespace boost */ #endif /* (BOOST_VERSION <= 104600) */ +const char Config::GameSettings::sContentKey[] = "content"; Config::GameSettings::GameSettings(Files::ConfigurationManager &cfg) : mCfgMgr(cfg) @@ -81,7 +83,7 @@ void Config::GameSettings::validatePaths() } } -QStringList Config::GameSettings::values(const QString &key, const QStringList &defaultValues) +QStringList Config::GameSettings::values(const QString &key, const QStringList &defaultValues) const { if (!mSettings.values(key).isEmpty()) return mSettings.values(key); @@ -149,9 +151,6 @@ bool Config::GameSettings::writeFile(QTextStream &stream) while (i.hasPrevious()) { i.previous(); - if (i.key() == QLatin1String("content")) - continue; - // Quote paths with spaces if (i.key() == QLatin1String("data") || i.key() == QLatin1String("data-local") @@ -171,18 +170,13 @@ bool Config::GameSettings::writeFile(QTextStream &stream) } - QStringList content = mUserSettings.values(QString("content")); - for (int i = content.count(); i--;) { - stream << "content=" << content.at(i) << "\n"; - } - return true; } bool Config::GameSettings::hasMaster() { bool result = false; - QStringList content = mSettings.values(QString("content")); + QStringList content = mSettings.values(QString(Config::GameSettings::sContentKey)); for (int i = 0; i < content.count(); ++i) { if (content.at(i).contains(".omwgame") || content.at(i).contains(".esm")) { result = true; @@ -192,3 +186,19 @@ bool Config::GameSettings::hasMaster() return result; } + +void Config::GameSettings::setContentList(const QStringList& fileNames) +{ + remove(sContentKey); + foreach(const QString& fileName, fileNames) + { + setMultiValue(sContentKey, fileName); + } +} + +QStringList Config::GameSettings::getContentList() const +{ + // QMap returns multiple rows in LIFO order, so need to reverse + return Config::LauncherSettings::reverse(values(sContentKey)); +} + diff --git a/components/config/gamesettings.hpp b/components/config/gamesettings.hpp index c4a6ead79..cc5033f35 100644 --- a/components/config/gamesettings.hpp +++ b/components/config/gamesettings.hpp @@ -59,7 +59,7 @@ namespace Config bool hasMaster(); - QStringList values(const QString &key, const QStringList &defaultValues = QStringList()); + QStringList values(const QString &key, const QStringList &defaultValues = QStringList()) const; bool readFile(QTextStream &stream); bool readFile(QTextStream &stream, QMap &settings); @@ -67,6 +67,9 @@ namespace Config bool writeFile(QTextStream &stream); + void setContentList(const QStringList& fileNames); + QStringList getContentList() const; + private: Files::ConfigurationManager &mCfgMgr; @@ -76,6 +79,8 @@ namespace Config QStringList mDataDirs; QString mDataLocal; + + static const char sContentKey[]; }; } #endif // GAMESETTINGS_HPP diff --git a/components/config/launchersettings.cpp b/components/config/launchersettings.cpp index c014579dc..66f05f691 100644 --- a/components/config/launchersettings.cpp +++ b/components/config/launchersettings.cpp @@ -7,6 +7,11 @@ #include +const char Config::LauncherSettings::sCurrentContentListKey[] = "Profiles/currentprofile"; +const char Config::LauncherSettings::sLauncherConfigFileName[] = "launcher.cfg"; +const char Config::LauncherSettings::sContentListsSectionPrefix[] = "Profiles/"; +const char Config::LauncherSettings::sContentListSuffix[] = "/content"; + Config::LauncherSettings::LauncherSettings() { } @@ -15,27 +20,6 @@ Config::LauncherSettings::~LauncherSettings() { } -QStringList Config::LauncherSettings::values(const QString &key, Qt::MatchFlags flags) -{ - QMap settings = SettingsBase::getSettings(); - - if (flags == Qt::MatchExactly) - return settings.values(key); - - QStringList result; - - if (flags == Qt::MatchStartsWith) { - QStringList keys = settings.keys(); - - foreach (const QString ¤tKey, keys) { - if (currentKey.startsWith(key)) - result.append(settings.value(currentKey)); - } - } - - return result; -} - QStringList Config::LauncherSettings::subKeys(const QString &key) { QMap settings = SettingsBase::getSettings(); @@ -66,6 +50,7 @@ QStringList Config::LauncherSettings::subKeys(const QString &key) return result; } + bool Config::LauncherSettings::writeFile(QTextStream &stream) { QString sectionPrefix; @@ -104,3 +89,110 @@ bool Config::LauncherSettings::writeFile(QTextStream &stream) return true; } + +QStringList Config::LauncherSettings::getContentLists() +{ + return subKeys(QString(sContentListsSectionPrefix)); +} + +QString Config::LauncherSettings::makeContentListKey(const QString& contentListName) +{ + return QString(sContentListsSectionPrefix) + contentListName + QString(sContentListSuffix); +} + +void Config::LauncherSettings::setContentList(const GameSettings& gameSettings) +{ + // obtain content list from game settings (if present) + const QStringList files(gameSettings.getContentList()); + + // if any existing profile in launcher matches the content list, make that profile the default + foreach(const QString &listName, getContentLists()) + { + if (isEqual(files, getContentListFiles(listName))) + { + setCurrentContentListName(listName); + return; + } + } + + // otherwise, add content list + QString newContentListName(makeNewContentListName()); + setCurrentContentListName(newContentListName); + setContentList(newContentListName, files); +} + +void Config::LauncherSettings::removeContentList(const QString &contentListName) +{ + remove(makeContentListKey(contentListName)); +} + +void Config::LauncherSettings::setCurrentContentListName(const QString &contentListName) +{ + remove(QString(sCurrentContentListKey)); + setValue(QString(sCurrentContentListKey), contentListName); +} + +void Config::LauncherSettings::setContentList(const QString& contentListName, const QStringList& fileNames) +{ + removeContentList(contentListName); + QString key = makeContentListKey(contentListName); + foreach(const QString& fileName, fileNames) + { + setMultiValue(key, fileName); + } +} + +QString Config::LauncherSettings::getCurrentContentListName() const +{ + return value(QString(sCurrentContentListKey)); +} + +QStringList Config::LauncherSettings::getContentListFiles(const QString& contentListName) const +{ + // QMap returns multiple rows in LIFO order, so need to reverse + return reverse(getSettings().values(makeContentListKey(contentListName))); +} + +QStringList Config::LauncherSettings::reverse(const QStringList& toReverse) +{ + QStringList result; + result.reserve(toReverse.size()); + std::reverse_copy(toReverse.begin(), toReverse.end(), std::back_inserter(result)); + return result; +} + +bool Config::LauncherSettings::isEqual(const QStringList& list1, const QStringList& list2) +{ + if (list1.count() != list2.count()) + { + return false; + } + + for (int i = 0; i < list1.count(); ++i) + { + if (list1.at(i) != list2.at(i)) + { + return false; + } + } + + // if get here, lists are same + return true; +} + +QString Config::LauncherSettings::makeNewContentListName() +{ + // basically, use date and time as the name e.g. YYYY-MM-DDThh:mm:ss + time_t rawtime; + struct tm * timeinfo; + + time(&rawtime); + timeinfo = localtime(&rawtime); + int base = 10; + QChar zeroPad('0'); + return QString("%1-%2-%3T%4:%5:%6") + .arg(timeinfo->tm_year + 1900, 4).arg(timeinfo->tm_mon + 1, 2, base, zeroPad).arg(timeinfo->tm_mday, 2, base, zeroPad) + .arg(timeinfo->tm_hour, 2, base, zeroPad).arg(timeinfo->tm_min, 2, base, zeroPad).arg(timeinfo->tm_sec, 2, base, zeroPad); +} + + diff --git a/components/config/launchersettings.hpp b/components/config/launchersettings.hpp index 042823ca9..cbe21c54a 100644 --- a/components/config/launchersettings.hpp +++ b/components/config/launchersettings.hpp @@ -2,6 +2,7 @@ #define LAUNCHERSETTINGS_HPP #include "settingsbase.hpp" +#include "gamesettings.hpp" namespace Config { @@ -11,11 +12,49 @@ namespace Config LauncherSettings(); ~LauncherSettings(); + bool writeFile(QTextStream &stream); + + /// \return names of all Content Lists in the launcher's .cfg file. + QStringList getContentLists(); + + /// Set initally selected content list to match values from openmw.cfg, creating if necessary + void setContentList(const GameSettings& gameSettings); + + /// Create a Content List (or replace if it already exists) + void setContentList(const QString& contentListName, const QStringList& fileNames); + + void removeContentList(const QString &contentListName); + + void setCurrentContentListName(const QString &contentListName); + + QString getCurrentContentListName() const; + + QStringList getContentListFiles(const QString& contentListName) const; + + /// \return new list that is reversed order of input + static QStringList reverse(const QStringList& toReverse); + + static const char sLauncherConfigFileName[]; + + private: + + /// \return key to use to get/set the files in the specified Content List + static QString makeContentListKey(const QString& contentListName); + + /// \return true if both lists are same + static bool isEqual(const QStringList& list1, const QStringList& list2); + + static QString makeNewContentListName(); + QStringList subKeys(const QString &key); - QStringList values(const QString &key, Qt::MatchFlags flags = Qt::MatchExactly); - bool writeFile(QTextStream &stream); + /// name of entry in launcher.cfg that holds name of currently selected Content List + static const char sCurrentContentListKey[]; + + /// section of launcher.cfg holding the Content Lists + static const char sContentListsSectionPrefix[]; + static const char sContentListSuffix[]; }; } #endif // LAUNCHERSETTINGS_HPP diff --git a/components/config/settingsbase.hpp b/components/config/settingsbase.hpp index e6b0908e0..c798d2893 100644 --- a/components/config/settingsbase.hpp +++ b/components/config/settingsbase.hpp @@ -17,7 +17,7 @@ namespace Config SettingsBase() { mMultiValue = false; } ~SettingsBase() {} - inline QString value(const QString &key, const QString &defaultValue = QString()) + inline QString value(const QString &key, const QString &defaultValue = QString()) const { return mSettings.value(key).isEmpty() ? defaultValue : mSettings.value(key); } @@ -46,7 +46,7 @@ namespace Config mSettings.remove(key); } - Map getSettings() {return mSettings;} + Map getSettings() const {return mSettings;} bool readFile(QTextStream &stream) { From 37bea9d4dc16bbefc70f66128abff9d6b51d89c8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 15:06:30 +0100 Subject: [PATCH 152/740] Fix exception for empty dialog topics (Fixes #2267) --- apps/openmw/mwdialogue/keywordsearch.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwdialogue/keywordsearch.hpp b/apps/openmw/mwdialogue/keywordsearch.hpp index c44139f32..0bb3616d9 100644 --- a/apps/openmw/mwdialogue/keywordsearch.hpp +++ b/apps/openmw/mwdialogue/keywordsearch.hpp @@ -28,6 +28,8 @@ public: void seed (string_t keyword, value_t value) { + if (keyword.empty()) + return; seed_impl (/*std::move*/ (keyword), /*std::move*/ (value), 0, mRoot); } From 412496e28cc1d20f88cbe5eec65380cae44e1253 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 17 Dec 2014 23:19:37 +0100 Subject: [PATCH 153/740] Enable coverity scan for Travis CI --- .travis.yml | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 233117718..c5ed43543 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,22 @@ branches: only: - master - /openmw-.*$/ +env: + global: + # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created + # via the "travis encrypt" command using the project repo's public key + - secure: "CcQGmzgaBRTPWqPZLoLX4Zkt5pOQb5c6Pr5OFt15C8xQRhWOLrWcdsQEO1UuEJ70/YJgbvN+wQk8B5COBDLxM1roBNBu7zMpK//393Qx3rL2f9PdaZGLaCEtS5DyuXimyUXWzjMt8gsnsBxtomTgHBY4E7F5ag0Ub2z6ZsIQE1A=" + +addons: + coverity_scan: + project: + name: "scrawl/openmw" + description: "" + notification_email: scrawl@baseoftrash.de + build_command_prepend: "cmake ." + build_command: "make -j4" + branch_pattern: coverity_scan + before_install: - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./CI/before_install.linux.sh; fi - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then ./CI/before_install.osx.sh; fi @@ -14,7 +30,7 @@ before_script: - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then ./CI/before_script.osx.sh; fi script: - cd ./build - - make -j4 + - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then make -j4; fi after_script: - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi notifications: From 3378dece60ef086c2ef5de54302373274fc5d1af Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 17 Dec 2014 23:22:20 +0100 Subject: [PATCH 154/740] Add coverity_scan branch to .travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index c5ed43543..7acb92554 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ language: cpp branches: only: - master + - coverity_scan - /openmw-.*$/ env: global: From bf1739ae2cab2c0e3f30e51c74b70dcd4c7f29d7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 15:54:13 +0100 Subject: [PATCH 155/740] Adjust COVERITY_SCAN_TOKEN --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7acb92554..1200c6bbc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,8 +11,7 @@ env: global: # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created # via the "travis encrypt" command using the project repo's public key - - secure: "CcQGmzgaBRTPWqPZLoLX4Zkt5pOQb5c6Pr5OFt15C8xQRhWOLrWcdsQEO1UuEJ70/YJgbvN+wQk8B5COBDLxM1roBNBu7zMpK//393Qx3rL2f9PdaZGLaCEtS5DyuXimyUXWzjMt8gsnsBxtomTgHBY4E7F5ag0Ub2z6ZsIQE1A=" - + - secure: "jybGzAdUbqt9vWR/GEnRd96BgAi/7Zd1+2HK68j/i/8+/1YH2XxLOy4Jv/DUBhBlJIkxs/Xv8dRcUlFOclZDHX1d/9Qnsqd3oUVkD7k1y7cTOWy9TBQaE/v/kZo3LpzA3xPwwthrb0BvqIbOfIELi5fS5s8ba85WFRg3AX70wWE=" addons: coverity_scan: project: From 2d51d599ea04f04e949efd248a974cf40fc3e580 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 15:57:13 +0100 Subject: [PATCH 156/740] Adjust coverity config to official repo --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1200c6bbc..d24f5ebd8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,7 @@ env: addons: coverity_scan: project: - name: "scrawl/openmw" + name: "openmw/openmw" description: "" notification_email: scrawl@baseoftrash.de build_command_prepend: "cmake ." From c37c071dfe1cb088e778d3e8fb0a9ad518f4d085 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 16:07:12 +0100 Subject: [PATCH 157/740] Repository name fix --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d24f5ebd8..079e84a8e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,7 @@ env: addons: coverity_scan: project: - name: "openmw/openmw" + name: "OpenMW/openmw" description: "" notification_email: scrawl@baseoftrash.de build_command_prepend: "cmake ." From 23ffd33d9e6e1f12faf2b7d8e7e4bc3cde49efc8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 16:27:15 +0100 Subject: [PATCH 158/740] Convert readme to markdown --- readme.txt => README.md | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) rename readme.txt => README.md (99%) diff --git a/readme.txt b/README.md similarity index 99% rename from readme.txt rename to README.md index 5d344c0b5..304844892 100644 --- a/readme.txt +++ b/README.md @@ -1,18 +1,19 @@ OpenMW: A reimplementation of The Elder Scrolls III: Morrowind +============================================================== OpenMW is an attempt at recreating the engine for the popular role-playing game Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work. -Version: 0.34.0 -License: GPL (see GPL3.txt for more information) -Website: http://www.openmw.org +* Version: 0.34.0 +* License: GPL (see GPL3.txt for more information) +* Website: http://www.openmw.org Font Licenses: DejaVuLGCSansMono.ttf: custom (see DejaVu Font License.txt for more information) - -INSTALLATION +Installation +============ Windows: Run the installer. @@ -28,18 +29,21 @@ https://www.archlinux.org/packages/?sort=&q=openmw OS X: Open DMG file, copy OpenMW folder anywhere, for example in /Applications -BUILD FROM SOURCE +Build from source +================= https://wiki.openmw.org/index.php?title=Development_Environment_Setup -THE DATA PATH +The data path +============= The data path tells OpenMW where to find your Morrowind files. If you run the launcher, OpenMW should be able to pick up the location of these files on its own, if both Morrowind and OpenMW are installed properly (installing Morrowind under WINE is considered a proper install). -COMMAND LINE OPTIONS +Command line options +==================== Syntax: openmw Allowed options: @@ -96,7 +100,8 @@ Allowed options: --no-grab Don't grab mouse cursor --activate-dist arg (=-1) activation distance override -CHANGELOG +Changelog +========= 0.34.0 From 88a562a6481ace71a0569aa07c695437c4ed29fb Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 16:35:03 +0100 Subject: [PATCH 159/740] Move changelog to its own file, formatting fixes --- CHANGELOG.md | 1465 +++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 1474 +------------------------------------------------- 2 files changed, 1470 insertions(+), 1469 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..09f318d9d --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,1465 @@ +

+0.34.0
+
+Bug #904: omwlauncher doesn't allow installing Tribunal and Bloodmoon if only MW is installed
+Bug #986: Launcher: renaming profile names is broken
+Bug #1061: "Browse to CD..." launcher crash
+Bug #1135: Launcher crashes if user does not have write permission
+Bug #1231: Current installer in launcher does not correctly import russian Morrowind.ini settings from setup.inx
+Bug #1288: Fix the Alignment of the Resolution Combobox
+Bug #1343: BIK videos occasionally out of sync with audio
+Bug #1684: Morrowind Grass Mod graphical glitches
+Bug #1734: NPC in fight with invisible/sneaking player
+Bug #1982: Long class names are cut off in the UI
+Bug #2012: Editor: OpenCS script compiler sometimes fails to find IDs
+Bug #2015: Running while levitating does not affect speed but still drains fatigue
+Bug #2018: OpenMW don´t reset modified cells to vanilla when a plugin is deselected and don´t apply changes to cells already visited.
+Bug #2045: ToggleMenus command should close dialogue windows
+Bug #2046: Crash: light_de_streetlight_01_223
+Bug #2047: Buglamp tooltip minor correction
+Bug #2050: Roobrush floating texture bits
+Bug #2053: Slaves react negatively to PC picking up slave's bracers
+Bug #2055: Dremora corpses use the wrong model
+Bug #2056: Mansilamat Vabdas's corpse is floating in the water
+Bug #2057: "Quest: Larius Varro Tells A Little Story": Bounty not completely removed after finishing quest
+Bug #2059: Silenced enemies try to cast spells anyway
+Bug #2060: Editor: Special case implementation for top level window with single sub-window should be optional
+Bug #2061: Editor: SubView closing that is not directly triggered by the user isn't handled properly
+Bug #2063: Tribunal: Quest 'The Warlords' doesn't work
+Bug #2064: Sneak attack on hostiles causes bounty
+Bug #2065: Editor: Qt signal-slot error when closing a dialogue subview
+Bug #2070: Loading ESP in OpenMW works but fails in OpenCS
+Bug #2071: CTD in 0.33
+Bug #2073: Storm atronach animation stops now and then
+Bug #2075: Molag Amur Region, Map shows water on solid ground
+Bug #2080: game won't work with fair magicka regen
+Bug #2082: NPCs appear frozen or switched off after leaving and quickly reentering a cell
+Bug #2088: OpenMW is unable to play OGG files.
+Bug #2093: Darth Gares talks to you in Ilunibi even when he's not there, screwing up the Main Quests
+Bug #2095: Coordinate and rotation editing in the Reference table does not work.
+Bug #2096: Some overflow fun and bartering exploit
+Bug #2098: [D3D] Game crash on maximize
+Bug #2099: Activate, player seems not to work
+Bug #2104: Only labels are sensitive in buttons
+Bug #2107: "Slowfall" effect is too weak
+Bug #2114: OpenCS doesn't load an ESP file full of errors even though Vanilla MW Construction Set can
+Bug #2117: Crash when encountering bandits on opposite side of river from the egg mine south of Balmora
+Bug #2124: [Mod: Baldurians Transparent Glass Amor] Armor above head
+Bug #2125: Unnamed NiNodes in weapons problem in First Person
+Bug #2126: Dirty dialog script in tribunal.esm causing bug in Tribunal MQ
+Bug #2128: Crash when picking character's face
+Bug #2129: Disable the third-person zoom feature by default
+Bug #2130: Ash storm particles shown too long during transition to clear sky
+Bug #2137: Editor: exception caused by following the Creature column of a SoundGen record
+Bug #2139: Mouse movement should be ignored during intro video
+Bug #2143: Editor: Saving is broken
+Bug #2145: OpenMW - crash while exiting x64 debug build
+Bug #2152: You can attack Almalexia during her final monologue
+Bug #2154: Visual effects behave weirdly after loading/taking a screenshot
+Bug #2155: Vivec has too little magicka
+Bug #2156: Azura's spirit fades away too fast
+Bug #2158: [Mod]Julan Ashlander Companion 2.0: Negative magicka
+Bug #2161: Editor: combat/magic/stealth values of creature not displayed correctly
+Bug #2163: OpenMW can't detect death if the NPC die by the post damage effect of a magic weapon.
+Bug #2168: Westly's Master Head Pack X – Some hairs aren't rendered correctly.
+Bug #2170: Mods using conversations to update PC inconsistant
+Bug #2180: Editor: Verifier doesn't handle Windows-specific path issues when dealing with resources
+Bug #2212: Crash or unexpected behavior while closing OpenCS cell render window on OS X
+Feature #238: Add UI to run INI-importer from the launcher
+Feature #854: Editor: Add user setting to show status bar
+Feature #987: Launcher: first launch instructions for CD need to be more explicit
+Feature #1232: There is no way to set the "encoding" option using launcher UI.
+Feature #1281: Editor: Render cell markers
+Feature #1918: Editor: Functionality for Double-Clicking in Tables
+Feature #1966: Editor: User Settings dialogue grouping/labelling/tooltips
+Feature #2097: Editor: Edit position of references in 3D scene
+Feature #2121: Editor: Add edit mode button to scene toolbar
+Task #1965: Editor: Improve layout of user settings dialogue
+
+0.33.1
+
+Bug #2108: OpenCS fails to build
+
+0.33.0
+
+Bug #371: If console assigned to ` (probably to any symbolic key), "`" symbol will be added to console every time it closed
+Bug #1148: Some books'/scrolls' contents are displayed incorrectly
+Bug #1290: Editor: status bar is not updated when record filter is changed
+Bug #1292: Editor: Documents are not removed on closing the last view
+Bug #1301: Editor: File->Exit only checks the document it was issued from.
+Bug #1353: Bluetooth on with no speaker connected results in significantly longer initial load times
+Bug #1436: NPCs react from too far distance
+Bug #1472: PC is placed on top of following NPC when changing cell
+Bug #1487: Tall PC can get stuck in staircases
+Bug #1565: Editor: Subviews are deleted on shutdown instead when they are closed
+Bug #1623: Door marker on Ghorak Manor's balcony makes PC stuck
+Bug #1633: Loaddoor to Sadrith Mora, Telvanni Council House spawns PC in the air
+Bug #1655: Use Appropriate Application Icons on Windows
+Bug #1679: Tribunal expansion, Meryn Othralas the backstage manager in the theatre group in Mournhold in the great bazaar district is floating a good feet above the ground.
+Bug #1705: Rain is broken in third person
+Bug #1706: Thunder and lighting still occurs while the game is paused during the rain
+Bug #1708: No long jumping
+Bug #1710: Editor: ReferenceableID drag to references record filter field creates incorrect filter
+Bug #1712: Rest on Water
+Bug #1715: "Cancel" button is not always on the same side of menu
+Bug #1725: Editor: content file can be opened multiple times from the same dialogue
+Bug #1730: [MOD: Less Generic Nerevarine] Compile failure attempting to enter the Corprusarium.
+Bug #1733: Unhandled ffmpeg sample formats
+Bug #1735: Editor: "Edit Record" context menu button not opening subview for journal infos
+Bug #1750: Editor: record edits result in duplicate entries
+Bug #1789: Editor: Some characters cannot be used in addon name
+Bug #1803: Resizing the map does not keep the pre-resize center at the post-resize center
+Bug #1821: Recovering Cloudcleaver quest: attacking Sosia is considered a crime when you side with Hlormar
+Bug #1838: Editor: Preferences window appears off screen
+Bug #1839: Editor: Record filter title should be moved two pixels to the right
+Bug #1849: Subrecord error in MAO_Containers
+Bug #1854: Knocked-out actors don't fully act knocked out
+Bug #1855: "Soul trapped" sound doesn't play
+Bug #1857: Missing sound effect for enchanted items with empty charge
+Bug #1859: Missing console command: ResetActors (RA)
+Bug #1861: Vendor category "MagicItems" is unhandled
+Bug #1862: Launcher doesn't start if a file listed in launcher.cfg has correct name but wrong capitalization
+Bug #1864: Editor: Region field for cell record in dialogue subview not working
+Bug #1869: Editor: Change label "Musics" to "Music"
+Bug #1870: Goblins killed while knocked down remain in knockdown-pose
+Bug #1874: CellChanged events should not trigger when crossing exterior cell border
+Bug #1877: Spriggans killed instantly if hit while regening
+Bug #1878: Magic Menu text not un-highlighting correctly when going from spell to item as active magic
+Bug #1881: Stuck in ceiling when entering castle karstaags tower
+Bug #1884: Unlit torches still produce a burning sound
+Bug #1885: Can type text in price field in barter window
+Bug #1887: Equipped items do not emit sounds
+Bug #1889: draugr lord aesliip will attack you and remain non-hostile
+Bug #1892: Guard asks player to pay bounty of 0 gold
+Bug #1895: getdistance should only return max float if ref and target are in different worldspaces
+Bug #1896: Crash Report
+Bug #1897: Conjured Equipment cant be re-equipped if removed
+Bug #1898: Only Gidar Verothan follows you during establish the mine quest
+Bug #1900: Black screen when you open the door and breath underwater
+Bug #1904: Crash on casting recall spell
+Bug #1906: Bound item checks should use the GMSTs
+Bug #1907: Bugged door. Mournhold, The Winged Guar
+Bug #1908: Crime reported for attacking Drathas Nerus's henchmen while they attack Dilborn
+Bug #1909: Weird Quest Flow Infidelities quest
+Bug #1910: Follower fighting with gone npc
+Bug #1911: Npcs will drown themselves
+Bug #1912: World map arrow stays static when inside a building
+Bug #1920: Ulyne Henim disappears when game is loaded inside Vas
+Bug #1922: alchemy-> potion of paralyze
+Bug #1923: "levitation magic cannot be used here" shows outside of tribunal
+Bug #1927: AI prefer melee over magic.
+Bug #1929: Tamriel Rebuilt: Named cells that lie within the overlap with Morrowind.esm are not shown
+Bug #1932: BTB - Spells 14.1 magic effects don´t overwrite the Vanilla ones but are added
+Bug #1935: Stacks of items are worth more when sold individually
+Bug #1940: Launcher does not list addon files if base game file is renamed to a different case
+Bug #1946: Mod "Tel Nechim - moved" breaks savegames
+Bug #1947: Buying/Selling price doesn't properly affect the growth of mercantile skill
+Bug #1950: followers from east empire company quest will fight each other if combat happens with anything
+Bug #1958: Journal can be scrolled indefinitely with a mouse wheel
+Bug #1959: Follower not leaving party on quest end
+Bug #1960: Key bindings not always saved correctly
+Bug #1961: Spell merchants selling racial bonus spells
+Bug #1967: segmentation fault on load saves
+Bug #1968: Jump sounds are not controlled by footsteps slider, sound weird compared to footsteps
+Bug #1970: PC suffers silently when taking damage from lava
+Bug #1971: Dwarven Sceptre collision area is not removed after killing one
+Bug #1974: Dalin/Daris Norvayne follows player indefinitely
+Bug #1975: East Empire Company faction rank breaks during Raven Rock questline
+Bug #1979: 0 strength = permanently over encumbered
+Bug #1993: Shrine blessing in Maar Gan doesn't work
+Bug #2008: Enchanted items do not recharge
+Bug #2011: Editor: OpenCS script compiler doesn't handle member variable access properly
+Bug #2016: Dagoth Ur already dead in Facility Cavern
+Bug #2017: Fighters Guild Quest: The Code Book - dialogue loop when UMP is loaded.
+Bug #2019: Animation of 'Correct UV Mudcrabs' broken
+Bug #2022: Alchemy window - Removing ingredient doesn't remove the number of ingredients
+Bug #2025: Missing mouse-over text for non affordable items
+Bug #2028: [MOD: Tamriel Rebuilt] Crashing when trying to enter interior cell "Ruinous Keep, Great Hall"
+Bug #2029: Ienith Brothers Thiev's Guild quest journal entry not adding
+Feature #471: Editor: Special case implementation for top-level window with single sub-window
+Feature #472: Editor: Sub-Window re-use settings
+Feature #704: Font colors import from fallback settings
+Feature #879: Editor: Open sub-views in a new top-level window
+Feature #932: Editor: magic effect table
+Feature #937: Editor: Path Grid table
+Feature #938: Editor: Sound Gen table
+Feature #1117: Death and LevelUp music
+Feature #1226: Editor: Request UniversalId editing from table columns
+Feature #1545: Targeting console on player
+Feature #1597: Editor: Render terrain
+Feature #1695: Editor: add column for CellRef's global variable
+Feature #1696: Editor: use ESM::Cell's RefNum counter
+Feature #1697: Redden player's vision when hit
+Feature #1856: Spellcasting for non-biped creatures
+Feature #1879: Editor: Run OpenMW with the currently edited content list
+Task #1851: Move AI temporary state out of AI packages
+Task #1865: Replace char type in records
+
+0.32.0
+
+Bug #1132: Unable to jump when facing a wall
+Bug #1341: Summoned Creatures do not immediately disappear when killed.
+Bug #1430: CharGen Revamped script does not compile
+Bug #1451: NPCs shouldn't equip weapons prior to fighting
+Bug #1461: Stopped start scripts do not restart on load
+Bug #1473: Dead NPC standing and in 2 pieces
+Bug #1482: Abilities are depleted when interrupted during casting
+Bug #1503: Behaviour of NPCs facing the player
+Bug #1506: Missing character, French edition: three-points
+Bug #1528: Inventory very slow after 2 hours
+Bug #1540: Extra arguments should be ignored for script functions
+Bug #1541: Helseth's Champion: Tribunal
+Bug #1570: Journal cannot be opened while in inventory screen
+Bug #1573: PC joins factions at random
+Bug #1576: NPCs aren't switching their weapons when out of ammo
+Bug #1579: Guards detect creatures in far distance, instead on sight
+Bug #1588: The Siege of the Skaal Village: bloodmoon
+Bug #1593: The script compiler isn't recognising some names that contain a -
+Bug #1606: Books: Question marks instead of quotation marks
+Bug #1608: Dead bodies prevent door from opening/closing.
+Bug #1609: Imperial guards in Sadrith Mora are not using their spears
+Bug #1610: The bounty number is not displayed properly with high numbers
+Bug #1620: Implement correct formula for auto-calculated NPC spells
+Bug #1630: Boats standing vertically in Vivec
+Bug #1635: Arrest dialogue is executed second time after I select "Go to jail"
+Bug #1637: Weird NPC behaviour in Vivec, Hlaalu Ancestral Vaults?
+Bug #1641: Persuasion dialog remains after loading, possibly resulting in crash
+Bug #1644: "Goodbye" and similar options on dialogues prevents escape working properly.
+Bug #1646: PC skill stats are not updated immediately when changing equipment
+Bug #1652: Non-aggressive creature
+Bug #1653: Quickloading while the container window is open crashes the game
+Bug #1654: Priority of checks in organic containers
+Bug #1656: Inventory items merge issue when repairing
+Bug #1657: Attacked state of NPCs is not saved properly
+Bug #1660: Rank dialogue condition ignored
+Bug #1668: Game starts on day 2 instead of day 1
+Bug #1669: Critical Strikes while fighting a target who is currently fighting me
+Bug #1672: OpenCS doesn't save the projects
+Bug #1673: Fatigue decreasing by only one point when running
+Bug #1675: Minimap and localmap graphic glitches
+Bug #1676: Pressing the OK button on the travel menu cancels the travel and exits the menu
+Bug #1677: Sleeping in a rented bed is considered a crime
+Bug #1685: NPCs turn towards player even if invisible/sneaking
+Bug #1686: UI bug: cursor is clicking "world/local" map button while inventory window is closed?
+Bug #1690: Double clicking on a inventory window header doesn't close it.
+Bug #1693: Spell Absorption does not absorb shrine blessings
+Bug #1694: journal displays learned topics as quests
+Bug #1700: Sideways scroll of text boxes
+Bug #1701: Player enchanting requires player hold money, always 100% sucessful.
+Bug #1704: self-made Fortify Intelligence/Drain willpower potions are broken
+Bug #1707: Pausing the game through the esc menu will silence rain, pausing it by opening the inventory will not.
+Bug #1709: Remesa Othril is hostile to Hlaalu members
+Bug #1713: Crash on load after death
+Bug #1719: Blind effect has slight border at the edge of the screen where it is ineffective.
+Bug #1722: Crash after creating enchanted item, reloading saved game
+Bug #1723: Content refs that are stacked share the same index after unstacking
+Bug #1726: Can't finish Aengoth the Jeweler's quest : Retrieve the Scrap Metal
+Bug #1727: Targets almost always resist soultrap scrolls
+Bug #1728: Casting a soultrap spell on invalid target yields no message
+Bug #1729: Chop attack doesn't work if walking diagonally
+Bug #1732: Error handling for missing script function arguments produces weird message
+Bug #1736: Alt-tabbing removes detail from overworld map.
+Bug #1737: Going through doors with (high magnitude?) leviation will put the player high up, possibly even out of bounds.
+Bug #1739: Setting a variable on an NPC from another NPC's dialogue result sets the wrong variable
+Bug #1741: The wait dialogue doesn't black the screen out properly during waiting.
+Bug #1742: ERROR: Object 'sDifficulty' not found (const)
+Bug #1744: Night sky in Skies V.IV (& possibly v3) by SWG rendered incorrectly
+Bug #1746: Bow/marksman weapon condition does not degrade with use
+Bug #1749: Constant Battle Music
+Bug #1752: Alt-Tabbing in the character menus makes the paper doll disappear temporarily
+Bug #1753: Cost of training is not added to merchant's inventory
+Bug #1755: Disposition changes do not persist if the conversation menu is closed by purchasing training.
+Bug #1756: Caught Blight after being cured of Corprus
+Bug #1758: Crash Upon Loading New Cell
+Bug #1760: Player's Magicka is not recalculated upon drained or boosted intelligence
+Bug #1761: Equiped torches lost on reload
+Bug #1762: Your spell did not get a target. Soul trap. Gorenea Andrano
+Bug #1763: Custom Spell Magicka Cost
+Bug #1765: Azuras Star breaks on recharging item
+Bug #1767: GetPCRank did not handle ignored explicit references
+Bug #1772: Dark Brotherhood Assassins never use their Carved Ebony Dart, sticking to their melee weapon.
+Bug #1774: String table overflow also occurs when loading TheGloryRoad.esm
+Bug #1776: dagoth uthol runs in slow motion
+Bug #1778: Incorrect values in spellmaking window
+Bug #1779: Icon of Master Propylon Index is not visible
+Bug #1783: Invisible NPC after looting corpse
+Bug #1787: Health Calculation
+Bug #1788: Skeletons, ghosts etc block doors when we try to open
+Bug #1791: [MOD: LGNPC Foreign Quarter] NPC in completely the wrong place.
+Bug #1792: Potions should show more effects
+Bug #1793: Encumbrance while bartering
+Bug #1794: Fortify attribute not affecting fatigue
+Bug #1795: Too much magicka
+Bug #1796: "Off by default" torch burning
+Bug #1797: Fish too slow
+Bug #1798: Rest until healed shouldn't show with full health and magicka
+Bug #1802: Mark location moved
+Bug #1804: stutter with recent builds
+Bug #1810: attack gothens dremora doesnt agro the others.
+Bug #1811: Regression: Crash Upon Loading New Cell
+Bug #1812: Mod: "QuickChar" weird button placement
+Bug #1815: Keys show value and weight, Vanilla Morrowind's keys dont.
+Bug #1817: Persuasion results do not show using unpatched MW ESM
+Bug #1818: Quest B3_ZainabBride moves to stage 47 upon loading save while Falura Llervu is following
+Bug #1823: AI response to theft incorrect - only guards react, in vanilla everyone does.
+Bug #1829: On-Target Spells Rendered Behind Water Surface Effects
+Bug #1830: Galsa Gindu's house is on fire
+Bug #1832: Fatal Error: OGRE Exception(2:InvalidParametersException)
+Bug #1836: Attacked Guards open "fine/jail/resist"-dialogue after killing you
+Bug #1840: Infinite recursion in ActionTeleport
+Bug #1843: Escorted people change into player's cell after completion of escort stage
+Bug #1845: Typing 'j' into 'Name' fields opens the journal
+Bug #1846: Text pasted into the console still appears twice (Windows)
+Bug #1847: "setfatigue 0" doesn't render NPC unconscious
+Bug #1848: I can talk to unconscious actors
+Bug #1866: Crash when player gets killed by a creature summoned by him
+Bug #1868: Memory leaking when openmw window is minimized
+Feature #47: Magic Effects
+Feature #642: Control NPC mouth movement using current Say sound
+Feature #939: Editor: Resources tables
+Feature #961: AI Combat for magic (spells, potions and enchanted items)
+Feature #1111: Collision script instructions (used e.g. by Lava)
+Feature #1120: Command creature/humanoid magic effects
+Feature #1121: Elemental shield magic effects
+Feature #1122: Light magic effect
+Feature #1139: AI: Friendly hits
+Feature #1141: AI: combat party
+Feature #1326: Editor: Add tooltips to all graphical buttons
+Feature #1489: Magic effect Get/Mod/Set functions
+Feature #1505: Difficulty slider
+Feature #1538: Targeted scripts
+Feature #1571: Allow creating custom markers on the local map
+Feature #1615: Determine local variables from compiled scripts instead of the values in the script record
+Feature #1616: Editor: Body part record verifier
+Feature #1651: Editor: Improved keyboard navigation for scene toolbar
+Feature #1666: Script blacklisting
+Feature #1711: Including the Git revision number from the command line "--version" switch.
+Feature #1721: NPC eye blinking
+Feature #1740: Scene toolbar buttons for selecting which type of elements are rendered
+Feature #1790: Mouse wheel scrolling for the journal
+Feature #1850: NiBSPArrayController
+Task #768: On windows, settings folder should be "OpenMW", not "openmw"
+Task #908: Share keyframe data
+Task #1716: Remove defunct option for building without FFmpeg
+
+0.31.0
+
+Bug #245: Cloud direction and weather systems differ from Morrowind
+Bug #275: Local Map does not always show objects that span multiple cells
+Bug #538: Update CenterOnCell (COC) function behavior
+Bug #618: Local and World Map Textures are sometimes Black
+Bug #640: Water behaviour at night
+Bug #668: OpenMW doesn't support non-latin paths on Windows
+Bug #746: OpenMW doesn't check if the background music was already played
+Bug #747: Door is stuck if cell is left before animation finishes
+Bug #772: Disabled statics are visible on map
+Bug #829: OpenMW uses up all available vram, when playing for extended time
+Bug #869: Dead bodies don't collide with anything
+Bug #894: Various character creation issues
+Bug #897/#1369: opencs Segmentation Fault after "new" or "load"
+Bug #899: Various jumping issues
+Bug #952: Reflection effects are one frame delayed
+Bug #993: Able to interact with world during Wait/Rest dialog
+Bug #995: Dropped items can be placed inside the wall
+Bug #1008: Corpses always face up upon reentering the cell
+Bug #1035: Random colour patterns appearing in automap
+Bug #1037: Footstep volume issues
+Bug #1047: Creation of wrong links in dialogue window
+Bug #1129: Summoned creature time life duration seems infinite
+Bug #1134: Crimes can be committed against hostile NPCs
+Bug #1136: Creature run speed formula is incorrect
+Bug #1150: Weakness to Fire doesn't apply to Fire Damage in the same spell
+Bug #1155: NPCs killing each other
+Bug #1166: Bittercup script still does not work
+Bug #1178: .bsa file names are case sensitive.
+Bug #1179: Crash after trying to load game after being killed
+Bug #1180: Changing footstep sound location
+Bug #1196: Jumping not disabled when showing messageboxes
+Bug #1202: "strange" keys are not shown in binding menu, and are not saved either, but works
+Bug #1216: Broken dialog topics in russian Morrowind
+Bug #1217: Container content changes based on the current position of the mouse
+Bug #1234: Loading/saving issues with dynamic records
+Bug #1277: Text pasted into the console appears twice
+Bug #1284: Crash on New Game
+Bug #1303: It's possible to skip the chargen
+Bug #1304: Slaughterfish should not detect the player unless the player is in the water
+Bug #1311: Editor: deleting Record Filter line does not reset the filter
+Bug #1324: ERROR: ESM Error: String table overflow when loading Animated Morrowind.esp
+Bug #1328: Editor: Bogus Filter created when dragging multiple records to filter bar of non-applicable table
+Bug #1331: Walking/running sound persist after killing NPC`s that are walking/running.
+Bug #1334: Previously equipped items not shown as unequipped after attempting to sell them.
+Bug #1335: Actors ignore vertical axis when deciding to attack
+Bug #1338: Unknown toggle option for shadows
+Bug #1339: "Ashlands Region" is visible when beginning new game during "Loading Area" process
+Bug #1340: Guards prompt Player with punishment options after resisting arrest with another guard.
+Bug #1348: Regression: Bug #1098 has returned with a vengeance
+Bug #1349: [TR] TR_Data mesh tr_ex_imp_gatejamb01 cannot be activated
+Bug #1352: Disabling an ESX file does not disable dependent ESX files
+Bug #1355: CppCat Checks OpenMW
+Bug #1356: Incorrect voice type filtering for sleep interrupts
+Bug #1357: Restarting the game clears saves
+Bug #1360: Seyda Neen silk rider dialog problem
+Bug #1361: Some lights don't work
+Bug #1364: It is difficult to bind "Mouse 1" to an action in the options menu
+Bug #1370: Animation compilation mod does not work properly
+Bug #1371: SL_Pick01.nif from third party fails to load in openmw, but works in Vanilla
+Bug #1373: When stealing in front of Sellus Gravius cannot exit the dialog
+Bug #1378: Installs to /usr/local are not working
+Bug #1380: Loading a save file fail if one of the content files is disabled
+Bug #1382: "getHExact() size mismatch" crash on loading official plugin "Siege at Firemoth.esp"
+Bug #1386: Arkngthand door will not open
+Bug #1388: Segfault when modifying View Distance in Menu options
+Bug #1389: Crash when loading a save after dying
+Bug #1390: Apostrophe characters not displayed [French version]
+Bug #1391: Custom made icon background texture for magical weapons and stuff isn't scaled properly on GUI.
+Bug #1393: Coin icon during the level up dialogue are off of the background
+Bug #1394: Alt+F4 doesn't work on Win version
+Bug #1395: Changing rings switches only the last one put on
+Bug #1396: Pauldron parts aren't showing when the robe is equipped
+Bug #1402: Dialogue of some shrines have wrong button orientation
+Bug #1403: Items are floating in the air when they're dropped onto dead bodies.
+Bug #1404: Forearms are not rendered on Argonian females
+Bug #1407: Alchemy allows making potions from two of the same item
+Bug #1408: "Max sale" button gives you all the items AND all the trader's gold
+Bug #1409: Rest "Until Healed" broken for characters with stunted magicka.
+Bug #1412: Empty travel window opens while playing through start game
+Bug #1413: Save game ignores missing writing permission
+Bug #1414: The Underground 2 ESM Error
+Bug #1416: Not all splash screens in the Splash directory are used
+Bug #1417: Loading saved game does not terminate
+Bug #1419: Skyrim: Home of the Nords error
+Bug #1422: ClearInfoActor
+Bug #1423: ForceGreeting closes existing dialogue windows
+Bug #1425: Cannot load save game
+Bug #1426: Read skill books aren't stored in savegame
+Bug #1427: Useless items can be set under hotkeys
+Bug #1429: Text variables in journal
+Bug #1432: When attacking friendly NPC, the crime is reported and bounty is raised after each swing
+Bug #1435: Stealing priceless items is without punishment
+Bug #1437: Door marker at Jobasha's Rare Books is spawning PC in the air
+Bug #1440: Topic selection menu should be wider
+Bug #1441: Dropping items on the rug makes them inaccessible
+Bug #1442: When dropping and taking some looted items, bystanders consider that as a crime
+Bug #1444: Arrows and bolts are not dropped where the cursor points
+Bug #1445: Security trainers offering acrobatics instead
+Bug #1447: Character dash not displayed, French edition
+Bug #1448: When the player is killed by the guard while having a bounty on his head, the guard dialogue opens over and over instead of loading dialogue
+Bug #1454: Script error in SkipTutorial
+Bug #1456: Bad lighting when using certain Morrowind.ini generated by MGE
+Bug #1457: Heart of Lorkan comes after you when attacking it
+Bug #1458: Modified Keybindings are not remembered
+Bug #1459: Dura Gra-Bol doesn't respond to PC attack
+Bug #1462: Interior cells not loaded with Morrowind Patch active
+Bug #1469: Item tooltip should show the base value, not real value
+Bug #1477: Death count is not stored in savegame
+Bug #1478: AiActivate does not trigger activate scripts
+Bug #1481: Weapon not rendered when partially submerged in water
+Bug #1483: Enemies are attacking even while dying
+Bug #1486: ESM Error: Don't know what to do with INFO
+Bug #1490: Arrows shot at PC can end up in inventory
+Bug #1492: Monsters respawn on top of one another
+Bug #1493: Dialogue box opens with follower NPC even if NPC is dead
+Bug #1494: Paralysed cliffracers remain airbourne
+Bug #1495: Dialogue box opens with follower NPC even the game is paused
+Bug #1496: GUI messages are not cleared when loading another saved game
+Bug #1499: Underwater sound sometimes plays when transitioning from interior.
+Bug #1500: Targetted spells and water.
+Bug #1502: Console error message on info refusal
+Bug #1507: Bloodmoon MQ The Ritual of Beasts: Can't remove the arrow
+Bug #1508: Bloodmoon: Fort Frostmoth, cant talk with Carnius Magius
+Bug #1516: PositionCell doesn't move actors to current cell
+Bug #1518: ForceGreeting broken for explicit references
+Bug #1522: Crash after attempting to play non-music file
+Bug #1523: World map empty after loading interior save
+Bug #1524: Arrows in waiting/resting dialog act like minimum and maximum buttons
+Bug #1525: Werewolf: Killed NPC's don't fill werewolfs hunger for blood
+Bug #1527: Werewolf: Detect life detects wrong type of actor
+Bug #1529: OpenMW crash during "the shrine of the dead" mission (tribunal)
+Bug #1530: Selected text in the console has the same color as the background
+Bug #1539: Barilzar's Mazed Band: Tribunal
+Bug #1542: Looping taunts from NPC`s after death: Tribunal
+Bug #1543: OpenCS crash when using drag&drop in script editor
+Bug #1547: Bamz-Amschend: Centurion Archers combat problem
+Bug #1548: The Missing Hand: Tribunal
+Bug #1549: The Mad God: Tribunal, Dome of Serlyn
+Bug #1557: A bounty is calculated from actual item cost
+Bug #1562: Invisible terrain on top of Red Mountain
+Bug #1564: Cave of the hidden music: Bloodmoon
+Bug #1567: Editor: Deleting of referenceables does not work
+Bug #1568: Picking up a stack of items and holding the enter key and moving your mouse around paints a bunch of garbage on screen.
+Bug #1574: Solstheim: Drauger cant inflict damage on player
+Bug #1578: Solstheim: Bonewolf running animation not working
+Bug #1585: Particle effects on PC are stopped when paralyzed
+Bug #1589: Tribunal: Crimson Plague quest does not update when Gedna Relvel is killed
+Bug #1590: Failed to save game: compile error
+Bug #1598: Segfault when making Drain/Fortify Skill spells
+Bug #1599: Unable to switch to fullscreen
+Bug #1613: Morrowind Rebirth duplicate objects / vanilla objects not removed
+Bug #1618: Death notice fails to show up
+Bug #1628: Alt+Tab Segfault
+Feature #32: Periodic Cleanup/Refill
+Feature #41: Precipitation and weather particles
+Feature #568: Editor: Configuration setup
+Feature #649: Editor: Threaded loading
+Feature #930: Editor: Cell record saving
+Feature #934: Editor: Body part table
+Feature #935: Editor: Enchantment effect table
+Feature #1162: Dialogue merging
+Feature #1174: Saved Game: add missing creature state
+Feature #1177: Saved Game: fog of war state
+Feature #1312: Editor: Combat/Magic/Stealth values for creatures are not displayed
+Feature #1314: Make NPCs and creatures fight each other
+Feature #1315: Crime: Murder
+Feature #1321: Sneak skill enhancements
+Feature #1323: Handle restocking items
+Feature #1332: Saved Game: levelled creatures
+Feature #1347: modFactionReaction script instruction
+Feature #1362: Animated main menu support
+Feature #1433: Store walk/run toggle
+Feature #1449: Use names instead of numbers for saved game files and folders
+Feature #1453: Adding Delete button to the load menu
+Feature #1460: Enable Journal screen while in dialogue
+Feature #1480: Play Battle music when in combat
+Feature #1501: Followers unable to fast travel with you
+Feature #1520: Disposition and distance-based aggression/ShouldAttack
+Feature #1595: Editor: Object rendering in cells
+Task #940: Move license to locations where applicable
+Task #1333: Remove cmake git tag reading
+Task #1566: Editor: Object rendering refactoring
+
+0.30.0
+
+Bug #416: Extreme shaking can occur during cell transitions while moving
+Bug #1003: Province Cyrodiil: Ogre Exception in Stirk
+Bug #1071: Crash when given a non-existent content file
+Bug #1080: OpenMW allows resting/using a bed while in combat
+Bug #1097: Wrong punishment for stealing in Census and Excise Office at the start of a new game
+Bug #1098: Unlocked evidence chests should get locked after new evidence is put into them
+Bug #1099: NPCs that you attacked still fight you after you went to jail/paid your fine
+Bug #1100: Taking items from a corpse is considered stealing
+Bug #1126: Some creatures can't get close enough to attack
+Bug #1144: Killed creatures seem to die again each time player transitions indoors/outdoors
+Bug #1181: loading a saved game does not reset the player control status
+Bug #1185: Collision issues in Addamasartus
+Bug #1187: Athyn Sarethi mission, rescuing varvur sarethi from the doesnt end the mission
+Bug #1189: Crash when entering interior cell "Gnisis, Arvs-Drelen"
+Bug #1191: Picking up papers without inventory in new game
+Bug #1195: NPCs do not equip torches in certain interiors
+Bug #1197: mouse wheel makes things scroll too fast
+Bug #1200: door blocked by monsters
+Bug #1201: item's magical charges are only refreshed when they are used
+Bug #1203: Scribs do not defend themselves
+Bug #1204: creatures life is not empty when they are dead
+Bug #1205: armor experience does not progress when hits are taken
+Bug #1206: blood particules always red. Undeads and mechanicals should have a different one.
+Bug #1209: Tarhiel never falls
+Bug #1210: journal adding script is ran again after having saved/loaded
+Bug #1224: Names of custom classes are not properly handled in save games
+Bug #1227: Editor: Fixed case handling for broken localised versions of Morrowind.esm
+Bug #1235: Indoors walk stutter
+Bug #1236: Aborting intro movie brings up the menu
+Bug #1239: NPCs get stuck when walking past each other
+Bug #1240: BTB - Settings 14.1 and Health Bar.
+Bug #1241: BTB - Character and Khajiit Prejudice
+Bug #1248: GUI Weapon icon is changed to hand-to-hand after save load
+Bug #1254: Guild ranks do not show in dialogue
+Bug #1255: When opening a container and selecting "Take All", the screen flashes blue
+Bug #1260: Level Up menu doesn't show image when using a custom class
+Bug #1265: Quit Menu Has Misaligned Buttons
+Bug #1270: Active weapon icon is not updated when weapon is repaired
+Bug #1271: NPC Stuck in hovering "Jumping" animation
+Bug #1272: Crash when attempting to load Big City esm file.
+Bug #1276: Editor: Dropping a region into the filter of a cell subview fails
+Bug #1286: Dialogue topic list clips with window frame
+Bug #1291: Saved game: store faction membership
+Bug #1293: Pluginless Khajiit Head Pack by ashiraniir makes OpenMW close.
+Bug #1294: Pasting in console adds text to end, not at cursor
+Bug #1295: Conversation loop when asking about "specific place" in Vivec
+Bug #1296: Caius doesn't leave at start of quest "Mehra Milo and the Lost Prophecies"
+Bug #1297: Saved game: map markers
+Bug #1302: ring_keley script causes vector::_M_range_check exception
+Bug #1309: Bug on "You violated the law" dialog
+Bug #1319: Creatures sometimes rendered incorrectly
+Feature #50: Ranged Combat
+Feature #58: Sneaking Skill
+Feature #73: Crime and Punishment
+Feature #135: Editor: OGRE integration
+Feature #541: Editor: Dialogue Sub-Views
+Feature #853: Editor: Rework User Settings
+Feature #944: Editor: lighting modes
+Feature #945: Editor: Camera navigation mode
+Feature #953: Trader gold
+Feature #1140: AI: summoned creatures
+Feature #1142: AI follow: Run stance
+Feature #1154: Not all NPCs get aggressive when one is attacked
+Feature #1169: Terrain threading
+Feature #1172: Loading screen and progress bars during saved/loading game
+Feature #1173: Saved Game: include weather state
+Feature #1207: Class creation form does not remember
+Feature #1220: Editor: Preview Subview
+Feature #1223: Saved Game: Local Variables
+Feature #1229: Quicksave, quickload, autosave
+Feature #1230: Deleting saves
+Feature #1233: Bribe gold is placed into NPCs inventory
+Feature #1252: Saved Game: quick key bindings
+Feature #1273: Editor: Region Map context menu
+Feature #1274: Editor: Region Map drag & drop
+Feature #1275: Editor: Scene subview drop
+Feature #1282: Non-faction member crime recognition.
+Feature #1289: NPCs return to default position
+Task #941: Remove unused cmake files
+
+0.29.0
+
+Bug #556: Video soundtrack not played when music volume is set to zero
+Bug #829: OpenMW uses up all available vram, when playing for extended time
+Bug #848: Wrong amount of footsteps playing in 1st person
+Bug #888: Ascended Sleepers have movement issues
+Bug #892: Explicit references are allowed on all script functions
+Bug #999: Graphic Herbalism (mod): sometimes doesn't activate properly
+Bug #1009: Lake Fjalding AI related slowdown.
+Bug #1041: Music playback issues on OS X >= 10.9
+Bug #1043: No message box when advancing skill "Speechcraft" while in dialog window
+Bug #1060: Some message boxes are cut off at the bottom
+Bug #1062: Bittercup script does not work ('end' variable)
+Bug #1074: Inventory paperdoll obscures armour rating
+Bug #1077: Message after killing an essential NPC disappears too fast
+Bug #1078: "Clutterbane" shows empty charge bar
+Bug #1083: UndoWerewolf fails
+Bug #1088: Better Clothes Bloodmoon Plus 1.5 by Spirited Treasure pants are not rendered
+Bug #1090: Start scripts fail when going to a non-predefined cell
+Bug #1091: Crash: Assertion `!q.isNaN() && "Invalid orientation supplied as parameter"' failed.
+Bug #1093: Weapons of aggressive NPCs are invisible after you exit and re-enter interior
+Bug #1105: Magicka is depleted when using uncastable spells
+Bug #1106: Creatures should be able to run
+Bug #1107: TR cliffs have way too huge collision boxes in OpenMW
+Bug #1109: Cleaning True Light and Darkness with Tes3cmd makes Addamasartus , Zenarbael and Yasamsi flooded.
+Bug #1114: Bad output for desktop-file-validate on openmw.desktop (and opencs.desktop)
+Bug #1115: Memory leak when spying on Fargoth
+Bug #1137: Script execution fails (drenSlaveOwners script)
+Bug #1143: Mehra Milo quest (vivec informants) is broken
+Bug #1145: Issues with moving gold between inventory and containers
+Bug #1146: Issues with picking up stacks of gold
+Bug #1147: Dwemer Crossbows are held incorrectly
+Bug #1158: Armor rating should always stay below inventory mannequin
+Bug #1159: Quick keys can be set during character generation
+Bug #1160: Crash on equip lockpick when
+Bug #1167: Editor: Referenceables are not correctly loaded when dealing with more than one content file
+Bug #1184: Game Save: overwriting an existing save does not actually overwrites the file
+Feature #30: Loading/Saving (still missing a few parts)
+Feature #101: AI Package: Activate
+Feature #103: AI Package: Follow, FollowCell
+Feature #138: Editor: Drag & Drop
+Feature #428: Player death
+Feature #505: Editor: Record Cloning
+Feature #701: Levelled creatures
+Feature #708: Improved Local Variable handling
+Feature #709: Editor: Script verifier
+Feature #764: Missing journal backend features
+Feature #777: Creature weapons/shields
+Feature #789: Editor: Referenceable record verifier
+Feature #924: Load/Save GUI (still missing loading screen and progress bars)
+Feature #946: Knockdown
+Feature #947: Decrease fatigue when running, swimming and attacking
+Feature #956: Melee Combat: Blocking
+Feature #957: Area magic
+Feature #960: Combat/AI combat for creatures
+Feature #962: Combat-Related AI instructions
+Feature #1075: Damage/Restore skill/attribute magic effects
+Feature #1076: Soultrap magic effect
+Feature #1081: Disease contraction
+Feature #1086: Blood particles
+Feature #1092: Interrupt resting
+Feature #1101: Inventory equip scripts
+Feature #1116: Version/Build number in Launcher window
+Feature #1119: Resistance/weakness to normal weapons magic effect
+Feature #1123: Slow Fall magic effect
+Feature #1130: Auto-calculate spells
+Feature #1164: Editor: Case-insensitive sorting in tables
+
+0.28.0
+
+Bug #399: Inventory changes are not visible immediately
+Bug #417: Apply weather instantly when teleporting
+Bug #566: Global Map position marker not updated for interior cells
+Bug #712: Looting corpse delay
+Bug #716: Problem with the "Vurt's Ascadian Isles Mod" mod
+Bug #805: Two TR meshes appear black (v0.24RC)
+Bug #841: Third-person activation distance taken from camera rather than head
+Bug #845: NPCs hold torches during the day
+Bug #855: Vvardenfell Visages Volume I some hairs don´t appear since 0,24
+Bug #856: Maormer race by Mac Kom - The heads are way up
+Bug #864: Walk locks during loading in 3rd person
+Bug #871: active weapon/magic item icon is not immediately made blank if item is removed during dialog
+Bug #882: Hircine's Ring doesn't always work
+Bug #909: [Tamriel Rebuilt] crashes in Akamora
+Bug #922: Launcher writing merged openmw.cfg files
+Bug #943: Random magnitude should be calculated per effect
+Bug #948: Negative fatigue level should be allowed
+Bug #949: Particles in world space
+Bug #950: Hard crash on x64 Linux running --new-game (on startup)
+Bug #951: setMagicka and setFatigue have no effect
+Bug #954: Problem with equipping inventory items when using a keyboard shortcut
+Bug #955: Issues with equipping torches
+Bug #966: Shield is visible when casting spell
+Bug #967: Game crashes when equipping silver candlestick
+Bug #970: Segmentation fault when starting at Bal Isra
+Bug #977: Pressing down key in console doesn't go forward in history
+Bug #979: Tooltip disappears when changing inventory
+Bug #980: Barter: item category is remembered, but not shown
+Bug #981: Mod: replacing model has wrong position/orientation
+Bug #982: Launcher: Addon unchecking is not saved
+Bug #983: Fix controllers to affect objects attached to the base node
+Bug #985: Player can talk to NPCs who are in combat
+Bug #989: OpenMW crashes when trying to include mod with capital .ESP
+Bug #991: Merchants equip items with harmful constant effect enchantments
+Bug #994: Don't cap skills/attributes when set via console
+Bug #998: Setting the max health should also set the current health
+Bug #1005: Torches are visible when casting spells and during hand to hand combat.
+Bug #1006: Many NPCs have 0 skill
+Bug #1007: Console fills up with text
+Bug #1013: Player randomly loses health or dies
+Bug #1014: Persuasion window is not centered in maximized window
+Bug #1015: Player status window scroll state resets on status change
+Bug #1016: Notification window not big enough for all skill level ups
+Bug #1020: Saved window positions are not rescaled appropriately on resolution change
+Bug #1022: Messages stuck permanently on screen when they pile up
+Bug #1023: Journals doesn't open
+Bug #1026: Game loses track of torch usage.
+Bug #1028: Crash on pickup of jug in Unexplored Shipwreck, Upper level
+Bug #1029: Quick keys menu: Select compatible replacement when tool used up
+Bug #1042: TES3 header data wrong encoding
+Bug #1045: OS X: deployed OpenCS won't launch
+Bug #1046: All damaged weaponry is worth 1 gold
+Bug #1048: Links in "locked" dialogue are still clickable
+Bug #1052: Using color codes when naming your character actually changes the name's color
+Bug #1054: Spell effects not visible in front of water
+Bug #1055: Power-Spell animation starts even though you already casted it that day
+Bug #1059: Cure disease potion removes all effects from player, even your race bonus and race ability
+Bug #1063: Crash upon checking out game start ship area in Seyda Neen
+Bug #1064: openmw binaries link to unnecessary libraries
+Bug #1065: Landing from a high place in water still causes fall damage
+Bug #1072: Drawing weapon increases torch brightness
+Bug #1073: Merchants sell stacks of gold
+Feature #43: Visuals for Magic Effects
+Feature #51: Ranged Magic
+Feature #52: Touch Range Magic
+Feature #53: Self Range Magic
+Feature #54: Spell Casting
+Feature #70: Vampirism
+Feature #100: Combat AI
+Feature #171: Implement NIF record NiFlipController
+Feature #410: Window to restore enchanted item charge
+Feature #647: Enchanted item glow
+Feature #723: Invisibility/Chameleon magic effects
+Feature #737: Resist Magicka magic effect
+Feature #758: GetLOS
+Feature #926: Editor: Info-Record tables
+Feature #958: Material controllers
+Feature #959: Terrain bump, specular, & parallax mapping
+Feature #990: Request: unlock mouse when in any menu
+Feature #1018: Do not allow view mode switching while performing an action
+Feature #1027: Vertex morph animation (NiGeomMorpherController)
+Feature #1031: Handle NiBillboardNode
+Feature #1051: Implement NIF texture slot DarkTexture
+Task #873: Unify OGRE initialisation
+
+0.27.0
+
+Bug #597: Assertion `dialogue->mId == id' failed in esmstore.cpp
+Bug #794: incorrect display of decimal numbers
+Bug #840: First-person sneaking camera height
+Bug #887: Ambient sounds playing while paused
+Bug #902: Problems with Polish character encoding
+Bug #907: Entering third person using the mousewheel is possible even if it's impossible using the key
+Bug #910: Some CDs not working correctly with Unshield installer
+Bug #917: Quick character creation plugin does not work
+Bug #918: Fatigue does not refill
+Bug #919: The PC falls dead in Beshara - OpenMW nightly Win64 (708CDE2)
+Feature #57: Acrobatics Skill
+Feature #462: Editor: Start Dialogue
+Feature #546: Modify ESX selector to handle new content file scheme
+Feature #588: Editor: Adjust name/path of edited content files
+Feature #644: Editor: Save
+Feature #710: Editor: Configure script compiler context
+Feature #790: God Mode
+Feature #881: Editor: Allow only one instance of OpenCS
+Feature #889: Editor: Record filtering
+Feature #895: Extinguish torches
+Feature #898: Breath meter enhancements
+Feature #901: Editor: Default record filter
+Feature #913: Merge --master and --plugin switches
+
+0.26.0
+
+Bug #274: Inconsistencies in the terrain
+Bug #557: Already-dead NPCs do not equip clothing/items.
+Bug #592: Window resizing
+Bug #612: [Tamriel Rebuilt] Missing terrain (South of Tel Oren)
+Bug #664: Heart of lorkhan acts like a dead body (container)
+Bug #767: Wonky ramp physics & water
+Bug #780: Swimming out of water
+Bug #792: Wrong ground alignment on actors when no clipping
+Bug #796: Opening and closing door sound issue
+Bug #797: No clipping hinders opening and closing of doors
+Bug #799: sliders in enchanting window
+Bug #838: Pressing key during startup procedure freezes the game
+Bug #839: Combat/magic stances during character creation
+Bug #843: [Tribunal] Dark Brotherhood assassin appears without equipment
+Bug #844: Resting "until healed" option given even with full stats
+Bug #846: Equipped torches are invisible.
+Bug #847: Incorrect formula for autocalculated NPC initial health
+Bug #850: Shealt weapon sound plays when leaving magic-ready stance
+Bug #852: Some boots do not produce footstep sounds
+Bug #860: FPS bar misalignment
+Bug #861: Unable to print screen
+Bug #863: No sneaking and jumping at the same time
+Bug #866: Empty variables in [Movies] section of Morrowind.ini gets imported into OpenMW.cfg as blank fallback option and crashes game on start.
+Bug #867: Dancing girls in "Suran, Desele's House of Earthly Delights" don't dance.
+Bug #868: Idle animations are repeated
+Bug #874: Underwater swimming close to the ground is jerky
+Bug #875: Animation problem while swimming on the surface and looking up
+Bug #876: Always a starting upper case letter in the inventory
+Bug #878: Active spell effects don't update the layout properly when ended
+Bug #891: Cell 24,-12 (Tamriel Rebuilt) crashes on load
+Bug #896: New game sound issue
+Feature #49: Melee Combat
+Feature #71: Lycanthropy
+Feature #393: Initialise MWMechanics::AiSequence from ESM::AIPackageList
+Feature #622: Multiple positions for inventory window
+Feature #627: Drowning
+Feature #786: Allow the 'Activate' key to close the countdialog window
+Feature #798: Morrowind installation via Launcher (Linux/Max OS only)
+Feature #851: First/Third person transitions with mouse wheel
+Task #689: change PhysicActor::enableCollisions
+Task #707: Reorganise Compiler
+
+0.25.0
+
+Bug #411: Launcher crash on OS X < 10.8
+Bug #604: Terrible performance drop in the Census and Excise Office.
+Bug #676: Start Scripts fail to load
+Bug #677: OpenMW does not accept script names with -
+Bug #766: Extra space in front of topic links
+Bug #793: AIWander Isn't Being Passed The Repeat Parameter
+Bug #795: Sound playing with drawn weapon and crossing cell-border
+Bug #800: can't select weapon for enchantment
+Bug #801: Player can move while over-encumbered
+Bug #802: Dead Keys not working
+Bug #808: mouse capture
+Bug #809: ini Importer does not work without an existing cfg file
+Bug #812: Launcher will run OpenMW with no ESM or ESP selected
+Bug #813: OpenMW defaults to Morrowind.ESM with no ESM or ESP selected
+Bug #817: Dead NPCs and Creatures still have collision boxes
+Bug #820: Incorrect sorting of answers (Dialogue)
+Bug #826: mwinimport dumps core when given an unknown parameter
+Bug #833: getting stuck in door
+Bug #835: Journals/books not showing up properly.
+Feature #38: SoundGen
+Feature #105: AI Package: Wander
+Feature #230: 64-bit compatibility for OS X
+Feature #263: Hardware mouse cursors
+Feature #449: Allow mouse outside of window while paused
+Feature #736: First person animations
+Feature #750: Using mouse wheel in third person mode
+Feature #822: Autorepeat for slider buttons
+
+0.24.0
+
+Bug #284: Book's text misalignment
+Bug #445: Camera able to get slightly below floor / terrain
+Bug #582: Seam issue in Red Mountain
+Bug #632: Journal Next Button shows white square
+Bug #653: IndexedStore ignores index
+Bug #694: Parser does not recognize float values starting with .
+Bug #699: Resource handling broken with Ogre 1.9 trunk
+Bug #718: components/esm/loadcell is using the mwworld subsystem
+Bug #729: Levelled item list tries to add nonexistent item
+Bug #730: Arrow buttons in the settings menu do not work.
+Bug #732: Erroneous behavior when binding keys
+Bug #733: Unclickable dialogue topic
+Bug #734: Book empty line problem
+Bug #738: OnDeath only works with implicit references
+Bug #740: Script compiler fails on scripts with special names
+Bug #742: Wait while no clipping
+Bug #743: Problem with changeweather console command
+Bug #744: No wait dialogue after starting a new game
+Bug #748: Player is not able to unselect objects with the console
+Bug #751: AddItem should only spawn a message box when called from dialogue
+Bug #752: The enter button has several functions in trade and looting that is not impelemted.
+Bug #753: Fargoth's Ring Quest Strange Behavior
+Bug #755: Launcher writes duplicate lines into settings.cfg
+Bug #759: Second quest in mages guild does not work
+Bug #763: Enchantment cast cost is wrong
+Bug #770: The "Take" and "Close" buttons in the scroll GUI are stretched incorrectly
+Bug #773: AIWander Isn't Being Passed The Correct idle Values
+Bug #778: The journal can be opened at the start of a new game
+Bug #779: Divayth Fyr starts as dead
+Bug #787: "Batch count" on detailed FPS counter gets cut-off
+Bug #788: chargen scroll layout does not match vanilla
+Feature #60: Atlethics Skill
+Feature #65: Security Skill
+Feature #74: Interaction with non-load-doors
+Feature #98: Render Weapon and Shield
+Feature #102: AI Package: Escort, EscortCell
+Feature #182: Advanced Journal GUI
+Feature #288: Trading enhancements
+Feature #405: Integrate "new game" into the menu
+Feature #537: Highlight dialogue topic links
+Feature #658: Rotate, RotateWorld script instructions and local rotations
+Feature #690: Animation Layering
+Feature #722: Night Eye/Blind magic effects
+Feature #735: Move, MoveWorld script instructions.
+Feature #760: Non-removable corpses
+
+0.23.0
+
+Bug #522: Player collides with placeable items
+Bug #553: Open/Close sounds played when accessing main menu w/ Journal Open
+Bug #561: Tooltip word wrapping delay
+Bug #578: Bribing works incorrectly
+Bug #601: PositionCell fails on negative coordinates
+Bug #606: Some NPCs hairs not rendered with Better Heads addon
+Bug #609: Bad rendering of bone boots
+Bug #613: Messagebox causing assert to fail
+Bug #631: Segfault on shutdown
+Bug #634: Exception when talking to Calvus Horatius in Mournhold, royal palace courtyard
+Bug #635: Scale NPCs depending on race
+Bug #643: Dialogue Race select function is inverted
+Bug #646: Twohanded weapons don't work properly
+Bug #654: Crash when dropping objects without a collision shape
+Bug #655/656: Objects that were disabled or deleted (but not both) were added to the scene when re-entering a cell
+Bug #660: "g" in "change" cut off in Race Menu
+Bug #661: Arrille sells me the key to his upstairs room
+Bug #662: Day counter starts at 2 instead of 1
+Bug #663: Cannot select "come unprepared" topic in dialog with Dagoth Ur
+Bug #665: Pickpocket -> "Grab all" grabs all NPC inventory, even not listed in container window.
+Bug #666: Looking up/down problem
+Bug #667: Active effects border visible during loading
+Bug #669: incorrect player position at new game start
+Bug #670: race selection menu: sex, face and hair left button not totally clickable
+Bug #671: new game: player is naked
+Bug #674: buying or selling items doesn't change amount of gold
+Bug #675: fatigue is not set to its maximum when starting a new game
+Bug #678: Wrong rotation order causes RefData's rotation to be stored incorrectly
+Bug #680: different gold coins in Tel Mara
+Bug #682: Race menu ignores playable flag for some hairs and faces
+Bug #685: Script compiler does not accept ":" after a function name
+Bug #688: dispose corpse makes cross-hair to disappear
+Bug #691: Auto equipping ignores equipment conditions
+Bug #692: OpenMW doesnt load "loose file" texture packs that places resources directly in data folder
+Bug #696: Draugr incorrect head offset
+Bug #697: Sail transparency issue
+Bug #700: "On the rocks" mod does not load its UV coordinates correctly.
+Bug #702: Some race mods don't work
+Bug #711: Crash during character creation
+Bug #715: Growing Tauryon
+Bug #725: Auto calculate stats
+Bug #728: Failure to open container and talk dialogue
+Bug #731: Crash with Mush-Mere's "background" topic
+Feature #55/657: Item Repairing
+Feature #62/87: Enchanting
+Feature #99: Pathfinding
+Feature #104: AI Package: Travel
+Feature #129: Levelled items
+Feature #204: Texture animations
+Feature #239: Fallback-Settings
+Feature #535: Console object selection improvements
+Feature #629: Add levelup description in levelup layout dialog
+Feature #630: Optional format subrecord in (tes3) header
+Feature #641: Armor rating
+Feature #645: OnDeath script function
+Feature #683: Companion item UI
+Feature #698: Basic Particles
+Task #648: Split up components/esm/loadlocks
+Task #695: mwgui cleanup
+
+0.22.0
+
+Bug #311: Potential infinite recursion in script compiler
+Bug #355: Keyboard repeat rate (in Xorg) are left disabled after game exit.
+Bug #382: Weird effect in 3rd person on water
+Bug #387: Always use detailed shape for physics raycasts
+Bug #420: Potion/ingredient effects do not stack
+Bug #429: Parts of dwemer door not picked up correctly for activation/tooltips
+Bug #434/Bug #605: Object movement between cells not properly implemented
+Bug #502: Duplicate player collision model at origin
+Bug #509: Dialogue topic list shifts inappropriately
+Bug #513: Sliding stairs
+Bug #515: Launcher does not support non-latin strings
+Bug #525: Race selection preview camera wrong position
+Bug #526: Attributes / skills should not go below zero
+Bug #529: Class and Birthsign menus options should be preselected
+Bug #530: Lock window button graphic missing
+Bug #532: Missing map menu graphics
+Bug #545: ESX selector does not list ESM files properly
+Bug #547: Global variables of type short are read incorrectly
+Bug #550: Invisible meshes collision and tooltip
+Bug #551: Performance drop when loading multiple ESM files
+Bug #552: Don't list CG in options if it is not available
+Bug #555: Character creation windows "OK" button broken
+Bug #558: Segmentation fault when Alt-tabbing with console opened
+Bug #559: Dialog window should not be available before character creation is finished
+Bug #560: Tooltip borders should be stretched
+Bug #562: Sound should not be played when an object cannot be picked up
+Bug #565: Water animation speed + timescale
+Bug #572: Better Bodies' textures don't work
+Bug #573: OpenMW doesn't load if TR_Mainland.esm is enabled (Tamriel Rebuilt mod)
+Bug #574: Moving left/right should not cancel auto-run
+Bug #575: Crash entering the Chamber of Song
+Bug #576: Missing includes
+Bug #577: Left Gloves Addon causes ESMReader exception
+Bug #579: Unable to open container "Kvama Egg Sack"
+Bug #581: Mimicking vanilla Morrowind water
+Bug #583: Gender not recognized
+Bug #586: Wrong char gen behaviour
+Bug #587: "End" script statements with spaces don't work
+Bug #589: Closing message boxes by pressing the activation key
+Bug #590: Ugly Dagoth Ur rendering
+Bug #591: Race selection issues
+Bug #593: Persuasion response should be random
+Bug #595: Footless guard
+Bug #599: Waterfalls are invisible from a certain distance
+Bug #600: Waterfalls rendered incorrectly, cut off by water
+Bug #607: New beast bodies mod crashes
+Bug #608: Crash in cell "Mournhold, Royal Palace"
+Bug #611: OpenMW doesn't find some of textures used in Tamriel Rebuilt
+Bug #613: Messagebox causing assert to fail
+Bug #615: Meshes invisible from above water
+Bug #617: Potion effects should be hidden until discovered
+Bug #619: certain moss hanging from tree has rendering bug
+Bug #621: Batching bloodmoon's trees
+Bug #623: NiMaterialProperty alpha unhandled
+Bug #628: Launcher in latest master crashes the game
+Bug #633: Crash on startup: Better Heads
+Bug #636: Incorrect Char Gen Menu Behavior
+Feature #29: Allow ESPs and multiple ESMs
+Feature #94: Finish class selection-dialogue
+Feature #149: Texture Alphas
+Feature #237: Run Morrowind-ini importer from launcher
+Feature #286: Update Active Spell Icons
+Feature #334: Swimming animation
+Feature #335: Walking animation
+Feature #360: Proper collision shapes for NPCs and creatures
+Feature #367: Lights that behave more like original morrowind implementation
+Feature #477: Special local scripting variables
+Feature #528: Message boxes should close when enter is pressed under certain conditions.
+Feature #543: Add bsa files to the settings imported by the ini importer
+Feature #594: coordinate space and utility functions
+Feature #625: Zoom in vanity mode
+Task #464: Refactor launcher ESX selector into a re-usable component
+Task #624: Unified implementation of type-variable sub-records
+
+0.21.0
+
+Bug #253: Dialogs don't work for Russian version of Morrowind
+Bug #267: Activating creatures without dialogue can still activate the dialogue GUI
+Bug #354: True flickering lights
+Bug #386: The main menu's first entry is wrong (in french)
+Bug #479: Adding the spell "Ash Woe Blight" to the player causes strange attribute oscillations
+Bug #495: Activation Range
+Bug #497: Failed Disposition check doesn't stop a dialogue entry from being returned
+Bug #498: Failing a disposition check shouldn't eliminate topics from the the list of those available
+Bug #500: Disposition for most NPCs is 0/100
+Bug #501: Getdisposition command wrongly returns base disposition
+Bug #506: Journal UI doesn't update anymore
+Bug #507: EnableRestMenu is not a valid command - change it to EnableRest
+Bug #508: Crash in Ald Daedroth Shrine
+Bug #517: Wrong price calculation when untrading an item
+Bug #521: MWGui::InventoryWindow creates a duplicate player actor at the origin
+Bug #524: Beast races are able to wear shoes
+Bug #527: Background music fails to play
+Bug #533: The arch at Gnisis entrance is not displayed
+Bug #534: Terrain gets its correct shape only some time after the cell is loaded
+Bug #536: The same entry can be added multiple times to the journal
+Bug #539: Race selection is broken
+Bug #544: Terrain normal map corrupt when the map is rendered
+Feature #39: Video Playback
+Feature #151: ^-escape sequences in text output
+Feature #392: Add AI related script functions
+Feature #456: Determine required ini fallback values and adjust the ini importer accordingly
+Feature #460: Experimental DirArchives improvements
+Feature #540: Execute scripts of objects in containers/inventories in active cells
+Task #401: Review GMST fixing
+Task #453: Unify case smashing/folding
+Task #512: Rewrite utf8 component
+
+0.20.0
+
+Bug #366: Changing the player's race during character creation does not change the look of the player character
+Bug #430: Teleporting and using loading doors linking within the same cell reloads the cell
+Bug #437: Stop animations when paused
+Bug #438: Time displays as "0 a.m." when it should be "12 a.m."
+Bug #439: Text in "name" field of potion/spell creation window is persistent
+Bug #440: Starting date at a new game is off by one day
+Bug #442: Console window doesn't close properly sometimes
+Bug #448: Do not break container window formatting when item names are very long
+Bug #458: Topics sometimes not automatically added to known topic list
+Bug #476: Auto-Moving allows player movement after using DisablePlayerControls
+Bug #478: After sleeping in a bed the rest dialogue window opens automtically again
+Bug #492: On creating potions the ingredients are removed twice
+Feature #63: Mercantile skill
+Feature #82: Persuasion Dialogue
+Feature #219: Missing dialogue filters/functions
+Feature #369: Add a FailedAction
+Feature #377: Select head/hair on character creation
+Feature #391: Dummy AI package classes
+Feature #435: Global Map, 2nd Layer
+Feature #450: Persuasion
+Feature #457: Add more script instructions
+Feature #474: update the global variable pcrace when the player's race is changed
+Task #158: Move dynamically generated classes from Player class to World Class
+Task #159: ESMStore rework and cleanup
+Task #163: More Component Namespace Cleanup
+Task #402: Move player data from MWWorld::Player to the player's NPC record
+Task #446: Fix no namespace in BulletShapeLoader
+
+0.19.0
+
+Bug #374: Character shakes in 3rd person mode near the origin
+Bug #404: Gamma correct rendering
+Bug #407: Shoes of St. Rilm do not work
+Bug #408: Rugs has collision even if they are not supposed to
+Bug #412: Birthsign menu sorted incorrectly
+Bug #413: Resolutions presented multiple times in launcher
+Bug #414: launcher.cfg file stored in wrong directory
+Bug #415: Wrong esm order in openmw.cfg
+Bug #418: Sound listener position updates incorrectly
+Bug #423: wrong usage of "Version" entry in openmw.desktop
+Bug #426: Do not use hardcoded splash images
+Bug #431: Don't use markers for raycast
+Bug #432: Crash after picking up items from an NPC
+Feature #21/#95: Sleeping/resting
+Feature #61: Alchemy Skill
+Feature #68: Death
+Feature #69/#86: Spell Creation
+Feature #72/#84: Travel
+Feature #76: Global Map, 1st Layer
+Feature #120: Trainer Window
+Feature #152: Skill Increase from Skill Books
+Feature #160: Record Saving
+Task #400: Review GMST access
+
+0.18.0
+
+Bug #310: Button of the "preferences menu" are too small
+Bug #361: Hand-to-hand skill is always 100
+Bug #365: NPC and creature animation is jerky; Characters float around when they are not supposed to
+Bug #372: playSound3D uses original coordinates instead of current coordinates.
+Bug #373: Static OGRE build faulty
+Bug #375: Alt-tab toggle view
+Bug #376: Screenshots are disable
+Bug #378: Exception when drinking self-made potions
+Bug #380: Cloth visibility problem
+Bug #384: Weird character on doors tooltip.
+Bug #398: Some objects do not collide in MW, but do so in OpenMW
+Feature #22: Implement level-up
+Feature #36: Hide Marker
+Feature #88: Hotkey Window
+Feature #91: Level-Up Dialogue
+Feature #118: Keyboard and Mouse-Button bindings
+Feature #119: Spell Buying Window
+Feature #133: Handle resources across multiple data directories
+Feature #134: Generate a suitable default-value for --data-local
+Feature #292: Object Movement/Creation Script Instructions
+Feature #340: AIPackage data structures
+Feature #356: Ingredients use
+Feature #358: Input system rewrite
+Feature #370: Target handling in actions
+Feature #379: Door markers on the local map
+Feature #389: AI framework
+Feature #395: Using keys to open doors / containers
+Feature #396: Loading screens
+Feature #397: Inventory avatar image and race selection head preview
+Task #339: Move sounds into Action
+
+0.17.0
+
+Bug #225: Valgrind reports about 40MB of leaked memory
+Bug #241: Some physics meshes still don't match
+Bug #248: Some textures are too dark
+Bug #300: Dependency on proprietary CG toolkit
+Bug #302: Some objects don't collide although they should
+Bug #308: Freeze in Balmora, Meldor: Armorer
+Bug #313: openmw without a ~/.config/openmw folder segfault.
+Bug #317: adding non-existing spell via console locks game
+Bug #318: Wrong character normals
+Bug #341: Building with Ogre Debug libraries does not use debug version of plugins
+Bug #347: Crash when running openmw with --start="XYZ"
+Bug #353: FindMyGUI.cmake breaks path on Windows
+Bug #359: WindowManager throws exception at destruction
+Bug #364: Laggy input on OS X due to bug in Ogre's event pump implementation
+Feature #33: Allow objects to cross cell-borders
+Feature #59: Dropping Items (replaced stopgap implementation with a proper one)
+Feature #93: Main Menu
+Feature #96/329/330/331/332/333: Player Control
+Feature #180: Object rotation and scaling.
+Feature #272: Incorrect NIF material sharing
+Feature #314: Potion usage
+Feature #324: Skill Gain
+Feature #342: Drain/fortify dynamic stats/attributes magic effects
+Feature #350: Allow console only script instructions
+Feature #352: Run scripts in console on startup
+Task #107: Refactor mw*-subsystems
+Task #325: Make CreatureStats into a class
+Task #345: Use Ogre's animation system
+Task #351: Rewrite Action class to support automatic sound playing
+
+0.16.0
+
+Bug #250: OpenMW launcher erratic behaviour
+Bug #270: Crash because of underwater effect on OS X
+Bug #277: Auto-equipping in some cells not working
+Bug #294: Container GUI ignores disabled inventory menu
+Bug #297: Stats review dialog shows all skills and attribute values as 0
+Bug #298: MechanicsManager::buildPlayer does not remove previous bonuses
+Bug #299: Crash in World::disable
+Bug #306: Non-existent ~/.config/openmw "crash" the launcher.
+Bug #307: False "Data Files" location make the launcher "crash"
+Feature #81: Spell Window
+Feature #85: Alchemy Window
+Feature #181: Support for x.y script syntax
+Feature #242: Weapon and Spell icons
+Feature #254: Ingame settings window
+Feature #293: Allow "stacking" game modes
+Feature #295: Class creation dialog tooltips
+Feature #296: Clicking on the HUD elements should show/hide the respective window
+Feature #301: Direction after using a Teleport Door
+Feature #303: Allow object selection in the console
+Feature #305: Allow the use of = as a synonym for ==
+Feature #312: Compensation for slow object access in poorly written Morrowind.esm scripts
+Task #176: Restructure enabling/disabling of MW-references
+Task #283: Integrate ogre.cfg file in settings file
+Task #290: Auto-Close MW-reference related GUI windows
+
+0.15.0
+
+Bug #5: Physics reimplementation (fixes various issues)
+Bug #258: Resizing arrow's background is not transparent
+Bug #268: Widening the stats window in X direction causes layout problems
+Bug #269: Topic pane in dialgoue window is too small for some longer topics
+Bug #271: Dialog choices are sorted incorrectly
+Bug #281: The single quote character is not rendered on dialog windows
+Bug #285: Terrain not handled properly in cells that are not predefined
+Bug #289: Dialogue filter isn't doing case smashing/folding for item IDs
+Feature #15: Collision with Terrain
+Feature #17: Inventory-, Container- and Trade-Windows
+Feature #44: Floating Labels above Focussed Objects
+Feature #80: Tooltips
+Feature #83: Barter Dialogue
+Feature #90: Book and Scroll Windows
+Feature #156: Item Stacking in Containers
+Feature #213: Pulsating lights
+Feature #218: Feather & Burden
+Feature #256: Implement magic effect bookkeeping
+Feature #259: Add missing information to Stats window
+Feature #260: Correct case for dialogue topics
+Feature #280: GUI texture atlasing
+Feature #291: Ability to use GMST strings from GUI layout files
+Task #255: Make MWWorld::Environment into a singleton
+
+0.14.0
+
+Bug #1: Meshes rendered with wrong orientation
+Bug #6/Task #220: Picking up small objects doesn't always work
+Bug #127: tcg doesn't work
+Bug #178: Compablity problems with Ogre 1.8.0 RC 1
+Bug #211: Wireframe mode (toggleWireframe command) should not apply to Console & other UI
+Bug #227: Terrain crashes when moving away from predefined cells
+Bug #229: On OS X Launcher cannot launch game if path to binary contains spaces
+Bug #235: TGA texture loading problem
+Bug #246: wireframe mode does not work in water
+Feature #8/#232: Water Rendering
+Feature #13: Terrain Rendering
+Feature #37: Render Path Grid
+Feature #66: Factions
+Feature #77: Local Map
+Feature #78: Compass/Mini-Map
+Feature #97: Render Clothing/Armour
+Feature #121: Window Pinning
+Feature #205: Auto equip
+Feature #217: Contiainer should track changes to its content
+Feature #221: NPC Dialogue Window Enhancements
+Feature #233: Game settings manager
+Feature #240: Spell List and selected spell (no GUI yet)
+Feature #243: Draw State
+Task #113: Morrowind.ini Importer
+Task #215: Refactor the sound code
+Task #216: Update MyGUI
+
+0.13.0
+
+Bug #145: Fixed sound problems after cell change
+Bug #179: Pressing space in console triggers activation
+Bug #186: CMake doesn't use the debug versions of Ogre libraries on Linux
+Bug #189: ASCII 16 character added to console on it's activation on Mac OS X
+Bug #190: Case Folding fails with music files
+Bug #192: Keypresses write Text into Console no matter which gui element is active
+Bug #196: Collision shapes out of place
+Bug #202: ESMTool doesn't not work with localised ESM files anymore
+Bug #203: Torch lights only visible on short distance
+Bug #207: Ogre.log not written
+Bug #209: Sounds do not play
+Bug #210: Ogre crash at Dren plantation
+Bug #214: Unsupported file format version
+Bug #222: Launcher is writing openmw.cfg file to wrong location
+Feature #9: NPC Dialogue Window
+Feature #16/42: New sky/weather implementation
+Feature #40: Fading
+Feature #48: NPC Dialogue System
+Feature #117: Equipping Items (backend only, no GUI yet, no rendering of equipped items yet)
+Feature #161: Load REC_PGRD records
+Feature #195: Wireframe-mode
+Feature #198/199: Various sound effects
+Feature #206: Allow picking data path from launcher if non is set
+Task #108: Refactor window manager class
+Task #172: Sound Manager Cleanup
+Task #173: Create OpenEngine systems in the appropriate manager classes
+Task #184: Adjust MSVC and gcc warning levels
+Task #185: RefData rewrite
+Task #201: Workaround for transparency issues
+Task #208: silenced esm_reader.hpp warning
+
+0.12.0
+
+Bug #154: FPS Drop
+Bug #169: Local scripts continue running if associated object is deleted
+Bug #174: OpenMW fails to start if the config directory doesn't exist
+Bug #187: Missing lighting
+Bug #188: Lights without a mesh are not rendered
+Bug #191: Taking screenshot causes crash when running installed
+Feature #28: Sort out the cell load problem
+Feature #31: Allow the player to move away from pre-defined cells
+Feature #35: Use alternate storage location for modified object position
+Feature #45: NPC animations
+Feature #46: Creature Animation
+Feature #89: Basic Journal Window
+Feature #110: Automatically pick up the path of existing MW-installations
+Feature #183: More FPS display settings
+Task #19: Refactor engine class
+Task #109/Feature #162: Automate Packaging
+Task #112: Catch exceptions thrown in input handling functions
+Task #128/#168: Cleanup Configuration File Handling
+Task #131: NPC Activation doesn't work properly
+Task #144: MWRender cleanup
+Task #155: cmake cleanup
+
+0.11.1
+
+Bug #2: Resources loading doesn't work outside of bsa files
+Bug #3: GUI does not render non-English characters
+Bug #7: openmw.cfg location doesn't match
+Bug #124: The TCL alias for ToggleCollision is missing.
+Bug #125: Some command line options can't be used from a .cfg file
+Bug #126: Toggle-type script instructions are less verbose compared with original MW
+Bug #130: NPC-Record Loading fails for some NPCs
+Bug #167: Launcher sets invalid parameters in ogre config
+Feature #10: Journal
+Feature #12: Rendering Optimisations
+Feature #23: Change Launcher GUI to a tabbed interface
+Feature #24: Integrate the OGRE settings window into the launcher
+Feature #25: Determine openmw.cfg location (Launcher)
+Feature #26: Launcher Profiles
+Feature #79: MessageBox
+Feature #116: Tab-Completion in Console
+Feature #132: --data-local and multiple --data
+Feature #143: Non-Rendering Performance-Optimisations
+Feature #150: Accessing objects in cells via ID does only work for objects with all lower case IDs
+Feature #157: Version Handling
+Task #14: Replace tabs with 4 spaces
+Task #18: Move components from global namespace into their own namespace
+Task #123: refactor header files in components/esm
+
+0.10.0
+
+* NPC dialogue window (not functional yet)
+* Collisions with objects
+* Refactor the PlayerPos class
+* Adjust file locations
+* CMake files and test linking for Bullet
+* Replace Ogre raycasting test for activation with something more precise
+* Adjust player movement according to collision results
+* FPS display
+* Various Portability Improvements
+* Mac OS X support is back!
+
+0.9.0
+
+* Exterior cells loading, unloading and management
+* Character Creation GUI
+* Character creation
+* Make cell names case insensitive when doing internal lookups
+* Music player
+* NPCs rendering
+
+0.8.0
+
+* GUI
+* Complete and working script engine
+* In game console
+* Sky rendering
+* Sound and music
+* Tons of smaller stuff
+
+0.7.0
+
+* This release is a complete rewrite in C++.
+* All D code has been culled, and all modules have been rewritten.
+* The game is now back up to the level of rendering interior cells and moving around, but physics, sound, GUI, and scripting still remain to be ported from the old codebase.
+
+0.6.0
+
+* Coded a GUI system using MyGUI
+* Skinned MyGUI to look like Morrowind (work in progress)
+* Integrated the Monster script engine
+* Rewrote some functions into script code
+* Very early MyGUI < > Monster binding
+* Fixed Windows sound problems (replaced old openal32.dll)
+
+0.5.0
+
+* Collision detection with Bullet
+* Experimental walk & fall character physics
+* New key bindings:
+  * t toggle physics mode (walking, flying, ghost),
+  * n night eye, brightens the scene
+* Fixed incompatability with DMD 1.032 and newer compilers
+* * (thanks to tomqyp)
+* Various minor changes and updates
+
+0.4.0
+
+* Switched from Audiere to OpenAL
+* * (BIG thanks to Chris Robinson)
+* Added complete Makefile (again) as a alternative build tool
+* More realistic lighting (thanks again to Chris Robinson)
+* Various localization fixes tested with Russian and French versions
+* Temporary workaround for the Unicode issue: invalid UTF displayed as '?'
+* Added ns option to disable sound, for debugging
+* Various bug fixes
+* Cosmetic changes to placate gdc Wall
+
+0.3.0
+
+* Built and tested on Windows XP
+* Partial support for FreeBSD (exceptions do not work)
+* You no longer have to download Monster separately
+* Made an alternative for building without DSSS (but DSSS still works)
+* Renamed main program from 'morro' to 'openmw'
+* Made the config system more robust
+* Added oc switch for showing Ogre config window on startup
+* Removed some config files, these are auto generated when missing.
+* Separated plugins.cfg into linux and windows versions.
+* Updated Makefile and sources for increased portability
+* confirmed to work against OIS 1.0.0 (Ubuntu repository package)
+
+0.2.0
+
+* Compiles with gdc
+* Switched to DSSS for building D code
+* Includes the program esmtool
+
+0.1.0
+
+first release
+
diff --git a/README.md b/README.md index 304844892..862ae16c7 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,7 @@ Morrowind by Bethesda Softworks. You need to own and install the original game f * Website: http://www.openmw.org Font Licenses: -DejaVuLGCSansMono.ttf: custom (see DejaVu Font License.txt for more information) - +* DejaVuLGCSansMono.ttf: custom (see DejaVu Font License.txt for more information) Installation ============ @@ -34,17 +33,15 @@ Build from source https://wiki.openmw.org/index.php?title=Development_Environment_Setup - The data path ============= -The data path tells OpenMW where to find your Morrowind files. If you run the launcher, OpenMW should be able to -pick up the location of these files on its own, if both Morrowind and OpenMW are installed properly -(installing Morrowind under WINE is considered a proper install). +The data path tells OpenMW where to find your Morrowind files. If you run the launcher, OpenMW should be able to pick up the location of these files on its own, if both Morrowind and OpenMW are installed properly (installing Morrowind under WINE is considered a proper install). Command line options ==================== +
 Syntax: openmw 
 Allowed options:
   --help                                print help message
@@ -99,1470 +96,9 @@ Allowed options:
   --fallback arg                        fallback values
   --no-grab                             Don't grab mouse cursor
   --activate-dist arg (=-1)             activation distance override
+
Changelog ========= -0.34.0 - -Bug #904: omwlauncher doesn't allow installing Tribunal and Bloodmoon if only MW is installed -Bug #986: Launcher: renaming profile names is broken -Bug #1061: "Browse to CD..." launcher crash -Bug #1135: Launcher crashes if user does not have write permission -Bug #1231: Current installer in launcher does not correctly import russian Morrowind.ini settings from setup.inx -Bug #1288: Fix the Alignment of the Resolution Combobox -Bug #1343: BIK videos occasionally out of sync with audio -Bug #1684: Morrowind Grass Mod graphical glitches -Bug #1734: NPC in fight with invisible/sneaking player -Bug #1982: Long class names are cut off in the UI -Bug #2012: Editor: OpenCS script compiler sometimes fails to find IDs -Bug #2015: Running while levitating does not affect speed but still drains fatigue -Bug #2018: OpenMW don´t reset modified cells to vanilla when a plugin is deselected and don´t apply changes to cells already visited. -Bug #2045: ToggleMenus command should close dialogue windows -Bug #2046: Crash: light_de_streetlight_01_223 -Bug #2047: Buglamp tooltip minor correction -Bug #2050: Roobrush floating texture bits -Bug #2053: Slaves react negatively to PC picking up slave's bracers -Bug #2055: Dremora corpses use the wrong model -Bug #2056: Mansilamat Vabdas's corpse is floating in the water -Bug #2057: "Quest: Larius Varro Tells A Little Story": Bounty not completely removed after finishing quest -Bug #2059: Silenced enemies try to cast spells anyway -Bug #2060: Editor: Special case implementation for top level window with single sub-window should be optional -Bug #2061: Editor: SubView closing that is not directly triggered by the user isn't handled properly -Bug #2063: Tribunal: Quest 'The Warlords' doesn't work -Bug #2064: Sneak attack on hostiles causes bounty -Bug #2065: Editor: Qt signal-slot error when closing a dialogue subview -Bug #2070: Loading ESP in OpenMW works but fails in OpenCS -Bug #2071: CTD in 0.33 -Bug #2073: Storm atronach animation stops now and then -Bug #2075: Molag Amur Region, Map shows water on solid ground -Bug #2080: game won't work with fair magicka regen -Bug #2082: NPCs appear frozen or switched off after leaving and quickly reentering a cell -Bug #2088: OpenMW is unable to play OGG files. -Bug #2093: Darth Gares talks to you in Ilunibi even when he's not there, screwing up the Main Quests -Bug #2095: Coordinate and rotation editing in the Reference table does not work. -Bug #2096: Some overflow fun and bartering exploit -Bug #2098: [D3D] Game crash on maximize -Bug #2099: Activate, player seems not to work -Bug #2104: Only labels are sensitive in buttons -Bug #2107: "Slowfall" effect is too weak -Bug #2114: OpenCS doesn't load an ESP file full of errors even though Vanilla MW Construction Set can -Bug #2117: Crash when encountering bandits on opposite side of river from the egg mine south of Balmora -Bug #2124: [Mod: Baldurians Transparent Glass Amor] Armor above head -Bug #2125: Unnamed NiNodes in weapons problem in First Person -Bug #2126: Dirty dialog script in tribunal.esm causing bug in Tribunal MQ -Bug #2128: Crash when picking character's face -Bug #2129: Disable the third-person zoom feature by default -Bug #2130: Ash storm particles shown too long during transition to clear sky -Bug #2137: Editor: exception caused by following the Creature column of a SoundGen record -Bug #2139: Mouse movement should be ignored during intro video -Bug #2143: Editor: Saving is broken -Bug #2145: OpenMW - crash while exiting x64 debug build -Bug #2152: You can attack Almalexia during her final monologue -Bug #2154: Visual effects behave weirdly after loading/taking a screenshot -Bug #2155: Vivec has too little magicka -Bug #2156: Azura's spirit fades away too fast -Bug #2158: [Mod]Julan Ashlander Companion 2.0: Negative magicka -Bug #2161: Editor: combat/magic/stealth values of creature not displayed correctly -Bug #2163: OpenMW can't detect death if the NPC die by the post damage effect of a magic weapon. -Bug #2168: Westly's Master Head Pack X – Some hairs aren't rendered correctly. -Bug #2170: Mods using conversations to update PC inconsistant -Bug #2180: Editor: Verifier doesn't handle Windows-specific path issues when dealing with resources -Bug #2212: Crash or unexpected behavior while closing OpenCS cell render window on OS X -Feature #238: Add UI to run INI-importer from the launcher -Feature #854: Editor: Add user setting to show status bar -Feature #987: Launcher: first launch instructions for CD need to be more explicit -Feature #1232: There is no way to set the "encoding" option using launcher UI. -Feature #1281: Editor: Render cell markers -Feature #1918: Editor: Functionality for Double-Clicking in Tables -Feature #1966: Editor: User Settings dialogue grouping/labelling/tooltips -Feature #2097: Editor: Edit position of references in 3D scene -Feature #2121: Editor: Add edit mode button to scene toolbar -Task #1965: Editor: Improve layout of user settings dialogue - -0.33.1 - -Bug #2108: OpenCS fails to build - -0.33.0 - -Bug #371: If console assigned to ` (probably to any symbolic key), "`" symbol will be added to console every time it closed -Bug #1148: Some books'/scrolls' contents are displayed incorrectly -Bug #1290: Editor: status bar is not updated when record filter is changed -Bug #1292: Editor: Documents are not removed on closing the last view -Bug #1301: Editor: File->Exit only checks the document it was issued from. -Bug #1353: Bluetooth on with no speaker connected results in significantly longer initial load times -Bug #1436: NPCs react from too far distance -Bug #1472: PC is placed on top of following NPC when changing cell -Bug #1487: Tall PC can get stuck in staircases -Bug #1565: Editor: Subviews are deleted on shutdown instead when they are closed -Bug #1623: Door marker on Ghorak Manor's balcony makes PC stuck -Bug #1633: Loaddoor to Sadrith Mora, Telvanni Council House spawns PC in the air -Bug #1655: Use Appropriate Application Icons on Windows -Bug #1679: Tribunal expansion, Meryn Othralas the backstage manager in the theatre group in Mournhold in the great bazaar district is floating a good feet above the ground. -Bug #1705: Rain is broken in third person -Bug #1706: Thunder and lighting still occurs while the game is paused during the rain -Bug #1708: No long jumping -Bug #1710: Editor: ReferenceableID drag to references record filter field creates incorrect filter -Bug #1712: Rest on Water -Bug #1715: "Cancel" button is not always on the same side of menu -Bug #1725: Editor: content file can be opened multiple times from the same dialogue -Bug #1730: [MOD: Less Generic Nerevarine] Compile failure attempting to enter the Corprusarium. -Bug #1733: Unhandled ffmpeg sample formats -Bug #1735: Editor: "Edit Record" context menu button not opening subview for journal infos -Bug #1750: Editor: record edits result in duplicate entries -Bug #1789: Editor: Some characters cannot be used in addon name -Bug #1803: Resizing the map does not keep the pre-resize center at the post-resize center -Bug #1821: Recovering Cloudcleaver quest: attacking Sosia is considered a crime when you side with Hlormar -Bug #1838: Editor: Preferences window appears off screen -Bug #1839: Editor: Record filter title should be moved two pixels to the right -Bug #1849: Subrecord error in MAO_Containers -Bug #1854: Knocked-out actors don't fully act knocked out -Bug #1855: "Soul trapped" sound doesn't play -Bug #1857: Missing sound effect for enchanted items with empty charge -Bug #1859: Missing console command: ResetActors (RA) -Bug #1861: Vendor category "MagicItems" is unhandled -Bug #1862: Launcher doesn't start if a file listed in launcher.cfg has correct name but wrong capitalization -Bug #1864: Editor: Region field for cell record in dialogue subview not working -Bug #1869: Editor: Change label "Musics" to "Music" -Bug #1870: Goblins killed while knocked down remain in knockdown-pose -Bug #1874: CellChanged events should not trigger when crossing exterior cell border -Bug #1877: Spriggans killed instantly if hit while regening -Bug #1878: Magic Menu text not un-highlighting correctly when going from spell to item as active magic -Bug #1881: Stuck in ceiling when entering castle karstaags tower -Bug #1884: Unlit torches still produce a burning sound -Bug #1885: Can type text in price field in barter window -Bug #1887: Equipped items do not emit sounds -Bug #1889: draugr lord aesliip will attack you and remain non-hostile -Bug #1892: Guard asks player to pay bounty of 0 gold -Bug #1895: getdistance should only return max float if ref and target are in different worldspaces -Bug #1896: Crash Report -Bug #1897: Conjured Equipment cant be re-equipped if removed -Bug #1898: Only Gidar Verothan follows you during establish the mine quest -Bug #1900: Black screen when you open the door and breath underwater -Bug #1904: Crash on casting recall spell -Bug #1906: Bound item checks should use the GMSTs -Bug #1907: Bugged door. Mournhold, The Winged Guar -Bug #1908: Crime reported for attacking Drathas Nerus's henchmen while they attack Dilborn -Bug #1909: Weird Quest Flow Infidelities quest -Bug #1910: Follower fighting with gone npc -Bug #1911: Npcs will drown themselves -Bug #1912: World map arrow stays static when inside a building -Bug #1920: Ulyne Henim disappears when game is loaded inside Vas -Bug #1922: alchemy-> potion of paralyze -Bug #1923: "levitation magic cannot be used here" shows outside of tribunal -Bug #1927: AI prefer melee over magic. -Bug #1929: Tamriel Rebuilt: Named cells that lie within the overlap with Morrowind.esm are not shown -Bug #1932: BTB - Spells 14.1 magic effects don´t overwrite the Vanilla ones but are added -Bug #1935: Stacks of items are worth more when sold individually -Bug #1940: Launcher does not list addon files if base game file is renamed to a different case -Bug #1946: Mod "Tel Nechim - moved" breaks savegames -Bug #1947: Buying/Selling price doesn't properly affect the growth of mercantile skill -Bug #1950: followers from east empire company quest will fight each other if combat happens with anything -Bug #1958: Journal can be scrolled indefinitely with a mouse wheel -Bug #1959: Follower not leaving party on quest end -Bug #1960: Key bindings not always saved correctly -Bug #1961: Spell merchants selling racial bonus spells -Bug #1967: segmentation fault on load saves -Bug #1968: Jump sounds are not controlled by footsteps slider, sound weird compared to footsteps -Bug #1970: PC suffers silently when taking damage from lava -Bug #1971: Dwarven Sceptre collision area is not removed after killing one -Bug #1974: Dalin/Daris Norvayne follows player indefinitely -Bug #1975: East Empire Company faction rank breaks during Raven Rock questline -Bug #1979: 0 strength = permanently over encumbered -Bug #1993: Shrine blessing in Maar Gan doesn't work -Bug #2008: Enchanted items do not recharge -Bug #2011: Editor: OpenCS script compiler doesn't handle member variable access properly -Bug #2016: Dagoth Ur already dead in Facility Cavern -Bug #2017: Fighters Guild Quest: The Code Book - dialogue loop when UMP is loaded. -Bug #2019: Animation of 'Correct UV Mudcrabs' broken -Bug #2022: Alchemy window - Removing ingredient doesn't remove the number of ingredients -Bug #2025: Missing mouse-over text for non affordable items -Bug #2028: [MOD: Tamriel Rebuilt] Crashing when trying to enter interior cell "Ruinous Keep, Great Hall" -Bug #2029: Ienith Brothers Thiev's Guild quest journal entry not adding -Feature #471: Editor: Special case implementation for top-level window with single sub-window -Feature #472: Editor: Sub-Window re-use settings -Feature #704: Font colors import from fallback settings -Feature #879: Editor: Open sub-views in a new top-level window -Feature #932: Editor: magic effect table -Feature #937: Editor: Path Grid table -Feature #938: Editor: Sound Gen table -Feature #1117: Death and LevelUp music -Feature #1226: Editor: Request UniversalId editing from table columns -Feature #1545: Targeting console on player -Feature #1597: Editor: Render terrain -Feature #1695: Editor: add column for CellRef's global variable -Feature #1696: Editor: use ESM::Cell's RefNum counter -Feature #1697: Redden player's vision when hit -Feature #1856: Spellcasting for non-biped creatures -Feature #1879: Editor: Run OpenMW with the currently edited content list -Task #1851: Move AI temporary state out of AI packages -Task #1865: Replace char type in records - -0.32.0 - -Bug #1132: Unable to jump when facing a wall -Bug #1341: Summoned Creatures do not immediately disappear when killed. -Bug #1430: CharGen Revamped script does not compile -Bug #1451: NPCs shouldn't equip weapons prior to fighting -Bug #1461: Stopped start scripts do not restart on load -Bug #1473: Dead NPC standing and in 2 pieces -Bug #1482: Abilities are depleted when interrupted during casting -Bug #1503: Behaviour of NPCs facing the player -Bug #1506: Missing character, French edition: three-points -Bug #1528: Inventory very slow after 2 hours -Bug #1540: Extra arguments should be ignored for script functions -Bug #1541: Helseth's Champion: Tribunal -Bug #1570: Journal cannot be opened while in inventory screen -Bug #1573: PC joins factions at random -Bug #1576: NPCs aren't switching their weapons when out of ammo -Bug #1579: Guards detect creatures in far distance, instead on sight -Bug #1588: The Siege of the Skaal Village: bloodmoon -Bug #1593: The script compiler isn't recognising some names that contain a - -Bug #1606: Books: Question marks instead of quotation marks -Bug #1608: Dead bodies prevent door from opening/closing. -Bug #1609: Imperial guards in Sadrith Mora are not using their spears -Bug #1610: The bounty number is not displayed properly with high numbers -Bug #1620: Implement correct formula for auto-calculated NPC spells -Bug #1630: Boats standing vertically in Vivec -Bug #1635: Arrest dialogue is executed second time after I select "Go to jail" -Bug #1637: Weird NPC behaviour in Vivec, Hlaalu Ancestral Vaults? -Bug #1641: Persuasion dialog remains after loading, possibly resulting in crash -Bug #1644: "Goodbye" and similar options on dialogues prevents escape working properly. -Bug #1646: PC skill stats are not updated immediately when changing equipment -Bug #1652: Non-aggressive creature -Bug #1653: Quickloading while the container window is open crashes the game -Bug #1654: Priority of checks in organic containers -Bug #1656: Inventory items merge issue when repairing -Bug #1657: Attacked state of NPCs is not saved properly -Bug #1660: Rank dialogue condition ignored -Bug #1668: Game starts on day 2 instead of day 1 -Bug #1669: Critical Strikes while fighting a target who is currently fighting me -Bug #1672: OpenCS doesn't save the projects -Bug #1673: Fatigue decreasing by only one point when running -Bug #1675: Minimap and localmap graphic glitches -Bug #1676: Pressing the OK button on the travel menu cancels the travel and exits the menu -Bug #1677: Sleeping in a rented bed is considered a crime -Bug #1685: NPCs turn towards player even if invisible/sneaking -Bug #1686: UI bug: cursor is clicking "world/local" map button while inventory window is closed? -Bug #1690: Double clicking on a inventory window header doesn't close it. -Bug #1693: Spell Absorption does not absorb shrine blessings -Bug #1694: journal displays learned topics as quests -Bug #1700: Sideways scroll of text boxes -Bug #1701: Player enchanting requires player hold money, always 100% sucessful. -Bug #1704: self-made Fortify Intelligence/Drain willpower potions are broken -Bug #1707: Pausing the game through the esc menu will silence rain, pausing it by opening the inventory will not. -Bug #1709: Remesa Othril is hostile to Hlaalu members -Bug #1713: Crash on load after death -Bug #1719: Blind effect has slight border at the edge of the screen where it is ineffective. -Bug #1722: Crash after creating enchanted item, reloading saved game -Bug #1723: Content refs that are stacked share the same index after unstacking -Bug #1726: Can't finish Aengoth the Jeweler's quest : Retrieve the Scrap Metal -Bug #1727: Targets almost always resist soultrap scrolls -Bug #1728: Casting a soultrap spell on invalid target yields no message -Bug #1729: Chop attack doesn't work if walking diagonally -Bug #1732: Error handling for missing script function arguments produces weird message -Bug #1736: Alt-tabbing removes detail from overworld map. -Bug #1737: Going through doors with (high magnitude?) leviation will put the player high up, possibly even out of bounds. -Bug #1739: Setting a variable on an NPC from another NPC's dialogue result sets the wrong variable -Bug #1741: The wait dialogue doesn't black the screen out properly during waiting. -Bug #1742: ERROR: Object 'sDifficulty' not found (const) -Bug #1744: Night sky in Skies V.IV (& possibly v3) by SWG rendered incorrectly -Bug #1746: Bow/marksman weapon condition does not degrade with use -Bug #1749: Constant Battle Music -Bug #1752: Alt-Tabbing in the character menus makes the paper doll disappear temporarily -Bug #1753: Cost of training is not added to merchant's inventory -Bug #1755: Disposition changes do not persist if the conversation menu is closed by purchasing training. -Bug #1756: Caught Blight after being cured of Corprus -Bug #1758: Crash Upon Loading New Cell -Bug #1760: Player's Magicka is not recalculated upon drained or boosted intelligence -Bug #1761: Equiped torches lost on reload -Bug #1762: Your spell did not get a target. Soul trap. Gorenea Andrano -Bug #1763: Custom Spell Magicka Cost -Bug #1765: Azuras Star breaks on recharging item -Bug #1767: GetPCRank did not handle ignored explicit references -Bug #1772: Dark Brotherhood Assassins never use their Carved Ebony Dart, sticking to their melee weapon. -Bug #1774: String table overflow also occurs when loading TheGloryRoad.esm -Bug #1776: dagoth uthol runs in slow motion -Bug #1778: Incorrect values in spellmaking window -Bug #1779: Icon of Master Propylon Index is not visible -Bug #1783: Invisible NPC after looting corpse -Bug #1787: Health Calculation -Bug #1788: Skeletons, ghosts etc block doors when we try to open -Bug #1791: [MOD: LGNPC Foreign Quarter] NPC in completely the wrong place. -Bug #1792: Potions should show more effects -Bug #1793: Encumbrance while bartering -Bug #1794: Fortify attribute not affecting fatigue -Bug #1795: Too much magicka -Bug #1796: "Off by default" torch burning -Bug #1797: Fish too slow -Bug #1798: Rest until healed shouldn't show with full health and magicka -Bug #1802: Mark location moved -Bug #1804: stutter with recent builds -Bug #1810: attack gothens dremora doesnt agro the others. -Bug #1811: Regression: Crash Upon Loading New Cell -Bug #1812: Mod: "QuickChar" weird button placement -Bug #1815: Keys show value and weight, Vanilla Morrowind's keys dont. -Bug #1817: Persuasion results do not show using unpatched MW ESM -Bug #1818: Quest B3_ZainabBride moves to stage 47 upon loading save while Falura Llervu is following -Bug #1823: AI response to theft incorrect - only guards react, in vanilla everyone does. -Bug #1829: On-Target Spells Rendered Behind Water Surface Effects -Bug #1830: Galsa Gindu's house is on fire -Bug #1832: Fatal Error: OGRE Exception(2:InvalidParametersException) -Bug #1836: Attacked Guards open "fine/jail/resist"-dialogue after killing you -Bug #1840: Infinite recursion in ActionTeleport -Bug #1843: Escorted people change into player's cell after completion of escort stage -Bug #1845: Typing 'j' into 'Name' fields opens the journal -Bug #1846: Text pasted into the console still appears twice (Windows) -Bug #1847: "setfatigue 0" doesn't render NPC unconscious -Bug #1848: I can talk to unconscious actors -Bug #1866: Crash when player gets killed by a creature summoned by him -Bug #1868: Memory leaking when openmw window is minimized -Feature #47: Magic Effects -Feature #642: Control NPC mouth movement using current Say sound -Feature #939: Editor: Resources tables -Feature #961: AI Combat for magic (spells, potions and enchanted items) -Feature #1111: Collision script instructions (used e.g. by Lava) -Feature #1120: Command creature/humanoid magic effects -Feature #1121: Elemental shield magic effects -Feature #1122: Light magic effect -Feature #1139: AI: Friendly hits -Feature #1141: AI: combat party -Feature #1326: Editor: Add tooltips to all graphical buttons -Feature #1489: Magic effect Get/Mod/Set functions -Feature #1505: Difficulty slider -Feature #1538: Targeted scripts -Feature #1571: Allow creating custom markers on the local map -Feature #1615: Determine local variables from compiled scripts instead of the values in the script record -Feature #1616: Editor: Body part record verifier -Feature #1651: Editor: Improved keyboard navigation for scene toolbar -Feature #1666: Script blacklisting -Feature #1711: Including the Git revision number from the command line "--version" switch. -Feature #1721: NPC eye blinking -Feature #1740: Scene toolbar buttons for selecting which type of elements are rendered -Feature #1790: Mouse wheel scrolling for the journal -Feature #1850: NiBSPArrayController -Task #768: On windows, settings folder should be "OpenMW", not "openmw" -Task #908: Share keyframe data -Task #1716: Remove defunct option for building without FFmpeg - -0.31.0 - -Bug #245: Cloud direction and weather systems differ from Morrowind -Bug #275: Local Map does not always show objects that span multiple cells -Bug #538: Update CenterOnCell (COC) function behavior -Bug #618: Local and World Map Textures are sometimes Black -Bug #640: Water behaviour at night -Bug #668: OpenMW doesn't support non-latin paths on Windows -Bug #746: OpenMW doesn't check if the background music was already played -Bug #747: Door is stuck if cell is left before animation finishes -Bug #772: Disabled statics are visible on map -Bug #829: OpenMW uses up all available vram, when playing for extended time -Bug #869: Dead bodies don't collide with anything -Bug #894: Various character creation issues -Bug #897/#1369: opencs Segmentation Fault after "new" or "load" -Bug #899: Various jumping issues -Bug #952: Reflection effects are one frame delayed -Bug #993: Able to interact with world during Wait/Rest dialog -Bug #995: Dropped items can be placed inside the wall -Bug #1008: Corpses always face up upon reentering the cell -Bug #1035: Random colour patterns appearing in automap -Bug #1037: Footstep volume issues -Bug #1047: Creation of wrong links in dialogue window -Bug #1129: Summoned creature time life duration seems infinite -Bug #1134: Crimes can be committed against hostile NPCs -Bug #1136: Creature run speed formula is incorrect -Bug #1150: Weakness to Fire doesn't apply to Fire Damage in the same spell -Bug #1155: NPCs killing each other -Bug #1166: Bittercup script still does not work -Bug #1178: .bsa file names are case sensitive. -Bug #1179: Crash after trying to load game after being killed -Bug #1180: Changing footstep sound location -Bug #1196: Jumping not disabled when showing messageboxes -Bug #1202: "strange" keys are not shown in binding menu, and are not saved either, but works -Bug #1216: Broken dialog topics in russian Morrowind -Bug #1217: Container content changes based on the current position of the mouse -Bug #1234: Loading/saving issues with dynamic records -Bug #1277: Text pasted into the console appears twice -Bug #1284: Crash on New Game -Bug #1303: It's possible to skip the chargen -Bug #1304: Slaughterfish should not detect the player unless the player is in the water -Bug #1311: Editor: deleting Record Filter line does not reset the filter -Bug #1324: ERROR: ESM Error: String table overflow when loading Animated Morrowind.esp -Bug #1328: Editor: Bogus Filter created when dragging multiple records to filter bar of non-applicable table -Bug #1331: Walking/running sound persist after killing NPC`s that are walking/running. -Bug #1334: Previously equipped items not shown as unequipped after attempting to sell them. -Bug #1335: Actors ignore vertical axis when deciding to attack -Bug #1338: Unknown toggle option for shadows -Bug #1339: "Ashlands Region" is visible when beginning new game during "Loading Area" process -Bug #1340: Guards prompt Player with punishment options after resisting arrest with another guard. -Bug #1348: Regression: Bug #1098 has returned with a vengeance -Bug #1349: [TR] TR_Data mesh tr_ex_imp_gatejamb01 cannot be activated -Bug #1352: Disabling an ESX file does not disable dependent ESX files -Bug #1355: CppCat Checks OpenMW -Bug #1356: Incorrect voice type filtering for sleep interrupts -Bug #1357: Restarting the game clears saves -Bug #1360: Seyda Neen silk rider dialog problem -Bug #1361: Some lights don't work -Bug #1364: It is difficult to bind "Mouse 1" to an action in the options menu -Bug #1370: Animation compilation mod does not work properly -Bug #1371: SL_Pick01.nif from third party fails to load in openmw, but works in Vanilla -Bug #1373: When stealing in front of Sellus Gravius cannot exit the dialog -Bug #1378: Installs to /usr/local are not working -Bug #1380: Loading a save file fail if one of the content files is disabled -Bug #1382: "getHExact() size mismatch" crash on loading official plugin "Siege at Firemoth.esp" -Bug #1386: Arkngthand door will not open -Bug #1388: Segfault when modifying View Distance in Menu options -Bug #1389: Crash when loading a save after dying -Bug #1390: Apostrophe characters not displayed [French version] -Bug #1391: Custom made icon background texture for magical weapons and stuff isn't scaled properly on GUI. -Bug #1393: Coin icon during the level up dialogue are off of the background -Bug #1394: Alt+F4 doesn't work on Win version -Bug #1395: Changing rings switches only the last one put on -Bug #1396: Pauldron parts aren't showing when the robe is equipped -Bug #1402: Dialogue of some shrines have wrong button orientation -Bug #1403: Items are floating in the air when they're dropped onto dead bodies. -Bug #1404: Forearms are not rendered on Argonian females -Bug #1407: Alchemy allows making potions from two of the same item -Bug #1408: "Max sale" button gives you all the items AND all the trader's gold -Bug #1409: Rest "Until Healed" broken for characters with stunted magicka. -Bug #1412: Empty travel window opens while playing through start game -Bug #1413: Save game ignores missing writing permission -Bug #1414: The Underground 2 ESM Error -Bug #1416: Not all splash screens in the Splash directory are used -Bug #1417: Loading saved game does not terminate -Bug #1419: Skyrim: Home of the Nords error -Bug #1422: ClearInfoActor -Bug #1423: ForceGreeting closes existing dialogue windows -Bug #1425: Cannot load save game -Bug #1426: Read skill books aren't stored in savegame -Bug #1427: Useless items can be set under hotkeys -Bug #1429: Text variables in journal -Bug #1432: When attacking friendly NPC, the crime is reported and bounty is raised after each swing -Bug #1435: Stealing priceless items is without punishment -Bug #1437: Door marker at Jobasha's Rare Books is spawning PC in the air -Bug #1440: Topic selection menu should be wider -Bug #1441: Dropping items on the rug makes them inaccessible -Bug #1442: When dropping and taking some looted items, bystanders consider that as a crime -Bug #1444: Arrows and bolts are not dropped where the cursor points -Bug #1445: Security trainers offering acrobatics instead -Bug #1447: Character dash not displayed, French edition -Bug #1448: When the player is killed by the guard while having a bounty on his head, the guard dialogue opens over and over instead of loading dialogue -Bug #1454: Script error in SkipTutorial -Bug #1456: Bad lighting when using certain Morrowind.ini generated by MGE -Bug #1457: Heart of Lorkan comes after you when attacking it -Bug #1458: Modified Keybindings are not remembered -Bug #1459: Dura Gra-Bol doesn't respond to PC attack -Bug #1462: Interior cells not loaded with Morrowind Patch active -Bug #1469: Item tooltip should show the base value, not real value -Bug #1477: Death count is not stored in savegame -Bug #1478: AiActivate does not trigger activate scripts -Bug #1481: Weapon not rendered when partially submerged in water -Bug #1483: Enemies are attacking even while dying -Bug #1486: ESM Error: Don't know what to do with INFO -Bug #1490: Arrows shot at PC can end up in inventory -Bug #1492: Monsters respawn on top of one another -Bug #1493: Dialogue box opens with follower NPC even if NPC is dead -Bug #1494: Paralysed cliffracers remain airbourne -Bug #1495: Dialogue box opens with follower NPC even the game is paused -Bug #1496: GUI messages are not cleared when loading another saved game -Bug #1499: Underwater sound sometimes plays when transitioning from interior. -Bug #1500: Targetted spells and water. -Bug #1502: Console error message on info refusal -Bug #1507: Bloodmoon MQ The Ritual of Beasts: Can't remove the arrow -Bug #1508: Bloodmoon: Fort Frostmoth, cant talk with Carnius Magius -Bug #1516: PositionCell doesn't move actors to current cell -Bug #1518: ForceGreeting broken for explicit references -Bug #1522: Crash after attempting to play non-music file -Bug #1523: World map empty after loading interior save -Bug #1524: Arrows in waiting/resting dialog act like minimum and maximum buttons -Bug #1525: Werewolf: Killed NPC's don't fill werewolfs hunger for blood -Bug #1527: Werewolf: Detect life detects wrong type of actor -Bug #1529: OpenMW crash during "the shrine of the dead" mission (tribunal) -Bug #1530: Selected text in the console has the same color as the background -Bug #1539: Barilzar's Mazed Band: Tribunal -Bug #1542: Looping taunts from NPC`s after death: Tribunal -Bug #1543: OpenCS crash when using drag&drop in script editor -Bug #1547: Bamz-Amschend: Centurion Archers combat problem -Bug #1548: The Missing Hand: Tribunal -Bug #1549: The Mad God: Tribunal, Dome of Serlyn -Bug #1557: A bounty is calculated from actual item cost -Bug #1562: Invisible terrain on top of Red Mountain -Bug #1564: Cave of the hidden music: Bloodmoon -Bug #1567: Editor: Deleting of referenceables does not work -Bug #1568: Picking up a stack of items and holding the enter key and moving your mouse around paints a bunch of garbage on screen. -Bug #1574: Solstheim: Drauger cant inflict damage on player -Bug #1578: Solstheim: Bonewolf running animation not working -Bug #1585: Particle effects on PC are stopped when paralyzed -Bug #1589: Tribunal: Crimson Plague quest does not update when Gedna Relvel is killed -Bug #1590: Failed to save game: compile error -Bug #1598: Segfault when making Drain/Fortify Skill spells -Bug #1599: Unable to switch to fullscreen -Bug #1613: Morrowind Rebirth duplicate objects / vanilla objects not removed -Bug #1618: Death notice fails to show up -Bug #1628: Alt+Tab Segfault -Feature #32: Periodic Cleanup/Refill -Feature #41: Precipitation and weather particles -Feature #568: Editor: Configuration setup -Feature #649: Editor: Threaded loading -Feature #930: Editor: Cell record saving -Feature #934: Editor: Body part table -Feature #935: Editor: Enchantment effect table -Feature #1162: Dialogue merging -Feature #1174: Saved Game: add missing creature state -Feature #1177: Saved Game: fog of war state -Feature #1312: Editor: Combat/Magic/Stealth values for creatures are not displayed -Feature #1314: Make NPCs and creatures fight each other -Feature #1315: Crime: Murder -Feature #1321: Sneak skill enhancements -Feature #1323: Handle restocking items -Feature #1332: Saved Game: levelled creatures -Feature #1347: modFactionReaction script instruction -Feature #1362: Animated main menu support -Feature #1433: Store walk/run toggle -Feature #1449: Use names instead of numbers for saved game files and folders -Feature #1453: Adding Delete button to the load menu -Feature #1460: Enable Journal screen while in dialogue -Feature #1480: Play Battle music when in combat -Feature #1501: Followers unable to fast travel with you -Feature #1520: Disposition and distance-based aggression/ShouldAttack -Feature #1595: Editor: Object rendering in cells -Task #940: Move license to locations where applicable -Task #1333: Remove cmake git tag reading -Task #1566: Editor: Object rendering refactoring - -0.30.0 - -Bug #416: Extreme shaking can occur during cell transitions while moving -Bug #1003: Province Cyrodiil: Ogre Exception in Stirk -Bug #1071: Crash when given a non-existent content file -Bug #1080: OpenMW allows resting/using a bed while in combat -Bug #1097: Wrong punishment for stealing in Census and Excise Office at the start of a new game -Bug #1098: Unlocked evidence chests should get locked after new evidence is put into them -Bug #1099: NPCs that you attacked still fight you after you went to jail/paid your fine -Bug #1100: Taking items from a corpse is considered stealing -Bug #1126: Some creatures can't get close enough to attack -Bug #1144: Killed creatures seem to die again each time player transitions indoors/outdoors -Bug #1181: loading a saved game does not reset the player control status -Bug #1185: Collision issues in Addamasartus -Bug #1187: Athyn Sarethi mission, rescuing varvur sarethi from the doesnt end the mission -Bug #1189: Crash when entering interior cell "Gnisis, Arvs-Drelen" -Bug #1191: Picking up papers without inventory in new game -Bug #1195: NPCs do not equip torches in certain interiors -Bug #1197: mouse wheel makes things scroll too fast -Bug #1200: door blocked by monsters -Bug #1201: item's magical charges are only refreshed when they are used -Bug #1203: Scribs do not defend themselves -Bug #1204: creatures life is not empty when they are dead -Bug #1205: armor experience does not progress when hits are taken -Bug #1206: blood particules always red. Undeads and mechanicals should have a different one. -Bug #1209: Tarhiel never falls -Bug #1210: journal adding script is ran again after having saved/loaded -Bug #1224: Names of custom classes are not properly handled in save games -Bug #1227: Editor: Fixed case handling for broken localised versions of Morrowind.esm -Bug #1235: Indoors walk stutter -Bug #1236: Aborting intro movie brings up the menu -Bug #1239: NPCs get stuck when walking past each other -Bug #1240: BTB - Settings 14.1 and Health Bar. -Bug #1241: BTB - Character and Khajiit Prejudice -Bug #1248: GUI Weapon icon is changed to hand-to-hand after save load -Bug #1254: Guild ranks do not show in dialogue -Bug #1255: When opening a container and selecting "Take All", the screen flashes blue -Bug #1260: Level Up menu doesn't show image when using a custom class -Bug #1265: Quit Menu Has Misaligned Buttons -Bug #1270: Active weapon icon is not updated when weapon is repaired -Bug #1271: NPC Stuck in hovering "Jumping" animation -Bug #1272: Crash when attempting to load Big City esm file. -Bug #1276: Editor: Dropping a region into the filter of a cell subview fails -Bug #1286: Dialogue topic list clips with window frame -Bug #1291: Saved game: store faction membership -Bug #1293: Pluginless Khajiit Head Pack by ashiraniir makes OpenMW close. -Bug #1294: Pasting in console adds text to end, not at cursor -Bug #1295: Conversation loop when asking about "specific place" in Vivec -Bug #1296: Caius doesn't leave at start of quest "Mehra Milo and the Lost Prophecies" -Bug #1297: Saved game: map markers -Bug #1302: ring_keley script causes vector::_M_range_check exception -Bug #1309: Bug on "You violated the law" dialog -Bug #1319: Creatures sometimes rendered incorrectly -Feature #50: Ranged Combat -Feature #58: Sneaking Skill -Feature #73: Crime and Punishment -Feature #135: Editor: OGRE integration -Feature #541: Editor: Dialogue Sub-Views -Feature #853: Editor: Rework User Settings -Feature #944: Editor: lighting modes -Feature #945: Editor: Camera navigation mode -Feature #953: Trader gold -Feature #1140: AI: summoned creatures -Feature #1142: AI follow: Run stance -Feature #1154: Not all NPCs get aggressive when one is attacked -Feature #1169: Terrain threading -Feature #1172: Loading screen and progress bars during saved/loading game -Feature #1173: Saved Game: include weather state -Feature #1207: Class creation form does not remember -Feature #1220: Editor: Preview Subview -Feature #1223: Saved Game: Local Variables -Feature #1229: Quicksave, quickload, autosave -Feature #1230: Deleting saves -Feature #1233: Bribe gold is placed into NPCs inventory -Feature #1252: Saved Game: quick key bindings -Feature #1273: Editor: Region Map context menu -Feature #1274: Editor: Region Map drag & drop -Feature #1275: Editor: Scene subview drop -Feature #1282: Non-faction member crime recognition. -Feature #1289: NPCs return to default position -Task #941: Remove unused cmake files - -0.29.0 - -Bug #556: Video soundtrack not played when music volume is set to zero -Bug #829: OpenMW uses up all available vram, when playing for extended time -Bug #848: Wrong amount of footsteps playing in 1st person -Bug #888: Ascended Sleepers have movement issues -Bug #892: Explicit references are allowed on all script functions -Bug #999: Graphic Herbalism (mod): sometimes doesn't activate properly -Bug #1009: Lake Fjalding AI related slowdown. -Bug #1041: Music playback issues on OS X >= 10.9 -Bug #1043: No message box when advancing skill "Speechcraft" while in dialog window -Bug #1060: Some message boxes are cut off at the bottom -Bug #1062: Bittercup script does not work ('end' variable) -Bug #1074: Inventory paperdoll obscures armour rating -Bug #1077: Message after killing an essential NPC disappears too fast -Bug #1078: "Clutterbane" shows empty charge bar -Bug #1083: UndoWerewolf fails -Bug #1088: Better Clothes Bloodmoon Plus 1.5 by Spirited Treasure pants are not rendered -Bug #1090: Start scripts fail when going to a non-predefined cell -Bug #1091: Crash: Assertion `!q.isNaN() && "Invalid orientation supplied as parameter"' failed. -Bug #1093: Weapons of aggressive NPCs are invisible after you exit and re-enter interior -Bug #1105: Magicka is depleted when using uncastable spells -Bug #1106: Creatures should be able to run -Bug #1107: TR cliffs have way too huge collision boxes in OpenMW -Bug #1109: Cleaning True Light and Darkness with Tes3cmd makes Addamasartus , Zenarbael and Yasamsi flooded. -Bug #1114: Bad output for desktop-file-validate on openmw.desktop (and opencs.desktop) -Bug #1115: Memory leak when spying on Fargoth -Bug #1137: Script execution fails (drenSlaveOwners script) -Bug #1143: Mehra Milo quest (vivec informants) is broken -Bug #1145: Issues with moving gold between inventory and containers -Bug #1146: Issues with picking up stacks of gold -Bug #1147: Dwemer Crossbows are held incorrectly -Bug #1158: Armor rating should always stay below inventory mannequin -Bug #1159: Quick keys can be set during character generation -Bug #1160: Crash on equip lockpick when -Bug #1167: Editor: Referenceables are not correctly loaded when dealing with more than one content file -Bug #1184: Game Save: overwriting an existing save does not actually overwrites the file -Feature #30: Loading/Saving (still missing a few parts) -Feature #101: AI Package: Activate -Feature #103: AI Package: Follow, FollowCell -Feature #138: Editor: Drag & Drop -Feature #428: Player death -Feature #505: Editor: Record Cloning -Feature #701: Levelled creatures -Feature #708: Improved Local Variable handling -Feature #709: Editor: Script verifier -Feature #764: Missing journal backend features -Feature #777: Creature weapons/shields -Feature #789: Editor: Referenceable record verifier -Feature #924: Load/Save GUI (still missing loading screen and progress bars) -Feature #946: Knockdown -Feature #947: Decrease fatigue when running, swimming and attacking -Feature #956: Melee Combat: Blocking -Feature #957: Area magic -Feature #960: Combat/AI combat for creatures -Feature #962: Combat-Related AI instructions -Feature #1075: Damage/Restore skill/attribute magic effects -Feature #1076: Soultrap magic effect -Feature #1081: Disease contraction -Feature #1086: Blood particles -Feature #1092: Interrupt resting -Feature #1101: Inventory equip scripts -Feature #1116: Version/Build number in Launcher window -Feature #1119: Resistance/weakness to normal weapons magic effect -Feature #1123: Slow Fall magic effect -Feature #1130: Auto-calculate spells -Feature #1164: Editor: Case-insensitive sorting in tables - -0.28.0 - -Bug #399: Inventory changes are not visible immediately -Bug #417: Apply weather instantly when teleporting -Bug #566: Global Map position marker not updated for interior cells -Bug #712: Looting corpse delay -Bug #716: Problem with the "Vurt's Ascadian Isles Mod" mod -Bug #805: Two TR meshes appear black (v0.24RC) -Bug #841: Third-person activation distance taken from camera rather than head -Bug #845: NPCs hold torches during the day -Bug #855: Vvardenfell Visages Volume I some hairs don´t appear since 0,24 -Bug #856: Maormer race by Mac Kom - The heads are way up -Bug #864: Walk locks during loading in 3rd person -Bug #871: active weapon/magic item icon is not immediately made blank if item is removed during dialog -Bug #882: Hircine's Ring doesn't always work -Bug #909: [Tamriel Rebuilt] crashes in Akamora -Bug #922: Launcher writing merged openmw.cfg files -Bug #943: Random magnitude should be calculated per effect -Bug #948: Negative fatigue level should be allowed -Bug #949: Particles in world space -Bug #950: Hard crash on x64 Linux running --new-game (on startup) -Bug #951: setMagicka and setFatigue have no effect -Bug #954: Problem with equipping inventory items when using a keyboard shortcut -Bug #955: Issues with equipping torches -Bug #966: Shield is visible when casting spell -Bug #967: Game crashes when equipping silver candlestick -Bug #970: Segmentation fault when starting at Bal Isra -Bug #977: Pressing down key in console doesn't go forward in history -Bug #979: Tooltip disappears when changing inventory -Bug #980: Barter: item category is remembered, but not shown -Bug #981: Mod: replacing model has wrong position/orientation -Bug #982: Launcher: Addon unchecking is not saved -Bug #983: Fix controllers to affect objects attached to the base node -Bug #985: Player can talk to NPCs who are in combat -Bug #989: OpenMW crashes when trying to include mod with capital .ESP -Bug #991: Merchants equip items with harmful constant effect enchantments -Bug #994: Don't cap skills/attributes when set via console -Bug #998: Setting the max health should also set the current health -Bug #1005: Torches are visible when casting spells and during hand to hand combat. -Bug #1006: Many NPCs have 0 skill -Bug #1007: Console fills up with text -Bug #1013: Player randomly loses health or dies -Bug #1014: Persuasion window is not centered in maximized window -Bug #1015: Player status window scroll state resets on status change -Bug #1016: Notification window not big enough for all skill level ups -Bug #1020: Saved window positions are not rescaled appropriately on resolution change -Bug #1022: Messages stuck permanently on screen when they pile up -Bug #1023: Journals doesn't open -Bug #1026: Game loses track of torch usage. -Bug #1028: Crash on pickup of jug in Unexplored Shipwreck, Upper level -Bug #1029: Quick keys menu: Select compatible replacement when tool used up -Bug #1042: TES3 header data wrong encoding -Bug #1045: OS X: deployed OpenCS won't launch -Bug #1046: All damaged weaponry is worth 1 gold -Bug #1048: Links in "locked" dialogue are still clickable -Bug #1052: Using color codes when naming your character actually changes the name's color -Bug #1054: Spell effects not visible in front of water -Bug #1055: Power-Spell animation starts even though you already casted it that day -Bug #1059: Cure disease potion removes all effects from player, even your race bonus and race ability -Bug #1063: Crash upon checking out game start ship area in Seyda Neen -Bug #1064: openmw binaries link to unnecessary libraries -Bug #1065: Landing from a high place in water still causes fall damage -Bug #1072: Drawing weapon increases torch brightness -Bug #1073: Merchants sell stacks of gold -Feature #43: Visuals for Magic Effects -Feature #51: Ranged Magic -Feature #52: Touch Range Magic -Feature #53: Self Range Magic -Feature #54: Spell Casting -Feature #70: Vampirism -Feature #100: Combat AI -Feature #171: Implement NIF record NiFlipController -Feature #410: Window to restore enchanted item charge -Feature #647: Enchanted item glow -Feature #723: Invisibility/Chameleon magic effects -Feature #737: Resist Magicka magic effect -Feature #758: GetLOS -Feature #926: Editor: Info-Record tables -Feature #958: Material controllers -Feature #959: Terrain bump, specular, & parallax mapping -Feature #990: Request: unlock mouse when in any menu -Feature #1018: Do not allow view mode switching while performing an action -Feature #1027: Vertex morph animation (NiGeomMorpherController) -Feature #1031: Handle NiBillboardNode -Feature #1051: Implement NIF texture slot DarkTexture -Task #873: Unify OGRE initialisation - -0.27.0 - -Bug #597: Assertion `dialogue->mId == id' failed in esmstore.cpp -Bug #794: incorrect display of decimal numbers -Bug #840: First-person sneaking camera height -Bug #887: Ambient sounds playing while paused -Bug #902: Problems with Polish character encoding -Bug #907: Entering third person using the mousewheel is possible even if it's impossible using the key -Bug #910: Some CDs not working correctly with Unshield installer -Bug #917: Quick character creation plugin does not work -Bug #918: Fatigue does not refill -Bug #919: The PC falls dead in Beshara - OpenMW nightly Win64 (708CDE2) -Feature #57: Acrobatics Skill -Feature #462: Editor: Start Dialogue -Feature #546: Modify ESX selector to handle new content file scheme -Feature #588: Editor: Adjust name/path of edited content files -Feature #644: Editor: Save -Feature #710: Editor: Configure script compiler context -Feature #790: God Mode -Feature #881: Editor: Allow only one instance of OpenCS -Feature #889: Editor: Record filtering -Feature #895: Extinguish torches -Feature #898: Breath meter enhancements -Feature #901: Editor: Default record filter -Feature #913: Merge --master and --plugin switches - -0.26.0 - -Bug #274: Inconsistencies in the terrain -Bug #557: Already-dead NPCs do not equip clothing/items. -Bug #592: Window resizing -Bug #612: [Tamriel Rebuilt] Missing terrain (South of Tel Oren) -Bug #664: Heart of lorkhan acts like a dead body (container) -Bug #767: Wonky ramp physics & water -Bug #780: Swimming out of water -Bug #792: Wrong ground alignment on actors when no clipping -Bug #796: Opening and closing door sound issue -Bug #797: No clipping hinders opening and closing of doors -Bug #799: sliders in enchanting window -Bug #838: Pressing key during startup procedure freezes the game -Bug #839: Combat/magic stances during character creation -Bug #843: [Tribunal] Dark Brotherhood assassin appears without equipment -Bug #844: Resting "until healed" option given even with full stats -Bug #846: Equipped torches are invisible. -Bug #847: Incorrect formula for autocalculated NPC initial health -Bug #850: Shealt weapon sound plays when leaving magic-ready stance -Bug #852: Some boots do not produce footstep sounds -Bug #860: FPS bar misalignment -Bug #861: Unable to print screen -Bug #863: No sneaking and jumping at the same time -Bug #866: Empty variables in [Movies] section of Morrowind.ini gets imported into OpenMW.cfg as blank fallback option and crashes game on start. -Bug #867: Dancing girls in "Suran, Desele's House of Earthly Delights" don't dance. -Bug #868: Idle animations are repeated -Bug #874: Underwater swimming close to the ground is jerky -Bug #875: Animation problem while swimming on the surface and looking up -Bug #876: Always a starting upper case letter in the inventory -Bug #878: Active spell effects don't update the layout properly when ended -Bug #891: Cell 24,-12 (Tamriel Rebuilt) crashes on load -Bug #896: New game sound issue -Feature #49: Melee Combat -Feature #71: Lycanthropy -Feature #393: Initialise MWMechanics::AiSequence from ESM::AIPackageList -Feature #622: Multiple positions for inventory window -Feature #627: Drowning -Feature #786: Allow the 'Activate' key to close the countdialog window -Feature #798: Morrowind installation via Launcher (Linux/Max OS only) -Feature #851: First/Third person transitions with mouse wheel -Task #689: change PhysicActor::enableCollisions -Task #707: Reorganise Compiler - -0.25.0 - -Bug #411: Launcher crash on OS X < 10.8 -Bug #604: Terrible performance drop in the Census and Excise Office. -Bug #676: Start Scripts fail to load -Bug #677: OpenMW does not accept script names with - -Bug #766: Extra space in front of topic links -Bug #793: AIWander Isn't Being Passed The Repeat Parameter -Bug #795: Sound playing with drawn weapon and crossing cell-border -Bug #800: can't select weapon for enchantment -Bug #801: Player can move while over-encumbered -Bug #802: Dead Keys not working -Bug #808: mouse capture -Bug #809: ini Importer does not work without an existing cfg file -Bug #812: Launcher will run OpenMW with no ESM or ESP selected -Bug #813: OpenMW defaults to Morrowind.ESM with no ESM or ESP selected -Bug #817: Dead NPCs and Creatures still have collision boxes -Bug #820: Incorrect sorting of answers (Dialogue) -Bug #826: mwinimport dumps core when given an unknown parameter -Bug #833: getting stuck in door -Bug #835: Journals/books not showing up properly. -Feature #38: SoundGen -Feature #105: AI Package: Wander -Feature #230: 64-bit compatibility for OS X -Feature #263: Hardware mouse cursors -Feature #449: Allow mouse outside of window while paused -Feature #736: First person animations -Feature #750: Using mouse wheel in third person mode -Feature #822: Autorepeat for slider buttons - -0.24.0 - -Bug #284: Book's text misalignment -Bug #445: Camera able to get slightly below floor / terrain -Bug #582: Seam issue in Red Mountain -Bug #632: Journal Next Button shows white square -Bug #653: IndexedStore ignores index -Bug #694: Parser does not recognize float values starting with . -Bug #699: Resource handling broken with Ogre 1.9 trunk -Bug #718: components/esm/loadcell is using the mwworld subsystem -Bug #729: Levelled item list tries to add nonexistent item -Bug #730: Arrow buttons in the settings menu do not work. -Bug #732: Erroneous behavior when binding keys -Bug #733: Unclickable dialogue topic -Bug #734: Book empty line problem -Bug #738: OnDeath only works with implicit references -Bug #740: Script compiler fails on scripts with special names -Bug #742: Wait while no clipping -Bug #743: Problem with changeweather console command -Bug #744: No wait dialogue after starting a new game -Bug #748: Player is not able to unselect objects with the console -Bug #751: AddItem should only spawn a message box when called from dialogue -Bug #752: The enter button has several functions in trade and looting that is not impelemted. -Bug #753: Fargoth's Ring Quest Strange Behavior -Bug #755: Launcher writes duplicate lines into settings.cfg -Bug #759: Second quest in mages guild does not work -Bug #763: Enchantment cast cost is wrong -Bug #770: The "Take" and "Close" buttons in the scroll GUI are stretched incorrectly -Bug #773: AIWander Isn't Being Passed The Correct idle Values -Bug #778: The journal can be opened at the start of a new game -Bug #779: Divayth Fyr starts as dead -Bug #787: "Batch count" on detailed FPS counter gets cut-off -Bug #788: chargen scroll layout does not match vanilla -Feature #60: Atlethics Skill -Feature #65: Security Skill -Feature #74: Interaction with non-load-doors -Feature #98: Render Weapon and Shield -Feature #102: AI Package: Escort, EscortCell -Feature #182: Advanced Journal GUI -Feature #288: Trading enhancements -Feature #405: Integrate "new game" into the menu -Feature #537: Highlight dialogue topic links -Feature #658: Rotate, RotateWorld script instructions and local rotations -Feature #690: Animation Layering -Feature #722: Night Eye/Blind magic effects -Feature #735: Move, MoveWorld script instructions. -Feature #760: Non-removable corpses - -0.23.0 - -Bug #522: Player collides with placeable items -Bug #553: Open/Close sounds played when accessing main menu w/ Journal Open -Bug #561: Tooltip word wrapping delay -Bug #578: Bribing works incorrectly -Bug #601: PositionCell fails on negative coordinates -Bug #606: Some NPCs hairs not rendered with Better Heads addon -Bug #609: Bad rendering of bone boots -Bug #613: Messagebox causing assert to fail -Bug #631: Segfault on shutdown -Bug #634: Exception when talking to Calvus Horatius in Mournhold, royal palace courtyard -Bug #635: Scale NPCs depending on race -Bug #643: Dialogue Race select function is inverted -Bug #646: Twohanded weapons don't work properly -Bug #654: Crash when dropping objects without a collision shape -Bug #655/656: Objects that were disabled or deleted (but not both) were added to the scene when re-entering a cell -Bug #660: "g" in "change" cut off in Race Menu -Bug #661: Arrille sells me the key to his upstairs room -Bug #662: Day counter starts at 2 instead of 1 -Bug #663: Cannot select "come unprepared" topic in dialog with Dagoth Ur -Bug #665: Pickpocket -> "Grab all" grabs all NPC inventory, even not listed in container window. -Bug #666: Looking up/down problem -Bug #667: Active effects border visible during loading -Bug #669: incorrect player position at new game start -Bug #670: race selection menu: sex, face and hair left button not totally clickable -Bug #671: new game: player is naked -Bug #674: buying or selling items doesn't change amount of gold -Bug #675: fatigue is not set to its maximum when starting a new game -Bug #678: Wrong rotation order causes RefData's rotation to be stored incorrectly -Bug #680: different gold coins in Tel Mara -Bug #682: Race menu ignores playable flag for some hairs and faces -Bug #685: Script compiler does not accept ":" after a function name -Bug #688: dispose corpse makes cross-hair to disappear -Bug #691: Auto equipping ignores equipment conditions -Bug #692: OpenMW doesnt load "loose file" texture packs that places resources directly in data folder -Bug #696: Draugr incorrect head offset -Bug #697: Sail transparency issue -Bug #700: "On the rocks" mod does not load its UV coordinates correctly. -Bug #702: Some race mods don't work -Bug #711: Crash during character creation -Bug #715: Growing Tauryon -Bug #725: Auto calculate stats -Bug #728: Failure to open container and talk dialogue -Bug #731: Crash with Mush-Mere's "background" topic -Feature #55/657: Item Repairing -Feature #62/87: Enchanting -Feature #99: Pathfinding -Feature #104: AI Package: Travel -Feature #129: Levelled items -Feature #204: Texture animations -Feature #239: Fallback-Settings -Feature #535: Console object selection improvements -Feature #629: Add levelup description in levelup layout dialog -Feature #630: Optional format subrecord in (tes3) header -Feature #641: Armor rating -Feature #645: OnDeath script function -Feature #683: Companion item UI -Feature #698: Basic Particles -Task #648: Split up components/esm/loadlocks -Task #695: mwgui cleanup - -0.22.0 - -Bug #311: Potential infinite recursion in script compiler -Bug #355: Keyboard repeat rate (in Xorg) are left disabled after game exit. -Bug #382: Weird effect in 3rd person on water -Bug #387: Always use detailed shape for physics raycasts -Bug #420: Potion/ingredient effects do not stack -Bug #429: Parts of dwemer door not picked up correctly for activation/tooltips -Bug #434/Bug #605: Object movement between cells not properly implemented -Bug #502: Duplicate player collision model at origin -Bug #509: Dialogue topic list shifts inappropriately -Bug #513: Sliding stairs -Bug #515: Launcher does not support non-latin strings -Bug #525: Race selection preview camera wrong position -Bug #526: Attributes / skills should not go below zero -Bug #529: Class and Birthsign menus options should be preselected -Bug #530: Lock window button graphic missing -Bug #532: Missing map menu graphics -Bug #545: ESX selector does not list ESM files properly -Bug #547: Global variables of type short are read incorrectly -Bug #550: Invisible meshes collision and tooltip -Bug #551: Performance drop when loading multiple ESM files -Bug #552: Don't list CG in options if it is not available -Bug #555: Character creation windows "OK" button broken -Bug #558: Segmentation fault when Alt-tabbing with console opened -Bug #559: Dialog window should not be available before character creation is finished -Bug #560: Tooltip borders should be stretched -Bug #562: Sound should not be played when an object cannot be picked up -Bug #565: Water animation speed + timescale -Bug #572: Better Bodies' textures don't work -Bug #573: OpenMW doesn't load if TR_Mainland.esm is enabled (Tamriel Rebuilt mod) -Bug #574: Moving left/right should not cancel auto-run -Bug #575: Crash entering the Chamber of Song -Bug #576: Missing includes -Bug #577: Left Gloves Addon causes ESMReader exception -Bug #579: Unable to open container "Kvama Egg Sack" -Bug #581: Mimicking vanilla Morrowind water -Bug #583: Gender not recognized -Bug #586: Wrong char gen behaviour -Bug #587: "End" script statements with spaces don't work -Bug #589: Closing message boxes by pressing the activation key -Bug #590: Ugly Dagoth Ur rendering -Bug #591: Race selection issues -Bug #593: Persuasion response should be random -Bug #595: Footless guard -Bug #599: Waterfalls are invisible from a certain distance -Bug #600: Waterfalls rendered incorrectly, cut off by water -Bug #607: New beast bodies mod crashes -Bug #608: Crash in cell "Mournhold, Royal Palace" -Bug #611: OpenMW doesn't find some of textures used in Tamriel Rebuilt -Bug #613: Messagebox causing assert to fail -Bug #615: Meshes invisible from above water -Bug #617: Potion effects should be hidden until discovered -Bug #619: certain moss hanging from tree has rendering bug -Bug #621: Batching bloodmoon's trees -Bug #623: NiMaterialProperty alpha unhandled -Bug #628: Launcher in latest master crashes the game -Bug #633: Crash on startup: Better Heads -Bug #636: Incorrect Char Gen Menu Behavior -Feature #29: Allow ESPs and multiple ESMs -Feature #94: Finish class selection-dialogue -Feature #149: Texture Alphas -Feature #237: Run Morrowind-ini importer from launcher -Feature #286: Update Active Spell Icons -Feature #334: Swimming animation -Feature #335: Walking animation -Feature #360: Proper collision shapes for NPCs and creatures -Feature #367: Lights that behave more like original morrowind implementation -Feature #477: Special local scripting variables -Feature #528: Message boxes should close when enter is pressed under certain conditions. -Feature #543: Add bsa files to the settings imported by the ini importer -Feature #594: coordinate space and utility functions -Feature #625: Zoom in vanity mode -Task #464: Refactor launcher ESX selector into a re-usable component -Task #624: Unified implementation of type-variable sub-records - -0.21.0 - -Bug #253: Dialogs don't work for Russian version of Morrowind -Bug #267: Activating creatures without dialogue can still activate the dialogue GUI -Bug #354: True flickering lights -Bug #386: The main menu's first entry is wrong (in french) -Bug #479: Adding the spell "Ash Woe Blight" to the player causes strange attribute oscillations -Bug #495: Activation Range -Bug #497: Failed Disposition check doesn't stop a dialogue entry from being returned -Bug #498: Failing a disposition check shouldn't eliminate topics from the the list of those available -Bug #500: Disposition for most NPCs is 0/100 -Bug #501: Getdisposition command wrongly returns base disposition -Bug #506: Journal UI doesn't update anymore -Bug #507: EnableRestMenu is not a valid command - change it to EnableRest -Bug #508: Crash in Ald Daedroth Shrine -Bug #517: Wrong price calculation when untrading an item -Bug #521: MWGui::InventoryWindow creates a duplicate player actor at the origin -Bug #524: Beast races are able to wear shoes -Bug #527: Background music fails to play -Bug #533: The arch at Gnisis entrance is not displayed -Bug #534: Terrain gets its correct shape only some time after the cell is loaded -Bug #536: The same entry can be added multiple times to the journal -Bug #539: Race selection is broken -Bug #544: Terrain normal map corrupt when the map is rendered -Feature #39: Video Playback -Feature #151: ^-escape sequences in text output -Feature #392: Add AI related script functions -Feature #456: Determine required ini fallback values and adjust the ini importer accordingly -Feature #460: Experimental DirArchives improvements -Feature #540: Execute scripts of objects in containers/inventories in active cells -Task #401: Review GMST fixing -Task #453: Unify case smashing/folding -Task #512: Rewrite utf8 component - -0.20.0 - -Bug #366: Changing the player's race during character creation does not change the look of the player character -Bug #430: Teleporting and using loading doors linking within the same cell reloads the cell -Bug #437: Stop animations when paused -Bug #438: Time displays as "0 a.m." when it should be "12 a.m." -Bug #439: Text in "name" field of potion/spell creation window is persistent -Bug #440: Starting date at a new game is off by one day -Bug #442: Console window doesn't close properly sometimes -Bug #448: Do not break container window formatting when item names are very long -Bug #458: Topics sometimes not automatically added to known topic list -Bug #476: Auto-Moving allows player movement after using DisablePlayerControls -Bug #478: After sleeping in a bed the rest dialogue window opens automtically again -Bug #492: On creating potions the ingredients are removed twice -Feature #63: Mercantile skill -Feature #82: Persuasion Dialogue -Feature #219: Missing dialogue filters/functions -Feature #369: Add a FailedAction -Feature #377: Select head/hair on character creation -Feature #391: Dummy AI package classes -Feature #435: Global Map, 2nd Layer -Feature #450: Persuasion -Feature #457: Add more script instructions -Feature #474: update the global variable pcrace when the player's race is changed -Task #158: Move dynamically generated classes from Player class to World Class -Task #159: ESMStore rework and cleanup -Task #163: More Component Namespace Cleanup -Task #402: Move player data from MWWorld::Player to the player's NPC record -Task #446: Fix no namespace in BulletShapeLoader - -0.19.0 - -Bug #374: Character shakes in 3rd person mode near the origin -Bug #404: Gamma correct rendering -Bug #407: Shoes of St. Rilm do not work -Bug #408: Rugs has collision even if they are not supposed to -Bug #412: Birthsign menu sorted incorrectly -Bug #413: Resolutions presented multiple times in launcher -Bug #414: launcher.cfg file stored in wrong directory -Bug #415: Wrong esm order in openmw.cfg -Bug #418: Sound listener position updates incorrectly -Bug #423: wrong usage of "Version" entry in openmw.desktop -Bug #426: Do not use hardcoded splash images -Bug #431: Don't use markers for raycast -Bug #432: Crash after picking up items from an NPC -Feature #21/#95: Sleeping/resting -Feature #61: Alchemy Skill -Feature #68: Death -Feature #69/#86: Spell Creation -Feature #72/#84: Travel -Feature #76: Global Map, 1st Layer -Feature #120: Trainer Window -Feature #152: Skill Increase from Skill Books -Feature #160: Record Saving -Task #400: Review GMST access - -0.18.0 - -Bug #310: Button of the "preferences menu" are too small -Bug #361: Hand-to-hand skill is always 100 -Bug #365: NPC and creature animation is jerky; Characters float around when they are not supposed to -Bug #372: playSound3D uses original coordinates instead of current coordinates. -Bug #373: Static OGRE build faulty -Bug #375: Alt-tab toggle view -Bug #376: Screenshots are disable -Bug #378: Exception when drinking self-made potions -Bug #380: Cloth visibility problem -Bug #384: Weird character on doors tooltip. -Bug #398: Some objects do not collide in MW, but do so in OpenMW -Feature #22: Implement level-up -Feature #36: Hide Marker -Feature #88: Hotkey Window -Feature #91: Level-Up Dialogue -Feature #118: Keyboard and Mouse-Button bindings -Feature #119: Spell Buying Window -Feature #133: Handle resources across multiple data directories -Feature #134: Generate a suitable default-value for --data-local -Feature #292: Object Movement/Creation Script Instructions -Feature #340: AIPackage data structures -Feature #356: Ingredients use -Feature #358: Input system rewrite -Feature #370: Target handling in actions -Feature #379: Door markers on the local map -Feature #389: AI framework -Feature #395: Using keys to open doors / containers -Feature #396: Loading screens -Feature #397: Inventory avatar image and race selection head preview -Task #339: Move sounds into Action - -0.17.0 - -Bug #225: Valgrind reports about 40MB of leaked memory -Bug #241: Some physics meshes still don't match -Bug #248: Some textures are too dark -Bug #300: Dependency on proprietary CG toolkit -Bug #302: Some objects don't collide although they should -Bug #308: Freeze in Balmora, Meldor: Armorer -Bug #313: openmw without a ~/.config/openmw folder segfault. -Bug #317: adding non-existing spell via console locks game -Bug #318: Wrong character normals -Bug #341: Building with Ogre Debug libraries does not use debug version of plugins -Bug #347: Crash when running openmw with --start="XYZ" -Bug #353: FindMyGUI.cmake breaks path on Windows -Bug #359: WindowManager throws exception at destruction -Bug #364: Laggy input on OS X due to bug in Ogre's event pump implementation -Feature #33: Allow objects to cross cell-borders -Feature #59: Dropping Items (replaced stopgap implementation with a proper one) -Feature #93: Main Menu -Feature #96/329/330/331/332/333: Player Control -Feature #180: Object rotation and scaling. -Feature #272: Incorrect NIF material sharing -Feature #314: Potion usage -Feature #324: Skill Gain -Feature #342: Drain/fortify dynamic stats/attributes magic effects -Feature #350: Allow console only script instructions -Feature #352: Run scripts in console on startup -Task #107: Refactor mw*-subsystems -Task #325: Make CreatureStats into a class -Task #345: Use Ogre's animation system -Task #351: Rewrite Action class to support automatic sound playing - -0.16.0 - -Bug #250: OpenMW launcher erratic behaviour -Bug #270: Crash because of underwater effect on OS X -Bug #277: Auto-equipping in some cells not working -Bug #294: Container GUI ignores disabled inventory menu -Bug #297: Stats review dialog shows all skills and attribute values as 0 -Bug #298: MechanicsManager::buildPlayer does not remove previous bonuses -Bug #299: Crash in World::disable -Bug #306: Non-existent ~/.config/openmw "crash" the launcher. -Bug #307: False "Data Files" location make the launcher "crash" -Feature #81: Spell Window -Feature #85: Alchemy Window -Feature #181: Support for x.y script syntax -Feature #242: Weapon and Spell icons -Feature #254: Ingame settings window -Feature #293: Allow "stacking" game modes -Feature #295: Class creation dialog tooltips -Feature #296: Clicking on the HUD elements should show/hide the respective window -Feature #301: Direction after using a Teleport Door -Feature #303: Allow object selection in the console -Feature #305: Allow the use of = as a synonym for == -Feature #312: Compensation for slow object access in poorly written Morrowind.esm scripts -Task #176: Restructure enabling/disabling of MW-references -Task #283: Integrate ogre.cfg file in settings file -Task #290: Auto-Close MW-reference related GUI windows - -0.15.0 - -Bug #5: Physics reimplementation (fixes various issues) -Bug #258: Resizing arrow's background is not transparent -Bug #268: Widening the stats window in X direction causes layout problems -Bug #269: Topic pane in dialgoue window is too small for some longer topics -Bug #271: Dialog choices are sorted incorrectly -Bug #281: The single quote character is not rendered on dialog windows -Bug #285: Terrain not handled properly in cells that are not predefined -Bug #289: Dialogue filter isn't doing case smashing/folding for item IDs -Feature #15: Collision with Terrain -Feature #17: Inventory-, Container- and Trade-Windows -Feature #44: Floating Labels above Focussed Objects -Feature #80: Tooltips -Feature #83: Barter Dialogue -Feature #90: Book and Scroll Windows -Feature #156: Item Stacking in Containers -Feature #213: Pulsating lights -Feature #218: Feather & Burden -Feature #256: Implement magic effect bookkeeping -Feature #259: Add missing information to Stats window -Feature #260: Correct case for dialogue topics -Feature #280: GUI texture atlasing -Feature #291: Ability to use GMST strings from GUI layout files -Task #255: Make MWWorld::Environment into a singleton - -0.14.0 - -Bug #1: Meshes rendered with wrong orientation -Bug #6/Task #220: Picking up small objects doesn't always work -Bug #127: tcg doesn't work -Bug #178: Compablity problems with Ogre 1.8.0 RC 1 -Bug #211: Wireframe mode (toggleWireframe command) should not apply to Console & other UI -Bug #227: Terrain crashes when moving away from predefined cells -Bug #229: On OS X Launcher cannot launch game if path to binary contains spaces -Bug #235: TGA texture loading problem -Bug #246: wireframe mode does not work in water -Feature #8/#232: Water Rendering -Feature #13: Terrain Rendering -Feature #37: Render Path Grid -Feature #66: Factions -Feature #77: Local Map -Feature #78: Compass/Mini-Map -Feature #97: Render Clothing/Armour -Feature #121: Window Pinning -Feature #205: Auto equip -Feature #217: Contiainer should track changes to its content -Feature #221: NPC Dialogue Window Enhancements -Feature #233: Game settings manager -Feature #240: Spell List and selected spell (no GUI yet) -Feature #243: Draw State -Task #113: Morrowind.ini Importer -Task #215: Refactor the sound code -Task #216: Update MyGUI - -0.13.0 - -Bug #145: Fixed sound problems after cell change -Bug #179: Pressing space in console triggers activation -Bug #186: CMake doesn't use the debug versions of Ogre libraries on Linux -Bug #189: ASCII 16 character added to console on it's activation on Mac OS X -Bug #190: Case Folding fails with music files -Bug #192: Keypresses write Text into Console no matter which gui element is active -Bug #196: Collision shapes out of place -Bug #202: ESMTool doesn't not work with localised ESM files anymore -Bug #203: Torch lights only visible on short distance -Bug #207: Ogre.log not written -Bug #209: Sounds do not play -Bug #210: Ogre crash at Dren plantation -Bug #214: Unsupported file format version -Bug #222: Launcher is writing openmw.cfg file to wrong location -Feature #9: NPC Dialogue Window -Feature #16/42: New sky/weather implementation -Feature #40: Fading -Feature #48: NPC Dialogue System -Feature #117: Equipping Items (backend only, no GUI yet, no rendering of equipped items yet) -Feature #161: Load REC_PGRD records -Feature #195: Wireframe-mode -Feature #198/199: Various sound effects -Feature #206: Allow picking data path from launcher if non is set -Task #108: Refactor window manager class -Task #172: Sound Manager Cleanup -Task #173: Create OpenEngine systems in the appropriate manager classes -Task #184: Adjust MSVC and gcc warning levels -Task #185: RefData rewrite -Task #201: Workaround for transparency issues -Task #208: silenced esm_reader.hpp warning - -0.12.0 - -Bug #154: FPS Drop -Bug #169: Local scripts continue running if associated object is deleted -Bug #174: OpenMW fails to start if the config directory doesn't exist -Bug #187: Missing lighting -Bug #188: Lights without a mesh are not rendered -Bug #191: Taking screenshot causes crash when running installed -Feature #28: Sort out the cell load problem -Feature #31: Allow the player to move away from pre-defined cells -Feature #35: Use alternate storage location for modified object position -Feature #45: NPC animations -Feature #46: Creature Animation -Feature #89: Basic Journal Window -Feature #110: Automatically pick up the path of existing MW-installations -Feature #183: More FPS display settings -Task #19: Refactor engine class -Task #109/Feature #162: Automate Packaging -Task #112: Catch exceptions thrown in input handling functions -Task #128/#168: Cleanup Configuration File Handling -Task #131: NPC Activation doesn't work properly -Task #144: MWRender cleanup -Task #155: cmake cleanup - -0.11.1 - -Bug #2: Resources loading doesn't work outside of bsa files -Bug #3: GUI does not render non-English characters -Bug #7: openmw.cfg location doesn't match -Bug #124: The TCL alias for ToggleCollision is missing. -Bug #125: Some command line options can't be used from a .cfg file -Bug #126: Toggle-type script instructions are less verbose compared with original MW -Bug #130: NPC-Record Loading fails for some NPCs -Bug #167: Launcher sets invalid parameters in ogre config -Feature #10: Journal -Feature #12: Rendering Optimisations -Feature #23: Change Launcher GUI to a tabbed interface -Feature #24: Integrate the OGRE settings window into the launcher -Feature #25: Determine openmw.cfg location (Launcher) -Feature #26: Launcher Profiles -Feature #79: MessageBox -Feature #116: Tab-Completion in Console -Feature #132: --data-local and multiple --data -Feature #143: Non-Rendering Performance-Optimisations -Feature #150: Accessing objects in cells via ID does only work for objects with all lower case IDs -Feature #157: Version Handling -Task #14: Replace tabs with 4 spaces -Task #18: Move components from global namespace into their own namespace -Task #123: refactor header files in components/esm - -0.10.0 - -* NPC dialogue window (not functional yet) -* Collisions with objects -* Refactor the PlayerPos class -* Adjust file locations -* CMake files and test linking for Bullet -* Replace Ogre raycasting test for activation with something more precise -* Adjust player movement according to collision results -* FPS display -* Various Portability Improvements -* Mac OS X support is back! - -0.9.0 - -* Exterior cells loading, unloading and management -* Character Creation GUI -* Character creation -* Make cell names case insensitive when doing internal lookups -* Music player -* NPCs rendering - -0.8.0 - -* GUI -* Complete and working script engine -* In game console -* Sky rendering -* Sound and music -* Tons of smaller stuff - -0.7.0 - -* This release is a complete rewrite in C++. -* All D code has been culled, and all modules have been rewritten. -* The game is now back up to the level of rendering interior cells and moving around, but physics, sound, GUI, and scripting still remain to be ported from the old codebase. - -0.6.0 - -* Coded a GUI system using MyGUI -* Skinned MyGUI to look like Morrowind (work in progress) -* Integrated the Monster script engine -* Rewrote some functions into script code -* Very early MyGUI < > Monster binding -* Fixed Windows sound problems (replaced old openal32.dll) - -0.5.0 - -* Collision detection with Bullet -* Experimental walk & fall character physics -* New key bindings: - * t toggle physics mode (walking, flying, ghost), - * n night eye, brightens the scene -* Fixed incompatability with DMD 1.032 and newer compilers -* * (thanks to tomqyp) -* Various minor changes and updates - -0.4.0 - -* Switched from Audiere to OpenAL -* * (BIG thanks to Chris Robinson) -* Added complete Makefile (again) as a alternative build tool -* More realistic lighting (thanks again to Chris Robinson) -* Various localization fixes tested with Russian and French versions -* Temporary workaround for the Unicode issue: invalid UTF displayed as '?' -* Added ns option to disable sound, for debugging -* Various bug fixes -* Cosmetic changes to placate gdc Wall - -0.3.0 - -* Built and tested on Windows XP -* Partial support for FreeBSD (exceptions do not work) -* You no longer have to download Monster separately -* Made an alternative for building without DSSS (but DSSS still works) -* Renamed main program from 'morro' to 'openmw' -* Made the config system more robust -* Added oc switch for showing Ogre config window on startup -* Removed some config files, these are auto generated when missing. -* Separated plugins.cfg into linux and windows versions. -* Updated Makefile and sources for increased portability -* confirmed to work against OIS 1.0.0 (Ubuntu repository package) - -0.2.0 - -* Compiles with gdc -* Switched to DSSS for building D code -* Includes the program esmtool - -0.1.0 - -first release +See CHANGELOG.md From c8373198a1b8c714ead2db7d38641d4f30a5db3e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 16:36:59 +0100 Subject: [PATCH 160/740] Add Travis-CI build status image to Readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 862ae16c7..63bf1bcf3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ OpenMW: A reimplementation of The Elder Scrolls III: Morrowind ============================================================== +[![Build Status](https://travis-ci.org/OpenMW/openmw.svg?branch=coverity_scan)](https://travis-ci.org/OpenMW/openmw) + OpenMW is an attempt at recreating the engine for the popular role-playing game Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work. From 32ad1ae1761e1961ccb2acf25669f3e97fb2799c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 16:39:00 +0100 Subject: [PATCH 161/740] Add coverity scan build status image to Readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 63bf1bcf3..bc1efa562 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ OpenMW: A reimplementation of The Elder Scrolls III: Morrowind [![Build Status](https://travis-ci.org/OpenMW/openmw.svg?branch=coverity_scan)](https://travis-ci.org/OpenMW/openmw) +[![Coverity Scan Build Status](https://scan.coverity.com/projects/3740/badge.svg)](https://scan.coverity.com/projects/3740) + OpenMW is an attempt at recreating the engine for the popular role-playing game Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work. From 5ee78602e98326601a7058183677497c22552ced Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 16:44:28 +0100 Subject: [PATCH 162/740] Improve readme formatting --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index bc1efa562..754e4d5f7 100644 --- a/README.md +++ b/README.md @@ -18,18 +18,18 @@ Font Licenses: Installation ============ -Windows: +Windows +------- Run the installer. -Linux: -Ubuntu (and most others) -Download the .deb file and install it in the usual way. +Linux +----- +* Ubuntu (and most others): Download the .deb file and install it in the usual way. -Arch Linux -There's an OpenMW package available in the [community] Repository: -https://www.archlinux.org/packages/?sort=&q=openmw +* Arch Linux: There's an OpenMW package available in the [community] Repository: https://www.archlinux.org/packages/?sort=&q=openmw -OS X: +OS X +---- Open DMG file, copy OpenMW folder anywhere, for example in /Applications Build from source From 3c74c554f811fe8e71d50fe6ab4ac0f8857385f0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 16:45:20 +0100 Subject: [PATCH 163/740] Add IRC channel to readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 754e4d5f7..de06554c1 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ Morrowind by Bethesda Softworks. You need to own and install the original game f * Version: 0.34.0 * License: GPL (see GPL3.txt for more information) * Website: http://www.openmw.org +* IRC: #openmw on irc.freenode.net Font Licenses: * DejaVuLGCSansMono.ttf: custom (see DejaVu Font License.txt for more information) From d1b07faa5678999f04e3d6e06162cef49115cf7d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 16:49:59 +0100 Subject: [PATCH 164/740] Replace outdated Installation section with link --- README.md | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/README.md b/README.md index de06554c1..279d1d6d7 100644 --- a/README.md +++ b/README.md @@ -19,19 +19,7 @@ Font Licenses: Installation ============ -Windows -------- -Run the installer. - -Linux ------ -* Ubuntu (and most others): Download the .deb file and install it in the usual way. - -* Arch Linux: There's an OpenMW package available in the [community] Repository: https://www.archlinux.org/packages/?sort=&q=openmw - -OS X ----- -Open DMG file, copy OpenMW folder anywhere, for example in /Applications +Head to [Downloads](http://openmw.org/downloads/) to find a packaged release for your platform of choice. Build from source ================= From bcddfabea135be3ff034ee11a0d0f79736272a57 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 16:54:55 +0100 Subject: [PATCH 165/740] Fix license file names in readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 279d1d6d7..ff5185b5d 100644 --- a/README.md +++ b/README.md @@ -9,12 +9,12 @@ OpenMW is an attempt at recreating the engine for the popular role-playing game Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work. * Version: 0.34.0 -* License: GPL (see GPL3.txt for more information) +* License: GPL (see docs/license/GPL3.txt for more information) * Website: http://www.openmw.org * IRC: #openmw on irc.freenode.net Font Licenses: -* DejaVuLGCSansMono.ttf: custom (see DejaVu Font License.txt for more information) +* DejaVuLGCSansMono.ttf: custom (see docs/license/DejaVu Font License.txt for more information) Installation ============ From 36a2c11da4e0f59c871673e482f3ab4c80f28f90 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 16:59:21 +0100 Subject: [PATCH 166/740] Move credits.txt to AUTHORS.md to make it consistent with most other github projects --- credits.txt => AUTHORS.md | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) rename credits.txt => AUTHORS.md (93%) diff --git a/credits.txt b/AUTHORS.md similarity index 93% rename from credits.txt rename to AUTHORS.md index dfdf87565..b6aec55f5 100644 --- a/credits.txt +++ b/AUTHORS.md @@ -1,4 +1,5 @@ Contributors +============ The OpenMW project was started in 2008 by Nicolay Korslund. In the course of years many people have contributed to the project. @@ -7,7 +8,9 @@ If you feel your name is missing from this list, please notify a developer. -Programmers: +Programmers +----------- + Marc Zinnschlag (Zini) - Lead Programmer/Project Manager Adam Hogan (aurix) @@ -103,7 +106,8 @@ viadanna Vincent Heuken vocollapse -Packagers: +Packagers +--------- Alexander Olofsson (Ace) - Windows Bret Curtis (psi29a) - Ubuntu Linux Edmondo Tommasina (edmondo) - Gentoo Linux @@ -113,7 +117,8 @@ Kenny Armstrong (artorius) - Fedora Linux Nikolay Kasyanov (corristo) - Mac OS X Sandy Carter (bwrsandman) - Arch Linux -Public Relations and Translations: +Public Relations and Translations +--------------------------------- Alex McKibben (WeirdSexy) - Podcaster Artem Kotsynyak (greye) - Russian News Writer Jim Clauwaert (Zedd) - Public Outreach @@ -125,12 +130,14 @@ Pithorn - Chinese News Writer sir_herrbatka - Polish News Writer Dawid Lakomy (Vedyimyn) - Polish News Writer -Website: +Website +------- Lukasz Gromanowski (Lgro) - Website Administrator Ryan Sardonic (Wry) - Wiki Editor sir_herrbatka - Forum Administrator -Formula Research: +Formula Research +---------------- Hrnchamd Epsilon fragonard @@ -141,12 +148,14 @@ Myckel natirips Sadler -Artwork: +Artwork +------- Necrod - OpenMW Logo Mickey Lyle (raevol) - Wordpress Theme Tom Koenderink (Okulo), SirHerrbatka, crysthala, Shnatsel - OpenMW Editor Icons -Inactive Contributors: +Inactive Contributors +--------------------- Ardekantur Armin Preiml Berulacks @@ -174,7 +183,8 @@ Thoronador Yuri Krupenin -Additional Credits: +Additional Credits +------------------ In this section we would like to thank people not part of OpenMW for their work. Thanks to Maxim Nikolaev, From 6079bcad245e22a9c778571a4b4387e367e804f0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 17:03:41 +0100 Subject: [PATCH 167/740] Formatting fix --- AUTHORS.md | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index b6aec55f5..dddc61a13 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -4,13 +4,12 @@ Contributors The OpenMW project was started in 2008 by Nicolay Korslund. In the course of years many people have contributed to the project. -If you feel your name is missing from this list, -please notify a developer. +If you feel your name is missing from this list, please notify a developer. Programmers ----------- - +
 Marc Zinnschlag (Zini) - Lead Programmer/Project Manager
 
 Adam Hogan (aurix)
@@ -105,9 +104,10 @@ Torben Leif Carrington (TorbenC)
 viadanna
 Vincent Heuken
 vocollapse
-
+
Packagers --------- +
 Alexander Olofsson (Ace) - Windows
 Bret Curtis (psi29a) - Ubuntu Linux
 Edmondo Tommasina (edmondo) - Gentoo Linux
@@ -116,9 +116,10 @@ Karl-Felix Glatzer (k1ll) - Linux Binaries
 Kenny Armstrong (artorius) - Fedora Linux
 Nikolay Kasyanov (corristo) - Mac OS X
 Sandy Carter (bwrsandman) - Arch Linux
-
+
Public Relations and Translations --------------------------------- +
 Alex McKibben (WeirdSexy) - Podcaster
 Artem Kotsynyak (greye) - Russian News Writer
 Jim Clauwaert (Zedd) - Public Outreach
@@ -129,15 +130,17 @@ Mickey Lyle (raevol) - Release Manager
 Pithorn - Chinese News Writer
 sir_herrbatka - Polish News Writer
 Dawid Lakomy (Vedyimyn) - Polish News Writer
-
+
Website ------- +
 Lukasz Gromanowski (Lgro) - Website Administrator
 Ryan Sardonic (Wry) - Wiki Editor
 sir_herrbatka - Forum Administrator
-
+
Formula Research ---------------- +
 Hrnchamd
 Epsilon
 fragonard
@@ -147,15 +150,17 @@ modred11
 Myckel
 natirips
 Sadler
-
+
Artwork ------- +
 Necrod - OpenMW Logo
 Mickey Lyle (raevol) - Wordpress Theme
 Tom Koenderink (Okulo), SirHerrbatka, crysthala, Shnatsel - OpenMW Editor Icons
-
+
Inactive Contributors --------------------- +
 Ardekantur
 Armin Preiml
 Berulacks
@@ -181,7 +186,7 @@ spyboot
 Star-Demon
 Thoronador
 Yuri Krupenin
-
+
Additional Credits ------------------ From 529fd353fe0724a179595854f0f92f137cd39fca Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 17:05:24 +0100 Subject: [PATCH 168/740] EB Garamond and Daedric Fontface are no longer used --- AUTHORS.md | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index dddc61a13..f6da26e77 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -196,17 +196,10 @@ Thanks to Maxim Nikolaev, for allowing us to use his excellent Morrowind fan-art on our website and in other places. Thanks to DokterDume, -for kindly providing us with the Moon and Star logo, -used as the application icon and project logo. +for kindly providing us with the Moon and Star logo, used as the application icon and project logo. Thanks to Kevin Ryan, for creating the icon used for the Data Files tab of the OpenMW Launcher. -Thanks to Georg Duffner, -for his EB Garamond fontface, see OFL.txt for his license terms. - -Thanks to Dongle, -for his Daedric fontface, see Daedric Font License.txt for his license terms. - Thanks to DejaVu team, for their DejaVuLGCSansMono fontface, see DejaVu Font License.txt for their license terms. From 3684f586cd6cad55cc5fb1d49db18d12a1ff8308 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 17:18:33 +0100 Subject: [PATCH 169/740] Changelog formatting --- CHANGELOG.md | 2677 +++++++++++++++++++++++++------------------------- 1 file changed, 1355 insertions(+), 1322 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09f318d9d..750cb5476 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,1376 +1,1401 @@ -
 0.34.0
-
-Bug #904: omwlauncher doesn't allow installing Tribunal and Bloodmoon if only MW is installed
-Bug #986: Launcher: renaming profile names is broken
-Bug #1061: "Browse to CD..." launcher crash
-Bug #1135: Launcher crashes if user does not have write permission
-Bug #1231: Current installer in launcher does not correctly import russian Morrowind.ini settings from setup.inx
-Bug #1288: Fix the Alignment of the Resolution Combobox
-Bug #1343: BIK videos occasionally out of sync with audio
-Bug #1684: Morrowind Grass Mod graphical glitches
-Bug #1734: NPC in fight with invisible/sneaking player
-Bug #1982: Long class names are cut off in the UI
-Bug #2012: Editor: OpenCS script compiler sometimes fails to find IDs
-Bug #2015: Running while levitating does not affect speed but still drains fatigue
-Bug #2018: OpenMW don´t reset modified cells to vanilla when a plugin is deselected and don´t apply changes to cells already visited.
-Bug #2045: ToggleMenus command should close dialogue windows
-Bug #2046: Crash: light_de_streetlight_01_223
-Bug #2047: Buglamp tooltip minor correction
-Bug #2050: Roobrush floating texture bits
-Bug #2053: Slaves react negatively to PC picking up slave's bracers
-Bug #2055: Dremora corpses use the wrong model
-Bug #2056: Mansilamat Vabdas's corpse is floating in the water
-Bug #2057: "Quest: Larius Varro Tells A Little Story": Bounty not completely removed after finishing quest
-Bug #2059: Silenced enemies try to cast spells anyway
-Bug #2060: Editor: Special case implementation for top level window with single sub-window should be optional
-Bug #2061: Editor: SubView closing that is not directly triggered by the user isn't handled properly
-Bug #2063: Tribunal: Quest 'The Warlords' doesn't work
-Bug #2064: Sneak attack on hostiles causes bounty
-Bug #2065: Editor: Qt signal-slot error when closing a dialogue subview
-Bug #2070: Loading ESP in OpenMW works but fails in OpenCS
-Bug #2071: CTD in 0.33
-Bug #2073: Storm atronach animation stops now and then
-Bug #2075: Molag Amur Region, Map shows water on solid ground
-Bug #2080: game won't work with fair magicka regen
-Bug #2082: NPCs appear frozen or switched off after leaving and quickly reentering a cell
-Bug #2088: OpenMW is unable to play OGG files.
-Bug #2093: Darth Gares talks to you in Ilunibi even when he's not there, screwing up the Main Quests
-Bug #2095: Coordinate and rotation editing in the Reference table does not work.
-Bug #2096: Some overflow fun and bartering exploit
-Bug #2098: [D3D] Game crash on maximize
-Bug #2099: Activate, player seems not to work
-Bug #2104: Only labels are sensitive in buttons
-Bug #2107: "Slowfall" effect is too weak
-Bug #2114: OpenCS doesn't load an ESP file full of errors even though Vanilla MW Construction Set can
-Bug #2117: Crash when encountering bandits on opposite side of river from the egg mine south of Balmora
-Bug #2124: [Mod: Baldurians Transparent Glass Amor] Armor above head
-Bug #2125: Unnamed NiNodes in weapons problem in First Person
-Bug #2126: Dirty dialog script in tribunal.esm causing bug in Tribunal MQ
-Bug #2128: Crash when picking character's face
-Bug #2129: Disable the third-person zoom feature by default
-Bug #2130: Ash storm particles shown too long during transition to clear sky
-Bug #2137: Editor: exception caused by following the Creature column of a SoundGen record
-Bug #2139: Mouse movement should be ignored during intro video
-Bug #2143: Editor: Saving is broken
-Bug #2145: OpenMW - crash while exiting x64 debug build
-Bug #2152: You can attack Almalexia during her final monologue
-Bug #2154: Visual effects behave weirdly after loading/taking a screenshot
-Bug #2155: Vivec has too little magicka
-Bug #2156: Azura's spirit fades away too fast
-Bug #2158: [Mod]Julan Ashlander Companion 2.0: Negative magicka
-Bug #2161: Editor: combat/magic/stealth values of creature not displayed correctly
-Bug #2163: OpenMW can't detect death if the NPC die by the post damage effect of a magic weapon.
-Bug #2168: Westly's Master Head Pack X – Some hairs aren't rendered correctly.
-Bug #2170: Mods using conversations to update PC inconsistant
-Bug #2180: Editor: Verifier doesn't handle Windows-specific path issues when dealing with resources
-Bug #2212: Crash or unexpected behavior while closing OpenCS cell render window on OS X
-Feature #238: Add UI to run INI-importer from the launcher
-Feature #854: Editor: Add user setting to show status bar
-Feature #987: Launcher: first launch instructions for CD need to be more explicit
-Feature #1232: There is no way to set the "encoding" option using launcher UI.
-Feature #1281: Editor: Render cell markers
-Feature #1918: Editor: Functionality for Double-Clicking in Tables
-Feature #1966: Editor: User Settings dialogue grouping/labelling/tooltips
-Feature #2097: Editor: Edit position of references in 3D scene
-Feature #2121: Editor: Add edit mode button to scene toolbar
-Task #1965: Editor: Improve layout of user settings dialogue
+------
+
+    Bug #904: omwlauncher doesn't allow installing Tribunal and Bloodmoon if only MW is installed
+    Bug #986: Launcher: renaming profile names is broken
+    Bug #1061: "Browse to CD..." launcher crash
+    Bug #1135: Launcher crashes if user does not have write permission
+    Bug #1231: Current installer in launcher does not correctly import russian Morrowind.ini settings from setup.inx
+    Bug #1288: Fix the Alignment of the Resolution Combobox
+    Bug #1343: BIK videos occasionally out of sync with audio
+    Bug #1684: Morrowind Grass Mod graphical glitches
+    Bug #1734: NPC in fight with invisible/sneaking player
+    Bug #1982: Long class names are cut off in the UI
+    Bug #2012: Editor: OpenCS script compiler sometimes fails to find IDs
+    Bug #2015: Running while levitating does not affect speed but still drains fatigue
+    Bug #2018: OpenMW don´t reset modified cells to vanilla when a plugin is deselected and don´t apply changes to cells already visited.
+    Bug #2045: ToggleMenus command should close dialogue windows
+    Bug #2046: Crash: light_de_streetlight_01_223
+    Bug #2047: Buglamp tooltip minor correction
+    Bug #2050: Roobrush floating texture bits
+    Bug #2053: Slaves react negatively to PC picking up slave's bracers
+    Bug #2055: Dremora corpses use the wrong model
+    Bug #2056: Mansilamat Vabdas's corpse is floating in the water
+    Bug #2057: "Quest: Larius Varro Tells A Little Story": Bounty not completely removed after finishing quest
+    Bug #2059: Silenced enemies try to cast spells anyway
+    Bug #2060: Editor: Special case implementation for top level window with single sub-window should be optional
+    Bug #2061: Editor: SubView closing that is not directly triggered by the user isn't handled properly
+    Bug #2063: Tribunal: Quest 'The Warlords' doesn't work
+    Bug #2064: Sneak attack on hostiles causes bounty
+    Bug #2065: Editor: Qt signal-slot error when closing a dialogue subview
+    Bug #2070: Loading ESP in OpenMW works but fails in OpenCS
+    Bug #2071: CTD in 0.33
+    Bug #2073: Storm atronach animation stops now and then
+    Bug #2075: Molag Amur Region, Map shows water on solid ground
+    Bug #2080: game won't work with fair magicka regen
+    Bug #2082: NPCs appear frozen or switched off after leaving and quickly reentering a cell
+    Bug #2088: OpenMW is unable to play OGG files.
+    Bug #2093: Darth Gares talks to you in Ilunibi even when he's not there, screwing up the Main Quests
+    Bug #2095: Coordinate and rotation editing in the Reference table does not work.
+    Bug #2096: Some overflow fun and bartering exploit
+    Bug #2098: [D3D] Game crash on maximize
+    Bug #2099: Activate, player seems not to work
+    Bug #2104: Only labels are sensitive in buttons
+    Bug #2107: "Slowfall" effect is too weak
+    Bug #2114: OpenCS doesn't load an ESP file full of errors even though Vanilla MW Construction Set can
+    Bug #2117: Crash when encountering bandits on opposite side of river from the egg mine south of Balmora
+    Bug #2124: [Mod: Baldurians Transparent Glass Amor] Armor above head
+    Bug #2125: Unnamed NiNodes in weapons problem in First Person
+    Bug #2126: Dirty dialog script in tribunal.esm causing bug in Tribunal MQ
+    Bug #2128: Crash when picking character's face
+    Bug #2129: Disable the third-person zoom feature by default
+    Bug #2130: Ash storm particles shown too long during transition to clear sky
+    Bug #2137: Editor: exception caused by following the Creature column of a SoundGen record
+    Bug #2139: Mouse movement should be ignored during intro video
+    Bug #2143: Editor: Saving is broken
+    Bug #2145: OpenMW - crash while exiting x64 debug build
+    Bug #2152: You can attack Almalexia during her final monologue
+    Bug #2154: Visual effects behave weirdly after loading/taking a screenshot
+    Bug #2155: Vivec has too little magicka
+    Bug #2156: Azura's spirit fades away too fast
+    Bug #2158: [Mod]Julan Ashlander Companion 2.0: Negative magicka
+    Bug #2161: Editor: combat/magic/stealth values of creature not displayed correctly
+    Bug #2163: OpenMW can't detect death if the NPC die by the post damage effect of a magic weapon.
+    Bug #2168: Westly's Master Head Pack X – Some hairs aren't rendered correctly.
+    Bug #2170: Mods using conversations to update PC inconsistant
+    Bug #2180: Editor: Verifier doesn't handle Windows-specific path issues when dealing with resources
+    Bug #2212: Crash or unexpected behavior while closing OpenCS cell render window on OS X
+    Feature #238: Add UI to run INI-importer from the launcher
+    Feature #854: Editor: Add user setting to show status bar
+    Feature #987: Launcher: first launch instructions for CD need to be more explicit
+    Feature #1232: There is no way to set the "encoding" option using launcher UI.
+    Feature #1281: Editor: Render cell markers
+    Feature #1918: Editor: Functionality for Double-Clicking in Tables
+    Feature #1966: Editor: User Settings dialogue grouping/labelling/tooltips
+    Feature #2097: Editor: Edit position of references in 3D scene
+    Feature #2121: Editor: Add edit mode button to scene toolbar
+    Task #1965: Editor: Improve layout of user settings dialogue
 
 0.33.1
+------
 
-Bug #2108: OpenCS fails to build
+    Bug #2108: OpenCS fails to build
 
 0.33.0
-
-Bug #371: If console assigned to ` (probably to any symbolic key), "`" symbol will be added to console every time it closed
-Bug #1148: Some books'/scrolls' contents are displayed incorrectly
-Bug #1290: Editor: status bar is not updated when record filter is changed
-Bug #1292: Editor: Documents are not removed on closing the last view
-Bug #1301: Editor: File->Exit only checks the document it was issued from.
-Bug #1353: Bluetooth on with no speaker connected results in significantly longer initial load times
-Bug #1436: NPCs react from too far distance
-Bug #1472: PC is placed on top of following NPC when changing cell
-Bug #1487: Tall PC can get stuck in staircases
-Bug #1565: Editor: Subviews are deleted on shutdown instead when they are closed
-Bug #1623: Door marker on Ghorak Manor's balcony makes PC stuck
-Bug #1633: Loaddoor to Sadrith Mora, Telvanni Council House spawns PC in the air
-Bug #1655: Use Appropriate Application Icons on Windows
-Bug #1679: Tribunal expansion, Meryn Othralas the backstage manager in the theatre group in Mournhold in the great bazaar district is floating a good feet above the ground.
-Bug #1705: Rain is broken in third person
-Bug #1706: Thunder and lighting still occurs while the game is paused during the rain
-Bug #1708: No long jumping
-Bug #1710: Editor: ReferenceableID drag to references record filter field creates incorrect filter
-Bug #1712: Rest on Water
-Bug #1715: "Cancel" button is not always on the same side of menu
-Bug #1725: Editor: content file can be opened multiple times from the same dialogue
-Bug #1730: [MOD: Less Generic Nerevarine] Compile failure attempting to enter the Corprusarium.
-Bug #1733: Unhandled ffmpeg sample formats
-Bug #1735: Editor: "Edit Record" context menu button not opening subview for journal infos
-Bug #1750: Editor: record edits result in duplicate entries
-Bug #1789: Editor: Some characters cannot be used in addon name
-Bug #1803: Resizing the map does not keep the pre-resize center at the post-resize center
-Bug #1821: Recovering Cloudcleaver quest: attacking Sosia is considered a crime when you side with Hlormar
-Bug #1838: Editor: Preferences window appears off screen
-Bug #1839: Editor: Record filter title should be moved two pixels to the right
-Bug #1849: Subrecord error in MAO_Containers
-Bug #1854: Knocked-out actors don't fully act knocked out
-Bug #1855: "Soul trapped" sound doesn't play
-Bug #1857: Missing sound effect for enchanted items with empty charge
-Bug #1859: Missing console command: ResetActors (RA)
-Bug #1861: Vendor category "MagicItems" is unhandled
-Bug #1862: Launcher doesn't start if a file listed in launcher.cfg has correct name but wrong capitalization
-Bug #1864: Editor: Region field for cell record in dialogue subview not working
-Bug #1869: Editor: Change label "Musics" to "Music"
-Bug #1870: Goblins killed while knocked down remain in knockdown-pose
-Bug #1874: CellChanged events should not trigger when crossing exterior cell border
-Bug #1877: Spriggans killed instantly if hit while regening
-Bug #1878: Magic Menu text not un-highlighting correctly when going from spell to item as active magic
-Bug #1881: Stuck in ceiling when entering castle karstaags tower
-Bug #1884: Unlit torches still produce a burning sound
-Bug #1885: Can type text in price field in barter window
-Bug #1887: Equipped items do not emit sounds
-Bug #1889: draugr lord aesliip will attack you and remain non-hostile
-Bug #1892: Guard asks player to pay bounty of 0 gold
-Bug #1895: getdistance should only return max float if ref and target are in different worldspaces
-Bug #1896: Crash Report
-Bug #1897: Conjured Equipment cant be re-equipped if removed
-Bug #1898: Only Gidar Verothan follows you during establish the mine quest
-Bug #1900: Black screen when you open the door and breath underwater
-Bug #1904: Crash on casting recall spell
-Bug #1906: Bound item checks should use the GMSTs
-Bug #1907: Bugged door. Mournhold, The Winged Guar
-Bug #1908: Crime reported for attacking Drathas Nerus's henchmen while they attack Dilborn
-Bug #1909: Weird Quest Flow Infidelities quest
-Bug #1910: Follower fighting with gone npc
-Bug #1911: Npcs will drown themselves
-Bug #1912: World map arrow stays static when inside a building
-Bug #1920: Ulyne Henim disappears when game is loaded inside Vas
-Bug #1922: alchemy-> potion of paralyze
-Bug #1923: "levitation magic cannot be used here" shows outside of tribunal
-Bug #1927: AI prefer melee over magic.
-Bug #1929: Tamriel Rebuilt: Named cells that lie within the overlap with Morrowind.esm are not shown
-Bug #1932: BTB - Spells 14.1 magic effects don´t overwrite the Vanilla ones but are added
-Bug #1935: Stacks of items are worth more when sold individually
-Bug #1940: Launcher does not list addon files if base game file is renamed to a different case
-Bug #1946: Mod "Tel Nechim - moved" breaks savegames
-Bug #1947: Buying/Selling price doesn't properly affect the growth of mercantile skill
-Bug #1950: followers from east empire company quest will fight each other if combat happens with anything
-Bug #1958: Journal can be scrolled indefinitely with a mouse wheel
-Bug #1959: Follower not leaving party on quest end
-Bug #1960: Key bindings not always saved correctly
-Bug #1961: Spell merchants selling racial bonus spells
-Bug #1967: segmentation fault on load saves
-Bug #1968: Jump sounds are not controlled by footsteps slider, sound weird compared to footsteps
-Bug #1970: PC suffers silently when taking damage from lava
-Bug #1971: Dwarven Sceptre collision area is not removed after killing one
-Bug #1974: Dalin/Daris Norvayne follows player indefinitely
-Bug #1975: East Empire Company faction rank breaks during Raven Rock questline
-Bug #1979: 0 strength = permanently over encumbered
-Bug #1993: Shrine blessing in Maar Gan doesn't work
-Bug #2008: Enchanted items do not recharge
-Bug #2011: Editor: OpenCS script compiler doesn't handle member variable access properly
-Bug #2016: Dagoth Ur already dead in Facility Cavern
-Bug #2017: Fighters Guild Quest: The Code Book - dialogue loop when UMP is loaded.
-Bug #2019: Animation of 'Correct UV Mudcrabs' broken
-Bug #2022: Alchemy window - Removing ingredient doesn't remove the number of ingredients
-Bug #2025: Missing mouse-over text for non affordable items
-Bug #2028: [MOD: Tamriel Rebuilt] Crashing when trying to enter interior cell "Ruinous Keep, Great Hall"
-Bug #2029: Ienith Brothers Thiev's Guild quest journal entry not adding
-Feature #471: Editor: Special case implementation for top-level window with single sub-window
-Feature #472: Editor: Sub-Window re-use settings
-Feature #704: Font colors import from fallback settings
-Feature #879: Editor: Open sub-views in a new top-level window
-Feature #932: Editor: magic effect table
-Feature #937: Editor: Path Grid table
-Feature #938: Editor: Sound Gen table
-Feature #1117: Death and LevelUp music
-Feature #1226: Editor: Request UniversalId editing from table columns
-Feature #1545: Targeting console on player
-Feature #1597: Editor: Render terrain
-Feature #1695: Editor: add column for CellRef's global variable
-Feature #1696: Editor: use ESM::Cell's RefNum counter
-Feature #1697: Redden player's vision when hit
-Feature #1856: Spellcasting for non-biped creatures
-Feature #1879: Editor: Run OpenMW with the currently edited content list
-Task #1851: Move AI temporary state out of AI packages
-Task #1865: Replace char type in records
+------
+
+    Bug #371: If console assigned to ` (probably to any symbolic key), "`" symbol will be added to console every time it closed
+    Bug #1148: Some books'/scrolls' contents are displayed incorrectly
+    Bug #1290: Editor: status bar is not updated when record filter is changed
+    Bug #1292: Editor: Documents are not removed on closing the last view
+    Bug #1301: Editor: File->Exit only checks the document it was issued from.
+    Bug #1353: Bluetooth on with no speaker connected results in significantly longer initial load times
+    Bug #1436: NPCs react from too far distance
+    Bug #1472: PC is placed on top of following NPC when changing cell
+    Bug #1487: Tall PC can get stuck in staircases
+    Bug #1565: Editor: Subviews are deleted on shutdown instead when they are closed
+    Bug #1623: Door marker on Ghorak Manor's balcony makes PC stuck
+    Bug #1633: Loaddoor to Sadrith Mora, Telvanni Council House spawns PC in the air
+    Bug #1655: Use Appropriate Application Icons on Windows
+    Bug #1679: Tribunal expansion, Meryn Othralas the backstage manager in the theatre group in Mournhold in the great bazaar district is floating a good feet above the ground.
+    Bug #1705: Rain is broken in third person
+    Bug #1706: Thunder and lighting still occurs while the game is paused during the rain
+    Bug #1708: No long jumping
+    Bug #1710: Editor: ReferenceableID drag to references record filter field creates incorrect filter
+    Bug #1712: Rest on Water
+    Bug #1715: "Cancel" button is not always on the same side of menu
+    Bug #1725: Editor: content file can be opened multiple times from the same dialogue
+    Bug #1730: [MOD: Less Generic Nerevarine] Compile failure attempting to enter the Corprusarium.
+    Bug #1733: Unhandled ffmpeg sample formats
+    Bug #1735: Editor: "Edit Record" context menu button not opening subview for journal infos
+    Bug #1750: Editor: record edits result in duplicate entries
+    Bug #1789: Editor: Some characters cannot be used in addon name
+    Bug #1803: Resizing the map does not keep the pre-resize center at the post-resize center
+    Bug #1821: Recovering Cloudcleaver quest: attacking Sosia is considered a crime when you side with Hlormar
+    Bug #1838: Editor: Preferences window appears off screen
+    Bug #1839: Editor: Record filter title should be moved two pixels to the right
+    Bug #1849: Subrecord error in MAO_Containers
+    Bug #1854: Knocked-out actors don't fully act knocked out
+    Bug #1855: "Soul trapped" sound doesn't play
+    Bug #1857: Missing sound effect for enchanted items with empty charge
+    Bug #1859: Missing console command: ResetActors (RA)
+    Bug #1861: Vendor category "MagicItems" is unhandled
+    Bug #1862: Launcher doesn't start if a file listed in launcher.cfg has correct name but wrong capitalization
+    Bug #1864: Editor: Region field for cell record in dialogue subview not working
+    Bug #1869: Editor: Change label "Musics" to "Music"
+    Bug #1870: Goblins killed while knocked down remain in knockdown-pose
+    Bug #1874: CellChanged events should not trigger when crossing exterior cell border
+    Bug #1877: Spriggans killed instantly if hit while regening
+    Bug #1878: Magic Menu text not un-highlighting correctly when going from spell to item as active magic
+    Bug #1881: Stuck in ceiling when entering castle karstaags tower
+    Bug #1884: Unlit torches still produce a burning sound
+    Bug #1885: Can type text in price field in barter window
+    Bug #1887: Equipped items do not emit sounds
+    Bug #1889: draugr lord aesliip will attack you and remain non-hostile
+    Bug #1892: Guard asks player to pay bounty of 0 gold
+    Bug #1895: getdistance should only return max float if ref and target are in different worldspaces
+    Bug #1896: Crash Report
+    Bug #1897: Conjured Equipment cant be re-equipped if removed
+    Bug #1898: Only Gidar Verothan follows you during establish the mine quest
+    Bug #1900: Black screen when you open the door and breath underwater
+    Bug #1904: Crash on casting recall spell
+    Bug #1906: Bound item checks should use the GMSTs
+    Bug #1907: Bugged door. Mournhold, The Winged Guar
+    Bug #1908: Crime reported for attacking Drathas Nerus's henchmen while they attack Dilborn
+    Bug #1909: Weird Quest Flow Infidelities quest
+    Bug #1910: Follower fighting with gone npc
+    Bug #1911: Npcs will drown themselves
+    Bug #1912: World map arrow stays static when inside a building
+    Bug #1920: Ulyne Henim disappears when game is loaded inside Vas
+    Bug #1922: alchemy-> potion of paralyze
+    Bug #1923: "levitation magic cannot be used here" shows outside of tribunal
+    Bug #1927: AI prefer melee over magic.
+    Bug #1929: Tamriel Rebuilt: Named cells that lie within the overlap with Morrowind.esm are not shown
+    Bug #1932: BTB - Spells 14.1 magic effects don´t overwrite the Vanilla ones but are added
+    Bug #1935: Stacks of items are worth more when sold individually
+    Bug #1940: Launcher does not list addon files if base game file is renamed to a different case
+    Bug #1946: Mod "Tel Nechim - moved" breaks savegames
+    Bug #1947: Buying/Selling price doesn't properly affect the growth of mercantile skill
+    Bug #1950: followers from east empire company quest will fight each other if combat happens with anything
+    Bug #1958: Journal can be scrolled indefinitely with a mouse wheel
+    Bug #1959: Follower not leaving party on quest end
+    Bug #1960: Key bindings not always saved correctly
+    Bug #1961: Spell merchants selling racial bonus spells
+    Bug #1967: segmentation fault on load saves
+    Bug #1968: Jump sounds are not controlled by footsteps slider, sound weird compared to footsteps
+    Bug #1970: PC suffers silently when taking damage from lava
+    Bug #1971: Dwarven Sceptre collision area is not removed after killing one
+    Bug #1974: Dalin/Daris Norvayne follows player indefinitely
+    Bug #1975: East Empire Company faction rank breaks during Raven Rock questline
+    Bug #1979: 0 strength = permanently over encumbered
+    Bug #1993: Shrine blessing in Maar Gan doesn't work
+    Bug #2008: Enchanted items do not recharge
+    Bug #2011: Editor: OpenCS script compiler doesn't handle member variable access properly
+    Bug #2016: Dagoth Ur already dead in Facility Cavern
+    Bug #2017: Fighters Guild Quest: The Code Book - dialogue loop when UMP is loaded.
+    Bug #2019: Animation of 'Correct UV Mudcrabs' broken
+    Bug #2022: Alchemy window - Removing ingredient doesn't remove the number of ingredients
+    Bug #2025: Missing mouse-over text for non affordable items
+    Bug #2028: [MOD: Tamriel Rebuilt] Crashing when trying to enter interior cell "Ruinous Keep, Great Hall"
+    Bug #2029: Ienith Brothers Thiev's Guild quest journal entry not adding
+    Feature #471: Editor: Special case implementation for top-level window with single sub-window
+    Feature #472: Editor: Sub-Window re-use settings
+    Feature #704: Font colors import from fallback settings
+    Feature #879: Editor: Open sub-views in a new top-level window
+    Feature #932: Editor: magic effect table
+    Feature #937: Editor: Path Grid table
+    Feature #938: Editor: Sound Gen table
+    Feature #1117: Death and LevelUp music
+    Feature #1226: Editor: Request UniversalId editing from table columns
+    Feature #1545: Targeting console on player
+    Feature #1597: Editor: Render terrain
+    Feature #1695: Editor: add column for CellRef's global variable
+    Feature #1696: Editor: use ESM::Cell's RefNum counter
+    Feature #1697: Redden player's vision when hit
+    Feature #1856: Spellcasting for non-biped creatures
+    Feature #1879: Editor: Run OpenMW with the currently edited content list
+    Task #1851: Move AI temporary state out of AI packages
+    Task #1865: Replace char type in records
 
 0.32.0
-
-Bug #1132: Unable to jump when facing a wall
-Bug #1341: Summoned Creatures do not immediately disappear when killed.
-Bug #1430: CharGen Revamped script does not compile
-Bug #1451: NPCs shouldn't equip weapons prior to fighting
-Bug #1461: Stopped start scripts do not restart on load
-Bug #1473: Dead NPC standing and in 2 pieces
-Bug #1482: Abilities are depleted when interrupted during casting
-Bug #1503: Behaviour of NPCs facing the player
-Bug #1506: Missing character, French edition: three-points
-Bug #1528: Inventory very slow after 2 hours
-Bug #1540: Extra arguments should be ignored for script functions
-Bug #1541: Helseth's Champion: Tribunal
-Bug #1570: Journal cannot be opened while in inventory screen
-Bug #1573: PC joins factions at random
-Bug #1576: NPCs aren't switching their weapons when out of ammo
-Bug #1579: Guards detect creatures in far distance, instead on sight
-Bug #1588: The Siege of the Skaal Village: bloodmoon
-Bug #1593: The script compiler isn't recognising some names that contain a -
-Bug #1606: Books: Question marks instead of quotation marks
-Bug #1608: Dead bodies prevent door from opening/closing.
-Bug #1609: Imperial guards in Sadrith Mora are not using their spears
-Bug #1610: The bounty number is not displayed properly with high numbers
-Bug #1620: Implement correct formula for auto-calculated NPC spells
-Bug #1630: Boats standing vertically in Vivec
-Bug #1635: Arrest dialogue is executed second time after I select "Go to jail"
-Bug #1637: Weird NPC behaviour in Vivec, Hlaalu Ancestral Vaults?
-Bug #1641: Persuasion dialog remains after loading, possibly resulting in crash
-Bug #1644: "Goodbye" and similar options on dialogues prevents escape working properly.
-Bug #1646: PC skill stats are not updated immediately when changing equipment
-Bug #1652: Non-aggressive creature
-Bug #1653: Quickloading while the container window is open crashes the game
-Bug #1654: Priority of checks in organic containers
-Bug #1656: Inventory items merge issue when repairing
-Bug #1657: Attacked state of NPCs is not saved properly
-Bug #1660: Rank dialogue condition ignored
-Bug #1668: Game starts on day 2 instead of day 1
-Bug #1669: Critical Strikes while fighting a target who is currently fighting me
-Bug #1672: OpenCS doesn't save the projects
-Bug #1673: Fatigue decreasing by only one point when running
-Bug #1675: Minimap and localmap graphic glitches
-Bug #1676: Pressing the OK button on the travel menu cancels the travel and exits the menu
-Bug #1677: Sleeping in a rented bed is considered a crime
-Bug #1685: NPCs turn towards player even if invisible/sneaking
-Bug #1686: UI bug: cursor is clicking "world/local" map button while inventory window is closed?
-Bug #1690: Double clicking on a inventory window header doesn't close it.
-Bug #1693: Spell Absorption does not absorb shrine blessings
-Bug #1694: journal displays learned topics as quests
-Bug #1700: Sideways scroll of text boxes
-Bug #1701: Player enchanting requires player hold money, always 100% sucessful.
-Bug #1704: self-made Fortify Intelligence/Drain willpower potions are broken
-Bug #1707: Pausing the game through the esc menu will silence rain, pausing it by opening the inventory will not.
-Bug #1709: Remesa Othril is hostile to Hlaalu members
-Bug #1713: Crash on load after death
-Bug #1719: Blind effect has slight border at the edge of the screen where it is ineffective.
-Bug #1722: Crash after creating enchanted item, reloading saved game
-Bug #1723: Content refs that are stacked share the same index after unstacking
-Bug #1726: Can't finish Aengoth the Jeweler's quest : Retrieve the Scrap Metal
-Bug #1727: Targets almost always resist soultrap scrolls
-Bug #1728: Casting a soultrap spell on invalid target yields no message
-Bug #1729: Chop attack doesn't work if walking diagonally
-Bug #1732: Error handling for missing script function arguments produces weird message
-Bug #1736: Alt-tabbing removes detail from overworld map.
-Bug #1737: Going through doors with (high magnitude?) leviation will put the player high up, possibly even out of bounds.
-Bug #1739: Setting a variable on an NPC from another NPC's dialogue result sets the wrong variable
-Bug #1741: The wait dialogue doesn't black the screen out properly during waiting.
-Bug #1742: ERROR: Object 'sDifficulty' not found (const)
-Bug #1744: Night sky in Skies V.IV (& possibly v3) by SWG rendered incorrectly
-Bug #1746: Bow/marksman weapon condition does not degrade with use
-Bug #1749: Constant Battle Music
-Bug #1752: Alt-Tabbing in the character menus makes the paper doll disappear temporarily
-Bug #1753: Cost of training is not added to merchant's inventory
-Bug #1755: Disposition changes do not persist if the conversation menu is closed by purchasing training.
-Bug #1756: Caught Blight after being cured of Corprus
-Bug #1758: Crash Upon Loading New Cell
-Bug #1760: Player's Magicka is not recalculated upon drained or boosted intelligence
-Bug #1761: Equiped torches lost on reload
-Bug #1762: Your spell did not get a target. Soul trap. Gorenea Andrano
-Bug #1763: Custom Spell Magicka Cost
-Bug #1765: Azuras Star breaks on recharging item
-Bug #1767: GetPCRank did not handle ignored explicit references
-Bug #1772: Dark Brotherhood Assassins never use their Carved Ebony Dart, sticking to their melee weapon.
-Bug #1774: String table overflow also occurs when loading TheGloryRoad.esm
-Bug #1776: dagoth uthol runs in slow motion
-Bug #1778: Incorrect values in spellmaking window
-Bug #1779: Icon of Master Propylon Index is not visible
-Bug #1783: Invisible NPC after looting corpse
-Bug #1787: Health Calculation
-Bug #1788: Skeletons, ghosts etc block doors when we try to open
-Bug #1791: [MOD: LGNPC Foreign Quarter] NPC in completely the wrong place.
-Bug #1792: Potions should show more effects
-Bug #1793: Encumbrance while bartering
-Bug #1794: Fortify attribute not affecting fatigue
-Bug #1795: Too much magicka
-Bug #1796: "Off by default" torch burning
-Bug #1797: Fish too slow
-Bug #1798: Rest until healed shouldn't show with full health and magicka
-Bug #1802: Mark location moved
-Bug #1804: stutter with recent builds
-Bug #1810: attack gothens dremora doesnt agro the others.
-Bug #1811: Regression: Crash Upon Loading New Cell
-Bug #1812: Mod: "QuickChar" weird button placement
-Bug #1815: Keys show value and weight, Vanilla Morrowind's keys dont.
-Bug #1817: Persuasion results do not show using unpatched MW ESM
-Bug #1818: Quest B3_ZainabBride moves to stage 47 upon loading save while Falura Llervu is following
-Bug #1823: AI response to theft incorrect - only guards react, in vanilla everyone does.
-Bug #1829: On-Target Spells Rendered Behind Water Surface Effects
-Bug #1830: Galsa Gindu's house is on fire
-Bug #1832: Fatal Error: OGRE Exception(2:InvalidParametersException)
-Bug #1836: Attacked Guards open "fine/jail/resist"-dialogue after killing you
-Bug #1840: Infinite recursion in ActionTeleport
-Bug #1843: Escorted people change into player's cell after completion of escort stage
-Bug #1845: Typing 'j' into 'Name' fields opens the journal
-Bug #1846: Text pasted into the console still appears twice (Windows)
-Bug #1847: "setfatigue 0" doesn't render NPC unconscious
-Bug #1848: I can talk to unconscious actors
-Bug #1866: Crash when player gets killed by a creature summoned by him
-Bug #1868: Memory leaking when openmw window is minimized
-Feature #47: Magic Effects
-Feature #642: Control NPC mouth movement using current Say sound
-Feature #939: Editor: Resources tables
-Feature #961: AI Combat for magic (spells, potions and enchanted items)
-Feature #1111: Collision script instructions (used e.g. by Lava)
-Feature #1120: Command creature/humanoid magic effects
-Feature #1121: Elemental shield magic effects
-Feature #1122: Light magic effect
-Feature #1139: AI: Friendly hits
-Feature #1141: AI: combat party
-Feature #1326: Editor: Add tooltips to all graphical buttons
-Feature #1489: Magic effect Get/Mod/Set functions
-Feature #1505: Difficulty slider
-Feature #1538: Targeted scripts
-Feature #1571: Allow creating custom markers on the local map
-Feature #1615: Determine local variables from compiled scripts instead of the values in the script record
-Feature #1616: Editor: Body part record verifier
-Feature #1651: Editor: Improved keyboard navigation for scene toolbar
-Feature #1666: Script blacklisting
-Feature #1711: Including the Git revision number from the command line "--version" switch.
-Feature #1721: NPC eye blinking
-Feature #1740: Scene toolbar buttons for selecting which type of elements are rendered
-Feature #1790: Mouse wheel scrolling for the journal
-Feature #1850: NiBSPArrayController
-Task #768: On windows, settings folder should be "OpenMW", not "openmw"
-Task #908: Share keyframe data
-Task #1716: Remove defunct option for building without FFmpeg
+------
+
+    Bug #1132: Unable to jump when facing a wall
+    Bug #1341: Summoned Creatures do not immediately disappear when killed.
+    Bug #1430: CharGen Revamped script does not compile
+    Bug #1451: NPCs shouldn't equip weapons prior to fighting
+    Bug #1461: Stopped start scripts do not restart on load
+    Bug #1473: Dead NPC standing and in 2 pieces
+    Bug #1482: Abilities are depleted when interrupted during casting
+    Bug #1503: Behaviour of NPCs facing the player
+    Bug #1506: Missing character, French edition: three-points
+    Bug #1528: Inventory very slow after 2 hours
+    Bug #1540: Extra arguments should be ignored for script functions
+    Bug #1541: Helseth's Champion: Tribunal
+    Bug #1570: Journal cannot be opened while in inventory screen
+    Bug #1573: PC joins factions at random
+    Bug #1576: NPCs aren't switching their weapons when out of ammo
+    Bug #1579: Guards detect creatures in far distance, instead on sight
+    Bug #1588: The Siege of the Skaal Village: bloodmoon
+    Bug #1593: The script compiler isn't recognising some names that contain a -
+    Bug #1606: Books: Question marks instead of quotation marks
+    Bug #1608: Dead bodies prevent door from opening/closing.
+    Bug #1609: Imperial guards in Sadrith Mora are not using their spears
+    Bug #1610: The bounty number is not displayed properly with high numbers
+    Bug #1620: Implement correct formula for auto-calculated NPC spells
+    Bug #1630: Boats standing vertically in Vivec
+    Bug #1635: Arrest dialogue is executed second time after I select "Go to jail"
+    Bug #1637: Weird NPC behaviour in Vivec, Hlaalu Ancestral Vaults?
+    Bug #1641: Persuasion dialog remains after loading, possibly resulting in crash
+    Bug #1644: "Goodbye" and similar options on dialogues prevents escape working properly.
+    Bug #1646: PC skill stats are not updated immediately when changing equipment
+    Bug #1652: Non-aggressive creature
+    Bug #1653: Quickloading while the container window is open crashes the game
+    Bug #1654: Priority of checks in organic containers
+    Bug #1656: Inventory items merge issue when repairing
+    Bug #1657: Attacked state of NPCs is not saved properly
+    Bug #1660: Rank dialogue condition ignored
+    Bug #1668: Game starts on day 2 instead of day 1
+    Bug #1669: Critical Strikes while fighting a target who is currently fighting me
+    Bug #1672: OpenCS doesn't save the projects
+    Bug #1673: Fatigue decreasing by only one point when running
+    Bug #1675: Minimap and localmap graphic glitches
+    Bug #1676: Pressing the OK button on the travel menu cancels the travel and exits the menu
+    Bug #1677: Sleeping in a rented bed is considered a crime
+    Bug #1685: NPCs turn towards player even if invisible/sneaking
+    Bug #1686: UI bug: cursor is clicking "world/local" map button while inventory window is closed?
+    Bug #1690: Double clicking on a inventory window header doesn't close it.
+    Bug #1693: Spell Absorption does not absorb shrine blessings
+    Bug #1694: journal displays learned topics as quests
+    Bug #1700: Sideways scroll of text boxes
+    Bug #1701: Player enchanting requires player hold money, always 100% sucessful.
+    Bug #1704: self-made Fortify Intelligence/Drain willpower potions are broken
+    Bug #1707: Pausing the game through the esc menu will silence rain, pausing it by opening the inventory will not.
+    Bug #1709: Remesa Othril is hostile to Hlaalu members
+    Bug #1713: Crash on load after death
+    Bug #1719: Blind effect has slight border at the edge of the screen where it is ineffective.
+    Bug #1722: Crash after creating enchanted item, reloading saved game
+    Bug #1723: Content refs that are stacked share the same index after unstacking
+    Bug #1726: Can't finish Aengoth the Jeweler's quest : Retrieve the Scrap Metal
+    Bug #1727: Targets almost always resist soultrap scrolls
+    Bug #1728: Casting a soultrap spell on invalid target yields no message
+    Bug #1729: Chop attack doesn't work if walking diagonally
+    Bug #1732: Error handling for missing script function arguments produces weird message
+    Bug #1736: Alt-tabbing removes detail from overworld map.
+    Bug #1737: Going through doors with (high magnitude?) leviation will put the player high up, possibly even out of bounds.
+    Bug #1739: Setting a variable on an NPC from another NPC's dialogue result sets the wrong variable
+    Bug #1741: The wait dialogue doesn't black the screen out properly during waiting.
+    Bug #1742: ERROR: Object 'sDifficulty' not found (const)
+    Bug #1744: Night sky in Skies V.IV (& possibly v3) by SWG rendered incorrectly
+    Bug #1746: Bow/marksman weapon condition does not degrade with use
+    Bug #1749: Constant Battle Music
+    Bug #1752: Alt-Tabbing in the character menus makes the paper doll disappear temporarily
+    Bug #1753: Cost of training is not added to merchant's inventory
+    Bug #1755: Disposition changes do not persist if the conversation menu is closed by purchasing training.
+    Bug #1756: Caught Blight after being cured of Corprus
+    Bug #1758: Crash Upon Loading New Cell
+    Bug #1760: Player's Magicka is not recalculated upon drained or boosted intelligence
+    Bug #1761: Equiped torches lost on reload
+    Bug #1762: Your spell did not get a target. Soul trap. Gorenea Andrano
+    Bug #1763: Custom Spell Magicka Cost
+    Bug #1765: Azuras Star breaks on recharging item
+    Bug #1767: GetPCRank did not handle ignored explicit references
+    Bug #1772: Dark Brotherhood Assassins never use their Carved Ebony Dart, sticking to their melee weapon.
+    Bug #1774: String table overflow also occurs when loading TheGloryRoad.esm
+    Bug #1776: dagoth uthol runs in slow motion
+    Bug #1778: Incorrect values in spellmaking window
+    Bug #1779: Icon of Master Propylon Index is not visible
+    Bug #1783: Invisible NPC after looting corpse
+    Bug #1787: Health Calculation
+    Bug #1788: Skeletons, ghosts etc block doors when we try to open
+    Bug #1791: [MOD: LGNPC Foreign Quarter] NPC in completely the wrong place.
+    Bug #1792: Potions should show more effects
+    Bug #1793: Encumbrance while bartering
+    Bug #1794: Fortify attribute not affecting fatigue
+    Bug #1795: Too much magicka
+    Bug #1796: "Off by default" torch burning
+    Bug #1797: Fish too slow
+    Bug #1798: Rest until healed shouldn't show with full health and magicka
+    Bug #1802: Mark location moved
+    Bug #1804: stutter with recent builds
+    Bug #1810: attack gothens dremora doesnt agro the others.
+    Bug #1811: Regression: Crash Upon Loading New Cell
+    Bug #1812: Mod: "QuickChar" weird button placement
+    Bug #1815: Keys show value and weight, Vanilla Morrowind's keys dont.
+    Bug #1817: Persuasion results do not show using unpatched MW ESM
+    Bug #1818: Quest B3_ZainabBride moves to stage 47 upon loading save while Falura Llervu is following
+    Bug #1823: AI response to theft incorrect - only guards react, in vanilla everyone does.
+    Bug #1829: On-Target Spells Rendered Behind Water Surface Effects
+    Bug #1830: Galsa Gindu's house is on fire
+    Bug #1832: Fatal Error: OGRE Exception(2:InvalidParametersException)
+    Bug #1836: Attacked Guards open "fine/jail/resist"-dialogue after killing you
+    Bug #1840: Infinite recursion in ActionTeleport
+    Bug #1843: Escorted people change into player's cell after completion of escort stage
+    Bug #1845: Typing 'j' into 'Name' fields opens the journal
+    Bug #1846: Text pasted into the console still appears twice (Windows)
+    Bug #1847: "setfatigue 0" doesn't render NPC unconscious
+    Bug #1848: I can talk to unconscious actors
+    Bug #1866: Crash when player gets killed by a creature summoned by him
+    Bug #1868: Memory leaking when openmw window is minimized
+    Feature #47: Magic Effects
+    Feature #642: Control NPC mouth movement using current Say sound
+    Feature #939: Editor: Resources tables
+    Feature #961: AI Combat for magic (spells, potions and enchanted items)
+    Feature #1111: Collision script instructions (used e.g. by Lava)
+    Feature #1120: Command creature/humanoid magic effects
+    Feature #1121: Elemental shield magic effects
+    Feature #1122: Light magic effect
+    Feature #1139: AI: Friendly hits
+    Feature #1141: AI: combat party
+    Feature #1326: Editor: Add tooltips to all graphical buttons
+    Feature #1489: Magic effect Get/Mod/Set functions
+    Feature #1505: Difficulty slider
+    Feature #1538: Targeted scripts
+    Feature #1571: Allow creating custom markers on the local map
+    Feature #1615: Determine local variables from compiled scripts instead of the values in the script record
+    Feature #1616: Editor: Body part record verifier
+    Feature #1651: Editor: Improved keyboard navigation for scene toolbar
+    Feature #1666: Script blacklisting
+    Feature #1711: Including the Git revision number from the command line "--version" switch.
+    Feature #1721: NPC eye blinking
+    Feature #1740: Scene toolbar buttons for selecting which type of elements are rendered
+    Feature #1790: Mouse wheel scrolling for the journal
+    Feature #1850: NiBSPArrayController
+    Task #768: On windows, settings folder should be "OpenMW", not "openmw"
+    Task #908: Share keyframe data
+    Task #1716: Remove defunct option for building without FFmpeg
 
 0.31.0
-
-Bug #245: Cloud direction and weather systems differ from Morrowind
-Bug #275: Local Map does not always show objects that span multiple cells
-Bug #538: Update CenterOnCell (COC) function behavior
-Bug #618: Local and World Map Textures are sometimes Black
-Bug #640: Water behaviour at night
-Bug #668: OpenMW doesn't support non-latin paths on Windows
-Bug #746: OpenMW doesn't check if the background music was already played
-Bug #747: Door is stuck if cell is left before animation finishes
-Bug #772: Disabled statics are visible on map
-Bug #829: OpenMW uses up all available vram, when playing for extended time
-Bug #869: Dead bodies don't collide with anything
-Bug #894: Various character creation issues
-Bug #897/#1369: opencs Segmentation Fault after "new" or "load"
-Bug #899: Various jumping issues
-Bug #952: Reflection effects are one frame delayed
-Bug #993: Able to interact with world during Wait/Rest dialog
-Bug #995: Dropped items can be placed inside the wall
-Bug #1008: Corpses always face up upon reentering the cell
-Bug #1035: Random colour patterns appearing in automap
-Bug #1037: Footstep volume issues
-Bug #1047: Creation of wrong links in dialogue window
-Bug #1129: Summoned creature time life duration seems infinite
-Bug #1134: Crimes can be committed against hostile NPCs
-Bug #1136: Creature run speed formula is incorrect
-Bug #1150: Weakness to Fire doesn't apply to Fire Damage in the same spell
-Bug #1155: NPCs killing each other
-Bug #1166: Bittercup script still does not work
-Bug #1178: .bsa file names are case sensitive.
-Bug #1179: Crash after trying to load game after being killed
-Bug #1180: Changing footstep sound location
-Bug #1196: Jumping not disabled when showing messageboxes
-Bug #1202: "strange" keys are not shown in binding menu, and are not saved either, but works
-Bug #1216: Broken dialog topics in russian Morrowind
-Bug #1217: Container content changes based on the current position of the mouse
-Bug #1234: Loading/saving issues with dynamic records
-Bug #1277: Text pasted into the console appears twice
-Bug #1284: Crash on New Game
-Bug #1303: It's possible to skip the chargen
-Bug #1304: Slaughterfish should not detect the player unless the player is in the water
-Bug #1311: Editor: deleting Record Filter line does not reset the filter
-Bug #1324: ERROR: ESM Error: String table overflow when loading Animated Morrowind.esp
-Bug #1328: Editor: Bogus Filter created when dragging multiple records to filter bar of non-applicable table
-Bug #1331: Walking/running sound persist after killing NPC`s that are walking/running.
-Bug #1334: Previously equipped items not shown as unequipped after attempting to sell them.
-Bug #1335: Actors ignore vertical axis when deciding to attack
-Bug #1338: Unknown toggle option for shadows
-Bug #1339: "Ashlands Region" is visible when beginning new game during "Loading Area" process
-Bug #1340: Guards prompt Player with punishment options after resisting arrest with another guard.
-Bug #1348: Regression: Bug #1098 has returned with a vengeance
-Bug #1349: [TR] TR_Data mesh tr_ex_imp_gatejamb01 cannot be activated
-Bug #1352: Disabling an ESX file does not disable dependent ESX files
-Bug #1355: CppCat Checks OpenMW
-Bug #1356: Incorrect voice type filtering for sleep interrupts
-Bug #1357: Restarting the game clears saves
-Bug #1360: Seyda Neen silk rider dialog problem
-Bug #1361: Some lights don't work
-Bug #1364: It is difficult to bind "Mouse 1" to an action in the options menu
-Bug #1370: Animation compilation mod does not work properly
-Bug #1371: SL_Pick01.nif from third party fails to load in openmw, but works in Vanilla
-Bug #1373: When stealing in front of Sellus Gravius cannot exit the dialog
-Bug #1378: Installs to /usr/local are not working
-Bug #1380: Loading a save file fail if one of the content files is disabled
-Bug #1382: "getHExact() size mismatch" crash on loading official plugin "Siege at Firemoth.esp"
-Bug #1386: Arkngthand door will not open
-Bug #1388: Segfault when modifying View Distance in Menu options
-Bug #1389: Crash when loading a save after dying
-Bug #1390: Apostrophe characters not displayed [French version]
-Bug #1391: Custom made icon background texture for magical weapons and stuff isn't scaled properly on GUI.
-Bug #1393: Coin icon during the level up dialogue are off of the background
-Bug #1394: Alt+F4 doesn't work on Win version
-Bug #1395: Changing rings switches only the last one put on
-Bug #1396: Pauldron parts aren't showing when the robe is equipped
-Bug #1402: Dialogue of some shrines have wrong button orientation
-Bug #1403: Items are floating in the air when they're dropped onto dead bodies.
-Bug #1404: Forearms are not rendered on Argonian females
-Bug #1407: Alchemy allows making potions from two of the same item
-Bug #1408: "Max sale" button gives you all the items AND all the trader's gold
-Bug #1409: Rest "Until Healed" broken for characters with stunted magicka.
-Bug #1412: Empty travel window opens while playing through start game
-Bug #1413: Save game ignores missing writing permission
-Bug #1414: The Underground 2 ESM Error
-Bug #1416: Not all splash screens in the Splash directory are used
-Bug #1417: Loading saved game does not terminate
-Bug #1419: Skyrim: Home of the Nords error
-Bug #1422: ClearInfoActor
-Bug #1423: ForceGreeting closes existing dialogue windows
-Bug #1425: Cannot load save game
-Bug #1426: Read skill books aren't stored in savegame
-Bug #1427: Useless items can be set under hotkeys
-Bug #1429: Text variables in journal
-Bug #1432: When attacking friendly NPC, the crime is reported and bounty is raised after each swing
-Bug #1435: Stealing priceless items is without punishment
-Bug #1437: Door marker at Jobasha's Rare Books is spawning PC in the air
-Bug #1440: Topic selection menu should be wider
-Bug #1441: Dropping items on the rug makes them inaccessible
-Bug #1442: When dropping and taking some looted items, bystanders consider that as a crime
-Bug #1444: Arrows and bolts are not dropped where the cursor points
-Bug #1445: Security trainers offering acrobatics instead
-Bug #1447: Character dash not displayed, French edition
-Bug #1448: When the player is killed by the guard while having a bounty on his head, the guard dialogue opens over and over instead of loading dialogue
-Bug #1454: Script error in SkipTutorial
-Bug #1456: Bad lighting when using certain Morrowind.ini generated by MGE
-Bug #1457: Heart of Lorkan comes after you when attacking it
-Bug #1458: Modified Keybindings are not remembered
-Bug #1459: Dura Gra-Bol doesn't respond to PC attack
-Bug #1462: Interior cells not loaded with Morrowind Patch active
-Bug #1469: Item tooltip should show the base value, not real value
-Bug #1477: Death count is not stored in savegame
-Bug #1478: AiActivate does not trigger activate scripts
-Bug #1481: Weapon not rendered when partially submerged in water
-Bug #1483: Enemies are attacking even while dying
-Bug #1486: ESM Error: Don't know what to do with INFO
-Bug #1490: Arrows shot at PC can end up in inventory
-Bug #1492: Monsters respawn on top of one another
-Bug #1493: Dialogue box opens with follower NPC even if NPC is dead
-Bug #1494: Paralysed cliffracers remain airbourne
-Bug #1495: Dialogue box opens with follower NPC even the game is paused
-Bug #1496: GUI messages are not cleared when loading another saved game
-Bug #1499: Underwater sound sometimes plays when transitioning from interior.
-Bug #1500: Targetted spells and water.
-Bug #1502: Console error message on info refusal
-Bug #1507: Bloodmoon MQ The Ritual of Beasts: Can't remove the arrow
-Bug #1508: Bloodmoon: Fort Frostmoth, cant talk with Carnius Magius
-Bug #1516: PositionCell doesn't move actors to current cell
-Bug #1518: ForceGreeting broken for explicit references
-Bug #1522: Crash after attempting to play non-music file
-Bug #1523: World map empty after loading interior save
-Bug #1524: Arrows in waiting/resting dialog act like minimum and maximum buttons
-Bug #1525: Werewolf: Killed NPC's don't fill werewolfs hunger for blood
-Bug #1527: Werewolf: Detect life detects wrong type of actor
-Bug #1529: OpenMW crash during "the shrine of the dead" mission (tribunal)
-Bug #1530: Selected text in the console has the same color as the background
-Bug #1539: Barilzar's Mazed Band: Tribunal
-Bug #1542: Looping taunts from NPC`s after death: Tribunal
-Bug #1543: OpenCS crash when using drag&drop in script editor
-Bug #1547: Bamz-Amschend: Centurion Archers combat problem
-Bug #1548: The Missing Hand: Tribunal
-Bug #1549: The Mad God: Tribunal, Dome of Serlyn
-Bug #1557: A bounty is calculated from actual item cost
-Bug #1562: Invisible terrain on top of Red Mountain
-Bug #1564: Cave of the hidden music: Bloodmoon
-Bug #1567: Editor: Deleting of referenceables does not work
-Bug #1568: Picking up a stack of items and holding the enter key and moving your mouse around paints a bunch of garbage on screen.
-Bug #1574: Solstheim: Drauger cant inflict damage on player
-Bug #1578: Solstheim: Bonewolf running animation not working
-Bug #1585: Particle effects on PC are stopped when paralyzed
-Bug #1589: Tribunal: Crimson Plague quest does not update when Gedna Relvel is killed
-Bug #1590: Failed to save game: compile error
-Bug #1598: Segfault when making Drain/Fortify Skill spells
-Bug #1599: Unable to switch to fullscreen
-Bug #1613: Morrowind Rebirth duplicate objects / vanilla objects not removed
-Bug #1618: Death notice fails to show up
-Bug #1628: Alt+Tab Segfault
-Feature #32: Periodic Cleanup/Refill
-Feature #41: Precipitation and weather particles
-Feature #568: Editor: Configuration setup
-Feature #649: Editor: Threaded loading
-Feature #930: Editor: Cell record saving
-Feature #934: Editor: Body part table
-Feature #935: Editor: Enchantment effect table
-Feature #1162: Dialogue merging
-Feature #1174: Saved Game: add missing creature state
-Feature #1177: Saved Game: fog of war state
-Feature #1312: Editor: Combat/Magic/Stealth values for creatures are not displayed
-Feature #1314: Make NPCs and creatures fight each other
-Feature #1315: Crime: Murder
-Feature #1321: Sneak skill enhancements
-Feature #1323: Handle restocking items
-Feature #1332: Saved Game: levelled creatures
-Feature #1347: modFactionReaction script instruction
-Feature #1362: Animated main menu support
-Feature #1433: Store walk/run toggle
-Feature #1449: Use names instead of numbers for saved game files and folders
-Feature #1453: Adding Delete button to the load menu
-Feature #1460: Enable Journal screen while in dialogue
-Feature #1480: Play Battle music when in combat
-Feature #1501: Followers unable to fast travel with you
-Feature #1520: Disposition and distance-based aggression/ShouldAttack
-Feature #1595: Editor: Object rendering in cells
-Task #940: Move license to locations where applicable
-Task #1333: Remove cmake git tag reading
-Task #1566: Editor: Object rendering refactoring
+------
+
+    Bug #245: Cloud direction and weather systems differ from Morrowind
+    Bug #275: Local Map does not always show objects that span multiple cells
+    Bug #538: Update CenterOnCell (COC) function behavior
+    Bug #618: Local and World Map Textures are sometimes Black
+    Bug #640: Water behaviour at night
+    Bug #668: OpenMW doesn't support non-latin paths on Windows
+    Bug #746: OpenMW doesn't check if the background music was already played
+    Bug #747: Door is stuck if cell is left before animation finishes
+    Bug #772: Disabled statics are visible on map
+    Bug #829: OpenMW uses up all available vram, when playing for extended time
+    Bug #869: Dead bodies don't collide with anything
+    Bug #894: Various character creation issues
+    Bug #897/#1369: opencs Segmentation Fault after "new" or "load"
+    Bug #899: Various jumping issues
+    Bug #952: Reflection effects are one frame delayed
+    Bug #993: Able to interact with world during Wait/Rest dialog
+    Bug #995: Dropped items can be placed inside the wall
+    Bug #1008: Corpses always face up upon reentering the cell
+    Bug #1035: Random colour patterns appearing in automap
+    Bug #1037: Footstep volume issues
+    Bug #1047: Creation of wrong links in dialogue window
+    Bug #1129: Summoned creature time life duration seems infinite
+    Bug #1134: Crimes can be committed against hostile NPCs
+    Bug #1136: Creature run speed formula is incorrect
+    Bug #1150: Weakness to Fire doesn't apply to Fire Damage in the same spell
+    Bug #1155: NPCs killing each other
+    Bug #1166: Bittercup script still does not work
+    Bug #1178: .bsa file names are case sensitive.
+    Bug #1179: Crash after trying to load game after being killed
+    Bug #1180: Changing footstep sound location
+    Bug #1196: Jumping not disabled when showing messageboxes
+    Bug #1202: "strange" keys are not shown in binding menu, and are not saved either, but works
+    Bug #1216: Broken dialog topics in russian Morrowind
+    Bug #1217: Container content changes based on the current position of the mouse
+    Bug #1234: Loading/saving issues with dynamic records
+    Bug #1277: Text pasted into the console appears twice
+    Bug #1284: Crash on New Game
+    Bug #1303: It's possible to skip the chargen
+    Bug #1304: Slaughterfish should not detect the player unless the player is in the water
+    Bug #1311: Editor: deleting Record Filter line does not reset the filter
+    Bug #1324: ERROR: ESM Error: String table overflow when loading Animated Morrowind.esp
+    Bug #1328: Editor: Bogus Filter created when dragging multiple records to filter bar of non-applicable table
+    Bug #1331: Walking/running sound persist after killing NPC`s that are walking/running.
+    Bug #1334: Previously equipped items not shown as unequipped after attempting to sell them.
+    Bug #1335: Actors ignore vertical axis when deciding to attack
+    Bug #1338: Unknown toggle option for shadows
+    Bug #1339: "Ashlands Region" is visible when beginning new game during "Loading Area" process
+    Bug #1340: Guards prompt Player with punishment options after resisting arrest with another guard.
+    Bug #1348: Regression: Bug #1098 has returned with a vengeance
+    Bug #1349: [TR] TR_Data mesh tr_ex_imp_gatejamb01 cannot be activated
+    Bug #1352: Disabling an ESX file does not disable dependent ESX files
+    Bug #1355: CppCat Checks OpenMW
+    Bug #1356: Incorrect voice type filtering for sleep interrupts
+    Bug #1357: Restarting the game clears saves
+    Bug #1360: Seyda Neen silk rider dialog problem
+    Bug #1361: Some lights don't work
+    Bug #1364: It is difficult to bind "Mouse 1" to an action in the options menu
+    Bug #1370: Animation compilation mod does not work properly
+    Bug #1371: SL_Pick01.nif from third party fails to load in openmw, but works in Vanilla
+    Bug #1373: When stealing in front of Sellus Gravius cannot exit the dialog
+    Bug #1378: Installs to /usr/local are not working
+    Bug #1380: Loading a save file fail if one of the content files is disabled
+    Bug #1382: "getHExact() size mismatch" crash on loading official plugin "Siege at Firemoth.esp"
+    Bug #1386: Arkngthand door will not open
+    Bug #1388: Segfault when modifying View Distance in Menu options
+    Bug #1389: Crash when loading a save after dying
+    Bug #1390: Apostrophe characters not displayed [French version]
+    Bug #1391: Custom made icon background texture for magical weapons and stuff isn't scaled properly on GUI.
+    Bug #1393: Coin icon during the level up dialogue are off of the background
+    Bug #1394: Alt+F4 doesn't work on Win version
+    Bug #1395: Changing rings switches only the last one put on
+    Bug #1396: Pauldron parts aren't showing when the robe is equipped
+    Bug #1402: Dialogue of some shrines have wrong button orientation
+    Bug #1403: Items are floating in the air when they're dropped onto dead bodies.
+    Bug #1404: Forearms are not rendered on Argonian females
+    Bug #1407: Alchemy allows making potions from two of the same item
+    Bug #1408: "Max sale" button gives you all the items AND all the trader's gold
+    Bug #1409: Rest "Until Healed" broken for characters with stunted magicka.
+    Bug #1412: Empty travel window opens while playing through start game
+    Bug #1413: Save game ignores missing writing permission
+    Bug #1414: The Underground 2 ESM Error
+    Bug #1416: Not all splash screens in the Splash directory are used
+    Bug #1417: Loading saved game does not terminate
+    Bug #1419: Skyrim: Home of the Nords error
+    Bug #1422: ClearInfoActor
+    Bug #1423: ForceGreeting closes existing dialogue windows
+    Bug #1425: Cannot load save game
+    Bug #1426: Read skill books aren't stored in savegame
+    Bug #1427: Useless items can be set under hotkeys
+    Bug #1429: Text variables in journal
+    Bug #1432: When attacking friendly NPC, the crime is reported and bounty is raised after each swing
+    Bug #1435: Stealing priceless items is without punishment
+    Bug #1437: Door marker at Jobasha's Rare Books is spawning PC in the air
+    Bug #1440: Topic selection menu should be wider
+    Bug #1441: Dropping items on the rug makes them inaccessible
+    Bug #1442: When dropping and taking some looted items, bystanders consider that as a crime
+    Bug #1444: Arrows and bolts are not dropped where the cursor points
+    Bug #1445: Security trainers offering acrobatics instead
+    Bug #1447: Character dash not displayed, French edition
+    Bug #1448: When the player is killed by the guard while having a bounty on his head, the guard dialogue opens over and over instead of loading dialogue
+    Bug #1454: Script error in SkipTutorial
+    Bug #1456: Bad lighting when using certain Morrowind.ini generated by MGE
+    Bug #1457: Heart of Lorkan comes after you when attacking it
+    Bug #1458: Modified Keybindings are not remembered
+    Bug #1459: Dura Gra-Bol doesn't respond to PC attack
+    Bug #1462: Interior cells not loaded with Morrowind Patch active
+    Bug #1469: Item tooltip should show the base value, not real value
+    Bug #1477: Death count is not stored in savegame
+    Bug #1478: AiActivate does not trigger activate scripts
+    Bug #1481: Weapon not rendered when partially submerged in water
+    Bug #1483: Enemies are attacking even while dying
+    Bug #1486: ESM Error: Don't know what to do with INFO
+    Bug #1490: Arrows shot at PC can end up in inventory
+    Bug #1492: Monsters respawn on top of one another
+    Bug #1493: Dialogue box opens with follower NPC even if NPC is dead
+    Bug #1494: Paralysed cliffracers remain airbourne
+    Bug #1495: Dialogue box opens with follower NPC even the game is paused
+    Bug #1496: GUI messages are not cleared when loading another saved game
+    Bug #1499: Underwater sound sometimes plays when transitioning from interior.
+    Bug #1500: Targetted spells and water.
+    Bug #1502: Console error message on info refusal
+    Bug #1507: Bloodmoon MQ The Ritual of Beasts: Can't remove the arrow
+    Bug #1508: Bloodmoon: Fort Frostmoth, cant talk with Carnius Magius
+    Bug #1516: PositionCell doesn't move actors to current cell
+    Bug #1518: ForceGreeting broken for explicit references
+    Bug #1522: Crash after attempting to play non-music file
+    Bug #1523: World map empty after loading interior save
+    Bug #1524: Arrows in waiting/resting dialog act like minimum and maximum buttons
+    Bug #1525: Werewolf: Killed NPC's don't fill werewolfs hunger for blood
+    Bug #1527: Werewolf: Detect life detects wrong type of actor
+    Bug #1529: OpenMW crash during "the shrine of the dead" mission (tribunal)
+    Bug #1530: Selected text in the console has the same color as the background
+    Bug #1539: Barilzar's Mazed Band: Tribunal
+    Bug #1542: Looping taunts from NPC`s after death: Tribunal
+    Bug #1543: OpenCS crash when using drag&drop in script editor
+    Bug #1547: Bamz-Amschend: Centurion Archers combat problem
+    Bug #1548: The Missing Hand: Tribunal
+    Bug #1549: The Mad God: Tribunal, Dome of Serlyn
+    Bug #1557: A bounty is calculated from actual item cost
+    Bug #1562: Invisible terrain on top of Red Mountain
+    Bug #1564: Cave of the hidden music: Bloodmoon
+    Bug #1567: Editor: Deleting of referenceables does not work
+    Bug #1568: Picking up a stack of items and holding the enter key and moving your mouse around paints a bunch of garbage on screen.
+    Bug #1574: Solstheim: Drauger cant inflict damage on player
+    Bug #1578: Solstheim: Bonewolf running animation not working
+    Bug #1585: Particle effects on PC are stopped when paralyzed
+    Bug #1589: Tribunal: Crimson Plague quest does not update when Gedna Relvel is killed
+    Bug #1590: Failed to save game: compile error
+    Bug #1598: Segfault when making Drain/Fortify Skill spells
+    Bug #1599: Unable to switch to fullscreen
+    Bug #1613: Morrowind Rebirth duplicate objects / vanilla objects not removed
+    Bug #1618: Death notice fails to show up
+    Bug #1628: Alt+Tab Segfault
+    Feature #32: Periodic Cleanup/Refill
+    Feature #41: Precipitation and weather particles
+    Feature #568: Editor: Configuration setup
+    Feature #649: Editor: Threaded loading
+    Feature #930: Editor: Cell record saving
+    Feature #934: Editor: Body part table
+    Feature #935: Editor: Enchantment effect table
+    Feature #1162: Dialogue merging
+    Feature #1174: Saved Game: add missing creature state
+    Feature #1177: Saved Game: fog of war state
+    Feature #1312: Editor: Combat/Magic/Stealth values for creatures are not displayed
+    Feature #1314: Make NPCs and creatures fight each other
+    Feature #1315: Crime: Murder
+    Feature #1321: Sneak skill enhancements
+    Feature #1323: Handle restocking items
+    Feature #1332: Saved Game: levelled creatures
+    Feature #1347: modFactionReaction script instruction
+    Feature #1362: Animated main menu support
+    Feature #1433: Store walk/run toggle
+    Feature #1449: Use names instead of numbers for saved game files and folders
+    Feature #1453: Adding Delete button to the load menu
+    Feature #1460: Enable Journal screen while in dialogue
+    Feature #1480: Play Battle music when in combat
+    Feature #1501: Followers unable to fast travel with you
+    Feature #1520: Disposition and distance-based aggression/ShouldAttack
+    Feature #1595: Editor: Object rendering in cells
+    Task #940: Move license to locations where applicable
+    Task #1333: Remove cmake git tag reading
+    Task #1566: Editor: Object rendering refactoring
 
 0.30.0
-
-Bug #416: Extreme shaking can occur during cell transitions while moving
-Bug #1003: Province Cyrodiil: Ogre Exception in Stirk
-Bug #1071: Crash when given a non-existent content file
-Bug #1080: OpenMW allows resting/using a bed while in combat
-Bug #1097: Wrong punishment for stealing in Census and Excise Office at the start of a new game
-Bug #1098: Unlocked evidence chests should get locked after new evidence is put into them
-Bug #1099: NPCs that you attacked still fight you after you went to jail/paid your fine
-Bug #1100: Taking items from a corpse is considered stealing
-Bug #1126: Some creatures can't get close enough to attack
-Bug #1144: Killed creatures seem to die again each time player transitions indoors/outdoors
-Bug #1181: loading a saved game does not reset the player control status
-Bug #1185: Collision issues in Addamasartus
-Bug #1187: Athyn Sarethi mission, rescuing varvur sarethi from the doesnt end the mission
-Bug #1189: Crash when entering interior cell "Gnisis, Arvs-Drelen"
-Bug #1191: Picking up papers without inventory in new game
-Bug #1195: NPCs do not equip torches in certain interiors
-Bug #1197: mouse wheel makes things scroll too fast
-Bug #1200: door blocked by monsters
-Bug #1201: item's magical charges are only refreshed when they are used
-Bug #1203: Scribs do not defend themselves
-Bug #1204: creatures life is not empty when they are dead
-Bug #1205: armor experience does not progress when hits are taken
-Bug #1206: blood particules always red. Undeads and mechanicals should have a different one.
-Bug #1209: Tarhiel never falls
-Bug #1210: journal adding script is ran again after having saved/loaded
-Bug #1224: Names of custom classes are not properly handled in save games
-Bug #1227: Editor: Fixed case handling for broken localised versions of Morrowind.esm
-Bug #1235: Indoors walk stutter
-Bug #1236: Aborting intro movie brings up the menu
-Bug #1239: NPCs get stuck when walking past each other
-Bug #1240: BTB - Settings 14.1 and Health Bar.
-Bug #1241: BTB - Character and Khajiit Prejudice
-Bug #1248: GUI Weapon icon is changed to hand-to-hand after save load
-Bug #1254: Guild ranks do not show in dialogue
-Bug #1255: When opening a container and selecting "Take All", the screen flashes blue
-Bug #1260: Level Up menu doesn't show image when using a custom class
-Bug #1265: Quit Menu Has Misaligned Buttons
-Bug #1270: Active weapon icon is not updated when weapon is repaired
-Bug #1271: NPC Stuck in hovering "Jumping" animation
-Bug #1272: Crash when attempting to load Big City esm file.
-Bug #1276: Editor: Dropping a region into the filter of a cell subview fails
-Bug #1286: Dialogue topic list clips with window frame
-Bug #1291: Saved game: store faction membership
-Bug #1293: Pluginless Khajiit Head Pack by ashiraniir makes OpenMW close.
-Bug #1294: Pasting in console adds text to end, not at cursor
-Bug #1295: Conversation loop when asking about "specific place" in Vivec
-Bug #1296: Caius doesn't leave at start of quest "Mehra Milo and the Lost Prophecies"
-Bug #1297: Saved game: map markers
-Bug #1302: ring_keley script causes vector::_M_range_check exception
-Bug #1309: Bug on "You violated the law" dialog
-Bug #1319: Creatures sometimes rendered incorrectly
-Feature #50: Ranged Combat
-Feature #58: Sneaking Skill
-Feature #73: Crime and Punishment
-Feature #135: Editor: OGRE integration
-Feature #541: Editor: Dialogue Sub-Views
-Feature #853: Editor: Rework User Settings
-Feature #944: Editor: lighting modes
-Feature #945: Editor: Camera navigation mode
-Feature #953: Trader gold
-Feature #1140: AI: summoned creatures
-Feature #1142: AI follow: Run stance
-Feature #1154: Not all NPCs get aggressive when one is attacked
-Feature #1169: Terrain threading
-Feature #1172: Loading screen and progress bars during saved/loading game
-Feature #1173: Saved Game: include weather state
-Feature #1207: Class creation form does not remember
-Feature #1220: Editor: Preview Subview
-Feature #1223: Saved Game: Local Variables
-Feature #1229: Quicksave, quickload, autosave
-Feature #1230: Deleting saves
-Feature #1233: Bribe gold is placed into NPCs inventory
-Feature #1252: Saved Game: quick key bindings
-Feature #1273: Editor: Region Map context menu
-Feature #1274: Editor: Region Map drag & drop
-Feature #1275: Editor: Scene subview drop
-Feature #1282: Non-faction member crime recognition.
-Feature #1289: NPCs return to default position
-Task #941: Remove unused cmake files
+------
+
+    Bug #416: Extreme shaking can occur during cell transitions while moving
+    Bug #1003: Province Cyrodiil: Ogre Exception in Stirk
+    Bug #1071: Crash when given a non-existent content file
+    Bug #1080: OpenMW allows resting/using a bed while in combat
+    Bug #1097: Wrong punishment for stealing in Census and Excise Office at the start of a new game
+    Bug #1098: Unlocked evidence chests should get locked after new evidence is put into them
+    Bug #1099: NPCs that you attacked still fight you after you went to jail/paid your fine
+    Bug #1100: Taking items from a corpse is considered stealing
+    Bug #1126: Some creatures can't get close enough to attack
+    Bug #1144: Killed creatures seem to die again each time player transitions indoors/outdoors
+    Bug #1181: loading a saved game does not reset the player control status
+    Bug #1185: Collision issues in Addamasartus
+    Bug #1187: Athyn Sarethi mission, rescuing varvur sarethi from the doesnt end the mission
+    Bug #1189: Crash when entering interior cell "Gnisis, Arvs-Drelen"
+    Bug #1191: Picking up papers without inventory in new game
+    Bug #1195: NPCs do not equip torches in certain interiors
+    Bug #1197: mouse wheel makes things scroll too fast
+    Bug #1200: door blocked by monsters
+    Bug #1201: item's magical charges are only refreshed when they are used
+    Bug #1203: Scribs do not defend themselves
+    Bug #1204: creatures life is not empty when they are dead
+    Bug #1205: armor experience does not progress when hits are taken
+    Bug #1206: blood particules always red. Undeads and mechanicals should have a different one.
+    Bug #1209: Tarhiel never falls
+    Bug #1210: journal adding script is ran again after having saved/loaded
+    Bug #1224: Names of custom classes are not properly handled in save games
+    Bug #1227: Editor: Fixed case handling for broken localised versions of Morrowind.esm
+    Bug #1235: Indoors walk stutter
+    Bug #1236: Aborting intro movie brings up the menu
+    Bug #1239: NPCs get stuck when walking past each other
+    Bug #1240: BTB - Settings 14.1 and Health Bar.
+    Bug #1241: BTB - Character and Khajiit Prejudice
+    Bug #1248: GUI Weapon icon is changed to hand-to-hand after save load
+    Bug #1254: Guild ranks do not show in dialogue
+    Bug #1255: When opening a container and selecting "Take All", the screen flashes blue
+    Bug #1260: Level Up menu doesn't show image when using a custom class
+    Bug #1265: Quit Menu Has Misaligned Buttons
+    Bug #1270: Active weapon icon is not updated when weapon is repaired
+    Bug #1271: NPC Stuck in hovering "Jumping" animation
+    Bug #1272: Crash when attempting to load Big City esm file.
+    Bug #1276: Editor: Dropping a region into the filter of a cell subview fails
+    Bug #1286: Dialogue topic list clips with window frame
+    Bug #1291: Saved game: store faction membership
+    Bug #1293: Pluginless Khajiit Head Pack by ashiraniir makes OpenMW close.
+    Bug #1294: Pasting in console adds text to end, not at cursor
+    Bug #1295: Conversation loop when asking about "specific place" in Vivec
+    Bug #1296: Caius doesn't leave at start of quest "Mehra Milo and the Lost Prophecies"
+    Bug #1297: Saved game: map markers
+    Bug #1302: ring_keley script causes vector::_M_range_check exception
+    Bug #1309: Bug on "You violated the law" dialog
+    Bug #1319: Creatures sometimes rendered incorrectly
+    Feature #50: Ranged Combat
+    Feature #58: Sneaking Skill
+    Feature #73: Crime and Punishment
+    Feature #135: Editor: OGRE integration
+    Feature #541: Editor: Dialogue Sub-Views
+    Feature #853: Editor: Rework User Settings
+    Feature #944: Editor: lighting modes
+    Feature #945: Editor: Camera navigation mode
+    Feature #953: Trader gold
+    Feature #1140: AI: summoned creatures
+    Feature #1142: AI follow: Run stance
+    Feature #1154: Not all NPCs get aggressive when one is attacked
+    Feature #1169: Terrain threading
+    Feature #1172: Loading screen and progress bars during saved/loading game
+    Feature #1173: Saved Game: include weather state
+    Feature #1207: Class creation form does not remember
+    Feature #1220: Editor: Preview Subview
+    Feature #1223: Saved Game: Local Variables
+    Feature #1229: Quicksave, quickload, autosave
+    Feature #1230: Deleting saves
+    Feature #1233: Bribe gold is placed into NPCs inventory
+    Feature #1252: Saved Game: quick key bindings
+    Feature #1273: Editor: Region Map context menu
+    Feature #1274: Editor: Region Map drag & drop
+    Feature #1275: Editor: Scene subview drop
+    Feature #1282: Non-faction member crime recognition.
+    Feature #1289: NPCs return to default position
+    Task #941: Remove unused cmake files
 
 0.29.0
-
-Bug #556: Video soundtrack not played when music volume is set to zero
-Bug #829: OpenMW uses up all available vram, when playing for extended time
-Bug #848: Wrong amount of footsteps playing in 1st person
-Bug #888: Ascended Sleepers have movement issues
-Bug #892: Explicit references are allowed on all script functions
-Bug #999: Graphic Herbalism (mod): sometimes doesn't activate properly
-Bug #1009: Lake Fjalding AI related slowdown.
-Bug #1041: Music playback issues on OS X >= 10.9
-Bug #1043: No message box when advancing skill "Speechcraft" while in dialog window
-Bug #1060: Some message boxes are cut off at the bottom
-Bug #1062: Bittercup script does not work ('end' variable)
-Bug #1074: Inventory paperdoll obscures armour rating
-Bug #1077: Message after killing an essential NPC disappears too fast
-Bug #1078: "Clutterbane" shows empty charge bar
-Bug #1083: UndoWerewolf fails
-Bug #1088: Better Clothes Bloodmoon Plus 1.5 by Spirited Treasure pants are not rendered
-Bug #1090: Start scripts fail when going to a non-predefined cell
-Bug #1091: Crash: Assertion `!q.isNaN() && "Invalid orientation supplied as parameter"' failed.
-Bug #1093: Weapons of aggressive NPCs are invisible after you exit and re-enter interior
-Bug #1105: Magicka is depleted when using uncastable spells
-Bug #1106: Creatures should be able to run
-Bug #1107: TR cliffs have way too huge collision boxes in OpenMW
-Bug #1109: Cleaning True Light and Darkness with Tes3cmd makes Addamasartus , Zenarbael and Yasamsi flooded.
-Bug #1114: Bad output for desktop-file-validate on openmw.desktop (and opencs.desktop)
-Bug #1115: Memory leak when spying on Fargoth
-Bug #1137: Script execution fails (drenSlaveOwners script)
-Bug #1143: Mehra Milo quest (vivec informants) is broken
-Bug #1145: Issues with moving gold between inventory and containers
-Bug #1146: Issues with picking up stacks of gold
-Bug #1147: Dwemer Crossbows are held incorrectly
-Bug #1158: Armor rating should always stay below inventory mannequin
-Bug #1159: Quick keys can be set during character generation
-Bug #1160: Crash on equip lockpick when
-Bug #1167: Editor: Referenceables are not correctly loaded when dealing with more than one content file
-Bug #1184: Game Save: overwriting an existing save does not actually overwrites the file
-Feature #30: Loading/Saving (still missing a few parts)
-Feature #101: AI Package: Activate
-Feature #103: AI Package: Follow, FollowCell
-Feature #138: Editor: Drag & Drop
-Feature #428: Player death
-Feature #505: Editor: Record Cloning
-Feature #701: Levelled creatures
-Feature #708: Improved Local Variable handling
-Feature #709: Editor: Script verifier
-Feature #764: Missing journal backend features
-Feature #777: Creature weapons/shields
-Feature #789: Editor: Referenceable record verifier
-Feature #924: Load/Save GUI (still missing loading screen and progress bars)
-Feature #946: Knockdown
-Feature #947: Decrease fatigue when running, swimming and attacking
-Feature #956: Melee Combat: Blocking
-Feature #957: Area magic
-Feature #960: Combat/AI combat for creatures
-Feature #962: Combat-Related AI instructions
-Feature #1075: Damage/Restore skill/attribute magic effects
-Feature #1076: Soultrap magic effect
-Feature #1081: Disease contraction
-Feature #1086: Blood particles
-Feature #1092: Interrupt resting
-Feature #1101: Inventory equip scripts
-Feature #1116: Version/Build number in Launcher window
-Feature #1119: Resistance/weakness to normal weapons magic effect
-Feature #1123: Slow Fall magic effect
-Feature #1130: Auto-calculate spells
-Feature #1164: Editor: Case-insensitive sorting in tables
+------
+
+    Bug #556: Video soundtrack not played when music volume is set to zero
+    Bug #829: OpenMW uses up all available vram, when playing for extended time
+    Bug #848: Wrong amount of footsteps playing in 1st person
+    Bug #888: Ascended Sleepers have movement issues
+    Bug #892: Explicit references are allowed on all script functions
+    Bug #999: Graphic Herbalism (mod): sometimes doesn't activate properly
+    Bug #1009: Lake Fjalding AI related slowdown.
+    Bug #1041: Music playback issues on OS X >= 10.9
+    Bug #1043: No message box when advancing skill "Speechcraft" while in dialog window
+    Bug #1060: Some message boxes are cut off at the bottom
+    Bug #1062: Bittercup script does not work ('end' variable)
+    Bug #1074: Inventory paperdoll obscures armour rating
+    Bug #1077: Message after killing an essential NPC disappears too fast
+    Bug #1078: "Clutterbane" shows empty charge bar
+    Bug #1083: UndoWerewolf fails
+    Bug #1088: Better Clothes Bloodmoon Plus 1.5 by Spirited Treasure pants are not rendered
+    Bug #1090: Start scripts fail when going to a non-predefined cell
+    Bug #1091: Crash: Assertion `!q.isNaN() && "Invalid orientation supplied as parameter"' failed.
+    Bug #1093: Weapons of aggressive NPCs are invisible after you exit and re-enter interior
+    Bug #1105: Magicka is depleted when using uncastable spells
+    Bug #1106: Creatures should be able to run
+    Bug #1107: TR cliffs have way too huge collision boxes in OpenMW
+    Bug #1109: Cleaning True Light and Darkness with Tes3cmd makes Addamasartus , Zenarbael and Yasamsi flooded.
+    Bug #1114: Bad output for desktop-file-validate on openmw.desktop (and opencs.desktop)
+    Bug #1115: Memory leak when spying on Fargoth
+    Bug #1137: Script execution fails (drenSlaveOwners script)
+    Bug #1143: Mehra Milo quest (vivec informants) is broken
+    Bug #1145: Issues with moving gold between inventory and containers
+    Bug #1146: Issues with picking up stacks of gold
+    Bug #1147: Dwemer Crossbows are held incorrectly
+    Bug #1158: Armor rating should always stay below inventory mannequin
+    Bug #1159: Quick keys can be set during character generation
+    Bug #1160: Crash on equip lockpick when
+    Bug #1167: Editor: Referenceables are not correctly loaded when dealing with more than one content file
+    Bug #1184: Game Save: overwriting an existing save does not actually overwrites the file
+    Feature #30: Loading/Saving (still missing a few parts)
+    Feature #101: AI Package: Activate
+    Feature #103: AI Package: Follow, FollowCell
+    Feature #138: Editor: Drag & Drop
+    Feature #428: Player death
+    Feature #505: Editor: Record Cloning
+    Feature #701: Levelled creatures
+    Feature #708: Improved Local Variable handling
+    Feature #709: Editor: Script verifier
+    Feature #764: Missing journal backend features
+    Feature #777: Creature weapons/shields
+    Feature #789: Editor: Referenceable record verifier
+    Feature #924: Load/Save GUI (still missing loading screen and progress bars)
+    Feature #946: Knockdown
+    Feature #947: Decrease fatigue when running, swimming and attacking
+    Feature #956: Melee Combat: Blocking
+    Feature #957: Area magic
+    Feature #960: Combat/AI combat for creatures
+    Feature #962: Combat-Related AI instructions
+    Feature #1075: Damage/Restore skill/attribute magic effects
+    Feature #1076: Soultrap magic effect
+    Feature #1081: Disease contraction
+    Feature #1086: Blood particles
+    Feature #1092: Interrupt resting
+    Feature #1101: Inventory equip scripts
+    Feature #1116: Version/Build number in Launcher window
+    Feature #1119: Resistance/weakness to normal weapons magic effect
+    Feature #1123: Slow Fall magic effect
+    Feature #1130: Auto-calculate spells
+    Feature #1164: Editor: Case-insensitive sorting in tables
 
 0.28.0
-
-Bug #399: Inventory changes are not visible immediately
-Bug #417: Apply weather instantly when teleporting
-Bug #566: Global Map position marker not updated for interior cells
-Bug #712: Looting corpse delay
-Bug #716: Problem with the "Vurt's Ascadian Isles Mod" mod
-Bug #805: Two TR meshes appear black (v0.24RC)
-Bug #841: Third-person activation distance taken from camera rather than head
-Bug #845: NPCs hold torches during the day
-Bug #855: Vvardenfell Visages Volume I some hairs don´t appear since 0,24
-Bug #856: Maormer race by Mac Kom - The heads are way up
-Bug #864: Walk locks during loading in 3rd person
-Bug #871: active weapon/magic item icon is not immediately made blank if item is removed during dialog
-Bug #882: Hircine's Ring doesn't always work
-Bug #909: [Tamriel Rebuilt] crashes in Akamora
-Bug #922: Launcher writing merged openmw.cfg files
-Bug #943: Random magnitude should be calculated per effect
-Bug #948: Negative fatigue level should be allowed
-Bug #949: Particles in world space
-Bug #950: Hard crash on x64 Linux running --new-game (on startup)
-Bug #951: setMagicka and setFatigue have no effect
-Bug #954: Problem with equipping inventory items when using a keyboard shortcut
-Bug #955: Issues with equipping torches
-Bug #966: Shield is visible when casting spell
-Bug #967: Game crashes when equipping silver candlestick
-Bug #970: Segmentation fault when starting at Bal Isra
-Bug #977: Pressing down key in console doesn't go forward in history
-Bug #979: Tooltip disappears when changing inventory
-Bug #980: Barter: item category is remembered, but not shown
-Bug #981: Mod: replacing model has wrong position/orientation
-Bug #982: Launcher: Addon unchecking is not saved
-Bug #983: Fix controllers to affect objects attached to the base node
-Bug #985: Player can talk to NPCs who are in combat
-Bug #989: OpenMW crashes when trying to include mod with capital .ESP
-Bug #991: Merchants equip items with harmful constant effect enchantments
-Bug #994: Don't cap skills/attributes when set via console
-Bug #998: Setting the max health should also set the current health
-Bug #1005: Torches are visible when casting spells and during hand to hand combat.
-Bug #1006: Many NPCs have 0 skill
-Bug #1007: Console fills up with text
-Bug #1013: Player randomly loses health or dies
-Bug #1014: Persuasion window is not centered in maximized window
-Bug #1015: Player status window scroll state resets on status change
-Bug #1016: Notification window not big enough for all skill level ups
-Bug #1020: Saved window positions are not rescaled appropriately on resolution change
-Bug #1022: Messages stuck permanently on screen when they pile up
-Bug #1023: Journals doesn't open
-Bug #1026: Game loses track of torch usage.
-Bug #1028: Crash on pickup of jug in Unexplored Shipwreck, Upper level
-Bug #1029: Quick keys menu: Select compatible replacement when tool used up
-Bug #1042: TES3 header data wrong encoding
-Bug #1045: OS X: deployed OpenCS won't launch
-Bug #1046: All damaged weaponry is worth 1 gold
-Bug #1048: Links in "locked" dialogue are still clickable
-Bug #1052: Using color codes when naming your character actually changes the name's color
-Bug #1054: Spell effects not visible in front of water
-Bug #1055: Power-Spell animation starts even though you already casted it that day
-Bug #1059: Cure disease potion removes all effects from player, even your race bonus and race ability
-Bug #1063: Crash upon checking out game start ship area in Seyda Neen
-Bug #1064: openmw binaries link to unnecessary libraries
-Bug #1065: Landing from a high place in water still causes fall damage
-Bug #1072: Drawing weapon increases torch brightness
-Bug #1073: Merchants sell stacks of gold
-Feature #43: Visuals for Magic Effects
-Feature #51: Ranged Magic
-Feature #52: Touch Range Magic
-Feature #53: Self Range Magic
-Feature #54: Spell Casting
-Feature #70: Vampirism
-Feature #100: Combat AI
-Feature #171: Implement NIF record NiFlipController
-Feature #410: Window to restore enchanted item charge
-Feature #647: Enchanted item glow
-Feature #723: Invisibility/Chameleon magic effects
-Feature #737: Resist Magicka magic effect
-Feature #758: GetLOS
-Feature #926: Editor: Info-Record tables
-Feature #958: Material controllers
-Feature #959: Terrain bump, specular, & parallax mapping
-Feature #990: Request: unlock mouse when in any menu
-Feature #1018: Do not allow view mode switching while performing an action
-Feature #1027: Vertex morph animation (NiGeomMorpherController)
-Feature #1031: Handle NiBillboardNode
-Feature #1051: Implement NIF texture slot DarkTexture
-Task #873: Unify OGRE initialisation
+------
+
+    Bug #399: Inventory changes are not visible immediately
+    Bug #417: Apply weather instantly when teleporting
+    Bug #566: Global Map position marker not updated for interior cells
+    Bug #712: Looting corpse delay
+    Bug #716: Problem with the "Vurt's Ascadian Isles Mod" mod
+    Bug #805: Two TR meshes appear black (v0.24RC)
+    Bug #841: Third-person activation distance taken from camera rather than head
+    Bug #845: NPCs hold torches during the day
+    Bug #855: Vvardenfell Visages Volume I some hairs don´t appear since 0,24
+    Bug #856: Maormer race by Mac Kom - The heads are way up
+    Bug #864: Walk locks during loading in 3rd person
+    Bug #871: active weapon/magic item icon is not immediately made blank if item is removed during dialog
+    Bug #882: Hircine's Ring doesn't always work
+    Bug #909: [Tamriel Rebuilt] crashes in Akamora
+    Bug #922: Launcher writing merged openmw.cfg files
+    Bug #943: Random magnitude should be calculated per effect
+    Bug #948: Negative fatigue level should be allowed
+    Bug #949: Particles in world space
+    Bug #950: Hard crash on x64 Linux running --new-game (on startup)
+    Bug #951: setMagicka and setFatigue have no effect
+    Bug #954: Problem with equipping inventory items when using a keyboard shortcut
+    Bug #955: Issues with equipping torches
+    Bug #966: Shield is visible when casting spell
+    Bug #967: Game crashes when equipping silver candlestick
+    Bug #970: Segmentation fault when starting at Bal Isra
+    Bug #977: Pressing down key in console doesn't go forward in history
+    Bug #979: Tooltip disappears when changing inventory
+    Bug #980: Barter: item category is remembered, but not shown
+    Bug #981: Mod: replacing model has wrong position/orientation
+    Bug #982: Launcher: Addon unchecking is not saved
+    Bug #983: Fix controllers to affect objects attached to the base node
+    Bug #985: Player can talk to NPCs who are in combat
+    Bug #989: OpenMW crashes when trying to include mod with capital .ESP
+    Bug #991: Merchants equip items with harmful constant effect enchantments
+    Bug #994: Don't cap skills/attributes when set via console
+    Bug #998: Setting the max health should also set the current health
+    Bug #1005: Torches are visible when casting spells and during hand to hand combat.
+    Bug #1006: Many NPCs have 0 skill
+    Bug #1007: Console fills up with text
+    Bug #1013: Player randomly loses health or dies
+    Bug #1014: Persuasion window is not centered in maximized window
+    Bug #1015: Player status window scroll state resets on status change
+    Bug #1016: Notification window not big enough for all skill level ups
+    Bug #1020: Saved window positions are not rescaled appropriately on resolution change
+    Bug #1022: Messages stuck permanently on screen when they pile up
+    Bug #1023: Journals doesn't open
+    Bug #1026: Game loses track of torch usage.
+    Bug #1028: Crash on pickup of jug in Unexplored Shipwreck, Upper level
+    Bug #1029: Quick keys menu: Select compatible replacement when tool used up
+    Bug #1042: TES3 header data wrong encoding
+    Bug #1045: OS X: deployed OpenCS won't launch
+    Bug #1046: All damaged weaponry is worth 1 gold
+    Bug #1048: Links in "locked" dialogue are still clickable
+    Bug #1052: Using color codes when naming your character actually changes the name's color
+    Bug #1054: Spell effects not visible in front of water
+    Bug #1055: Power-Spell animation starts even though you already casted it that day
+    Bug #1059: Cure disease potion removes all effects from player, even your race bonus and race ability
+    Bug #1063: Crash upon checking out game start ship area in Seyda Neen
+    Bug #1064: openmw binaries link to unnecessary libraries
+    Bug #1065: Landing from a high place in water still causes fall damage
+    Bug #1072: Drawing weapon increases torch brightness
+    Bug #1073: Merchants sell stacks of gold
+    Feature #43: Visuals for Magic Effects
+    Feature #51: Ranged Magic
+    Feature #52: Touch Range Magic
+    Feature #53: Self Range Magic
+    Feature #54: Spell Casting
+    Feature #70: Vampirism
+    Feature #100: Combat AI
+    Feature #171: Implement NIF record NiFlipController
+    Feature #410: Window to restore enchanted item charge
+    Feature #647: Enchanted item glow
+    Feature #723: Invisibility/Chameleon magic effects
+    Feature #737: Resist Magicka magic effect
+    Feature #758: GetLOS
+    Feature #926: Editor: Info-Record tables
+    Feature #958: Material controllers
+    Feature #959: Terrain bump, specular, & parallax mapping
+    Feature #990: Request: unlock mouse when in any menu
+    Feature #1018: Do not allow view mode switching while performing an action
+    Feature #1027: Vertex morph animation (NiGeomMorpherController)
+    Feature #1031: Handle NiBillboardNode
+    Feature #1051: Implement NIF texture slot DarkTexture
+    Task #873: Unify OGRE initialisation
 
 0.27.0
-
-Bug #597: Assertion `dialogue->mId == id' failed in esmstore.cpp
-Bug #794: incorrect display of decimal numbers
-Bug #840: First-person sneaking camera height
-Bug #887: Ambient sounds playing while paused
-Bug #902: Problems with Polish character encoding
-Bug #907: Entering third person using the mousewheel is possible even if it's impossible using the key
-Bug #910: Some CDs not working correctly with Unshield installer
-Bug #917: Quick character creation plugin does not work
-Bug #918: Fatigue does not refill
-Bug #919: The PC falls dead in Beshara - OpenMW nightly Win64 (708CDE2)
-Feature #57: Acrobatics Skill
-Feature #462: Editor: Start Dialogue
-Feature #546: Modify ESX selector to handle new content file scheme
-Feature #588: Editor: Adjust name/path of edited content files
-Feature #644: Editor: Save
-Feature #710: Editor: Configure script compiler context
-Feature #790: God Mode
-Feature #881: Editor: Allow only one instance of OpenCS
-Feature #889: Editor: Record filtering
-Feature #895: Extinguish torches
-Feature #898: Breath meter enhancements
-Feature #901: Editor: Default record filter
-Feature #913: Merge --master and --plugin switches
+------
+
+    Bug #597: Assertion `dialogue->mId == id' failed in esmstore.cpp
+    Bug #794: incorrect display of decimal numbers
+    Bug #840: First-person sneaking camera height
+    Bug #887: Ambient sounds playing while paused
+    Bug #902: Problems with Polish character encoding
+    Bug #907: Entering third person using the mousewheel is possible even if it's impossible using the key
+    Bug #910: Some CDs not working correctly with Unshield installer
+    Bug #917: Quick character creation plugin does not work
+    Bug #918: Fatigue does not refill
+    Bug #919: The PC falls dead in Beshara - OpenMW nightly Win64 (708CDE2)
+    Feature #57: Acrobatics Skill
+    Feature #462: Editor: Start Dialogue
+    Feature #546: Modify ESX selector to handle new content file scheme
+    Feature #588: Editor: Adjust name/path of edited content files
+    Feature #644: Editor: Save
+    Feature #710: Editor: Configure script compiler context
+    Feature #790: God Mode
+    Feature #881: Editor: Allow only one instance of OpenCS
+    Feature #889: Editor: Record filtering
+    Feature #895: Extinguish torches
+    Feature #898: Breath meter enhancements
+    Feature #901: Editor: Default record filter
+    Feature #913: Merge --master and --plugin switches
 
 0.26.0
-
-Bug #274: Inconsistencies in the terrain
-Bug #557: Already-dead NPCs do not equip clothing/items.
-Bug #592: Window resizing
-Bug #612: [Tamriel Rebuilt] Missing terrain (South of Tel Oren)
-Bug #664: Heart of lorkhan acts like a dead body (container)
-Bug #767: Wonky ramp physics & water
-Bug #780: Swimming out of water
-Bug #792: Wrong ground alignment on actors when no clipping
-Bug #796: Opening and closing door sound issue
-Bug #797: No clipping hinders opening and closing of doors
-Bug #799: sliders in enchanting window
-Bug #838: Pressing key during startup procedure freezes the game
-Bug #839: Combat/magic stances during character creation
-Bug #843: [Tribunal] Dark Brotherhood assassin appears without equipment
-Bug #844: Resting "until healed" option given even with full stats
-Bug #846: Equipped torches are invisible.
-Bug #847: Incorrect formula for autocalculated NPC initial health
-Bug #850: Shealt weapon sound plays when leaving magic-ready stance
-Bug #852: Some boots do not produce footstep sounds
-Bug #860: FPS bar misalignment
-Bug #861: Unable to print screen
-Bug #863: No sneaking and jumping at the same time
-Bug #866: Empty variables in [Movies] section of Morrowind.ini gets imported into OpenMW.cfg as blank fallback option and crashes game on start.
-Bug #867: Dancing girls in "Suran, Desele's House of Earthly Delights" don't dance.
-Bug #868: Idle animations are repeated
-Bug #874: Underwater swimming close to the ground is jerky
-Bug #875: Animation problem while swimming on the surface and looking up
-Bug #876: Always a starting upper case letter in the inventory
-Bug #878: Active spell effects don't update the layout properly when ended
-Bug #891: Cell 24,-12 (Tamriel Rebuilt) crashes on load
-Bug #896: New game sound issue
-Feature #49: Melee Combat
-Feature #71: Lycanthropy
-Feature #393: Initialise MWMechanics::AiSequence from ESM::AIPackageList
-Feature #622: Multiple positions for inventory window
-Feature #627: Drowning
-Feature #786: Allow the 'Activate' key to close the countdialog window
-Feature #798: Morrowind installation via Launcher (Linux/Max OS only)
-Feature #851: First/Third person transitions with mouse wheel
-Task #689: change PhysicActor::enableCollisions
-Task #707: Reorganise Compiler
+------
+
+    Bug #274: Inconsistencies in the terrain
+    Bug #557: Already-dead NPCs do not equip clothing/items.
+    Bug #592: Window resizing
+    Bug #612: [Tamriel Rebuilt] Missing terrain (South of Tel Oren)
+    Bug #664: Heart of lorkhan acts like a dead body (container)
+    Bug #767: Wonky ramp physics & water
+    Bug #780: Swimming out of water
+    Bug #792: Wrong ground alignment on actors when no clipping
+    Bug #796: Opening and closing door sound issue
+    Bug #797: No clipping hinders opening and closing of doors
+    Bug #799: sliders in enchanting window
+    Bug #838: Pressing key during startup procedure freezes the game
+    Bug #839: Combat/magic stances during character creation
+    Bug #843: [Tribunal] Dark Brotherhood assassin appears without equipment
+    Bug #844: Resting "until healed" option given even with full stats
+    Bug #846: Equipped torches are invisible.
+    Bug #847: Incorrect formula for autocalculated NPC initial health
+    Bug #850: Shealt weapon sound plays when leaving magic-ready stance
+    Bug #852: Some boots do not produce footstep sounds
+    Bug #860: FPS bar misalignment
+    Bug #861: Unable to print screen
+    Bug #863: No sneaking and jumping at the same time
+    Bug #866: Empty variables in [Movies] section of Morrowind.ini gets imported into OpenMW.cfg as blank fallback option and crashes game on start.
+    Bug #867: Dancing girls in "Suran, Desele's House of Earthly Delights" don't dance.
+    Bug #868: Idle animations are repeated
+    Bug #874: Underwater swimming close to the ground is jerky
+    Bug #875: Animation problem while swimming on the surface and looking up
+    Bug #876: Always a starting upper case letter in the inventory
+    Bug #878: Active spell effects don't update the layout properly when ended
+    Bug #891: Cell 24,-12 (Tamriel Rebuilt) crashes on load
+    Bug #896: New game sound issue
+    Feature #49: Melee Combat
+    Feature #71: Lycanthropy
+    Feature #393: Initialise MWMechanics::AiSequence from ESM::AIPackageList
+    Feature #622: Multiple positions for inventory window
+    Feature #627: Drowning
+    Feature #786: Allow the 'Activate' key to close the countdialog window
+    Feature #798: Morrowind installation via Launcher (Linux/Max OS only)
+    Feature #851: First/Third person transitions with mouse wheel
+    Task #689: change PhysicActor::enableCollisions
+    Task #707: Reorganise Compiler
 
 0.25.0
-
-Bug #411: Launcher crash on OS X < 10.8
-Bug #604: Terrible performance drop in the Census and Excise Office.
-Bug #676: Start Scripts fail to load
-Bug #677: OpenMW does not accept script names with -
-Bug #766: Extra space in front of topic links
-Bug #793: AIWander Isn't Being Passed The Repeat Parameter
-Bug #795: Sound playing with drawn weapon and crossing cell-border
-Bug #800: can't select weapon for enchantment
-Bug #801: Player can move while over-encumbered
-Bug #802: Dead Keys not working
-Bug #808: mouse capture
-Bug #809: ini Importer does not work without an existing cfg file
-Bug #812: Launcher will run OpenMW with no ESM or ESP selected
-Bug #813: OpenMW defaults to Morrowind.ESM with no ESM or ESP selected
-Bug #817: Dead NPCs and Creatures still have collision boxes
-Bug #820: Incorrect sorting of answers (Dialogue)
-Bug #826: mwinimport dumps core when given an unknown parameter
-Bug #833: getting stuck in door
-Bug #835: Journals/books not showing up properly.
-Feature #38: SoundGen
-Feature #105: AI Package: Wander
-Feature #230: 64-bit compatibility for OS X
-Feature #263: Hardware mouse cursors
-Feature #449: Allow mouse outside of window while paused
-Feature #736: First person animations
-Feature #750: Using mouse wheel in third person mode
-Feature #822: Autorepeat for slider buttons
+------
+
+    Bug #411: Launcher crash on OS X < 10.8
+    Bug #604: Terrible performance drop in the Census and Excise Office.
+    Bug #676: Start Scripts fail to load
+    Bug #677: OpenMW does not accept script names with -
+    Bug #766: Extra space in front of topic links
+    Bug #793: AIWander Isn't Being Passed The Repeat Parameter
+    Bug #795: Sound playing with drawn weapon and crossing cell-border
+    Bug #800: can't select weapon for enchantment
+    Bug #801: Player can move while over-encumbered
+    Bug #802: Dead Keys not working
+    Bug #808: mouse capture
+    Bug #809: ini Importer does not work without an existing cfg file
+    Bug #812: Launcher will run OpenMW with no ESM or ESP selected
+    Bug #813: OpenMW defaults to Morrowind.ESM with no ESM or ESP selected
+    Bug #817: Dead NPCs and Creatures still have collision boxes
+    Bug #820: Incorrect sorting of answers (Dialogue)
+    Bug #826: mwinimport dumps core when given an unknown parameter
+    Bug #833: getting stuck in door
+    Bug #835: Journals/books not showing up properly.
+    Feature #38: SoundGen
+    Feature #105: AI Package: Wander
+    Feature #230: 64-bit compatibility for OS X
+    Feature #263: Hardware mouse cursors
+    Feature #449: Allow mouse outside of window while paused
+    Feature #736: First person animations
+    Feature #750: Using mouse wheel in third person mode
+    Feature #822: Autorepeat for slider buttons
 
 0.24.0
-
-Bug #284: Book's text misalignment
-Bug #445: Camera able to get slightly below floor / terrain
-Bug #582: Seam issue in Red Mountain
-Bug #632: Journal Next Button shows white square
-Bug #653: IndexedStore ignores index
-Bug #694: Parser does not recognize float values starting with .
-Bug #699: Resource handling broken with Ogre 1.9 trunk
-Bug #718: components/esm/loadcell is using the mwworld subsystem
-Bug #729: Levelled item list tries to add nonexistent item
-Bug #730: Arrow buttons in the settings menu do not work.
-Bug #732: Erroneous behavior when binding keys
-Bug #733: Unclickable dialogue topic
-Bug #734: Book empty line problem
-Bug #738: OnDeath only works with implicit references
-Bug #740: Script compiler fails on scripts with special names
-Bug #742: Wait while no clipping
-Bug #743: Problem with changeweather console command
-Bug #744: No wait dialogue after starting a new game
-Bug #748: Player is not able to unselect objects with the console
-Bug #751: AddItem should only spawn a message box when called from dialogue
-Bug #752: The enter button has several functions in trade and looting that is not impelemted.
-Bug #753: Fargoth's Ring Quest Strange Behavior
-Bug #755: Launcher writes duplicate lines into settings.cfg
-Bug #759: Second quest in mages guild does not work
-Bug #763: Enchantment cast cost is wrong
-Bug #770: The "Take" and "Close" buttons in the scroll GUI are stretched incorrectly
-Bug #773: AIWander Isn't Being Passed The Correct idle Values
-Bug #778: The journal can be opened at the start of a new game
-Bug #779: Divayth Fyr starts as dead
-Bug #787: "Batch count" on detailed FPS counter gets cut-off
-Bug #788: chargen scroll layout does not match vanilla
-Feature #60: Atlethics Skill
-Feature #65: Security Skill
-Feature #74: Interaction with non-load-doors
-Feature #98: Render Weapon and Shield
-Feature #102: AI Package: Escort, EscortCell
-Feature #182: Advanced Journal GUI
-Feature #288: Trading enhancements
-Feature #405: Integrate "new game" into the menu
-Feature #537: Highlight dialogue topic links
-Feature #658: Rotate, RotateWorld script instructions and local rotations
-Feature #690: Animation Layering
-Feature #722: Night Eye/Blind magic effects
-Feature #735: Move, MoveWorld script instructions.
-Feature #760: Non-removable corpses
+------
+
+    Bug #284: Book's text misalignment
+    Bug #445: Camera able to get slightly below floor / terrain
+    Bug #582: Seam issue in Red Mountain
+    Bug #632: Journal Next Button shows white square
+    Bug #653: IndexedStore ignores index
+    Bug #694: Parser does not recognize float values starting with .
+    Bug #699: Resource handling broken with Ogre 1.9 trunk
+    Bug #718: components/esm/loadcell is using the mwworld subsystem
+    Bug #729: Levelled item list tries to add nonexistent item
+    Bug #730: Arrow buttons in the settings menu do not work.
+    Bug #732: Erroneous behavior when binding keys
+    Bug #733: Unclickable dialogue topic
+    Bug #734: Book empty line problem
+    Bug #738: OnDeath only works with implicit references
+    Bug #740: Script compiler fails on scripts with special names
+    Bug #742: Wait while no clipping
+    Bug #743: Problem with changeweather console command
+    Bug #744: No wait dialogue after starting a new game
+    Bug #748: Player is not able to unselect objects with the console
+    Bug #751: AddItem should only spawn a message box when called from dialogue
+    Bug #752: The enter button has several functions in trade and looting that is not impelemted.
+    Bug #753: Fargoth's Ring Quest Strange Behavior
+    Bug #755: Launcher writes duplicate lines into settings.cfg
+    Bug #759: Second quest in mages guild does not work
+    Bug #763: Enchantment cast cost is wrong
+    Bug #770: The "Take" and "Close" buttons in the scroll GUI are stretched incorrectly
+    Bug #773: AIWander Isn't Being Passed The Correct idle Values
+    Bug #778: The journal can be opened at the start of a new game
+    Bug #779: Divayth Fyr starts as dead
+    Bug #787: "Batch count" on detailed FPS counter gets cut-off
+    Bug #788: chargen scroll layout does not match vanilla
+    Feature #60: Atlethics Skill
+    Feature #65: Security Skill
+    Feature #74: Interaction with non-load-doors
+    Feature #98: Render Weapon and Shield
+    Feature #102: AI Package: Escort, EscortCell
+    Feature #182: Advanced Journal GUI
+    Feature #288: Trading enhancements
+    Feature #405: Integrate "new game" into the menu
+    Feature #537: Highlight dialogue topic links
+    Feature #658: Rotate, RotateWorld script instructions and local rotations
+    Feature #690: Animation Layering
+    Feature #722: Night Eye/Blind magic effects
+    Feature #735: Move, MoveWorld script instructions.
+    Feature #760: Non-removable corpses
 
 0.23.0
-
-Bug #522: Player collides with placeable items
-Bug #553: Open/Close sounds played when accessing main menu w/ Journal Open
-Bug #561: Tooltip word wrapping delay
-Bug #578: Bribing works incorrectly
-Bug #601: PositionCell fails on negative coordinates
-Bug #606: Some NPCs hairs not rendered with Better Heads addon
-Bug #609: Bad rendering of bone boots
-Bug #613: Messagebox causing assert to fail
-Bug #631: Segfault on shutdown
-Bug #634: Exception when talking to Calvus Horatius in Mournhold, royal palace courtyard
-Bug #635: Scale NPCs depending on race
-Bug #643: Dialogue Race select function is inverted
-Bug #646: Twohanded weapons don't work properly
-Bug #654: Crash when dropping objects without a collision shape
-Bug #655/656: Objects that were disabled or deleted (but not both) were added to the scene when re-entering a cell
-Bug #660: "g" in "change" cut off in Race Menu
-Bug #661: Arrille sells me the key to his upstairs room
-Bug #662: Day counter starts at 2 instead of 1
-Bug #663: Cannot select "come unprepared" topic in dialog with Dagoth Ur
-Bug #665: Pickpocket -> "Grab all" grabs all NPC inventory, even not listed in container window.
-Bug #666: Looking up/down problem
-Bug #667: Active effects border visible during loading
-Bug #669: incorrect player position at new game start
-Bug #670: race selection menu: sex, face and hair left button not totally clickable
-Bug #671: new game: player is naked
-Bug #674: buying or selling items doesn't change amount of gold
-Bug #675: fatigue is not set to its maximum when starting a new game
-Bug #678: Wrong rotation order causes RefData's rotation to be stored incorrectly
-Bug #680: different gold coins in Tel Mara
-Bug #682: Race menu ignores playable flag for some hairs and faces
-Bug #685: Script compiler does not accept ":" after a function name
-Bug #688: dispose corpse makes cross-hair to disappear
-Bug #691: Auto equipping ignores equipment conditions
-Bug #692: OpenMW doesnt load "loose file" texture packs that places resources directly in data folder
-Bug #696: Draugr incorrect head offset
-Bug #697: Sail transparency issue
-Bug #700: "On the rocks" mod does not load its UV coordinates correctly.
-Bug #702: Some race mods don't work
-Bug #711: Crash during character creation
-Bug #715: Growing Tauryon
-Bug #725: Auto calculate stats
-Bug #728: Failure to open container and talk dialogue
-Bug #731: Crash with Mush-Mere's "background" topic
-Feature #55/657: Item Repairing
-Feature #62/87: Enchanting
-Feature #99: Pathfinding
-Feature #104: AI Package: Travel
-Feature #129: Levelled items
-Feature #204: Texture animations
-Feature #239: Fallback-Settings
-Feature #535: Console object selection improvements
-Feature #629: Add levelup description in levelup layout dialog
-Feature #630: Optional format subrecord in (tes3) header
-Feature #641: Armor rating
-Feature #645: OnDeath script function
-Feature #683: Companion item UI
-Feature #698: Basic Particles
-Task #648: Split up components/esm/loadlocks
-Task #695: mwgui cleanup
+------
+
+    Bug #522: Player collides with placeable items
+    Bug #553: Open/Close sounds played when accessing main menu w/ Journal Open
+    Bug #561: Tooltip word wrapping delay
+    Bug #578: Bribing works incorrectly
+    Bug #601: PositionCell fails on negative coordinates
+    Bug #606: Some NPCs hairs not rendered with Better Heads addon
+    Bug #609: Bad rendering of bone boots
+    Bug #613: Messagebox causing assert to fail
+    Bug #631: Segfault on shutdown
+    Bug #634: Exception when talking to Calvus Horatius in Mournhold, royal palace courtyard
+    Bug #635: Scale NPCs depending on race
+    Bug #643: Dialogue Race select function is inverted
+    Bug #646: Twohanded weapons don't work properly
+    Bug #654: Crash when dropping objects without a collision shape
+    Bug #655/656: Objects that were disabled or deleted (but not both) were added to the scene when re-entering a cell
+    Bug #660: "g" in "change" cut off in Race Menu
+    Bug #661: Arrille sells me the key to his upstairs room
+    Bug #662: Day counter starts at 2 instead of 1
+    Bug #663: Cannot select "come unprepared" topic in dialog with Dagoth Ur
+    Bug #665: Pickpocket -> "Grab all" grabs all NPC inventory, even not listed in container window.
+    Bug #666: Looking up/down problem
+    Bug #667: Active effects border visible during loading
+    Bug #669: incorrect player position at new game start
+    Bug #670: race selection menu: sex, face and hair left button not totally clickable
+    Bug #671: new game: player is naked
+    Bug #674: buying or selling items doesn't change amount of gold
+    Bug #675: fatigue is not set to its maximum when starting a new game
+    Bug #678: Wrong rotation order causes RefData's rotation to be stored incorrectly
+    Bug #680: different gold coins in Tel Mara
+    Bug #682: Race menu ignores playable flag for some hairs and faces
+    Bug #685: Script compiler does not accept ":" after a function name
+    Bug #688: dispose corpse makes cross-hair to disappear
+    Bug #691: Auto equipping ignores equipment conditions
+    Bug #692: OpenMW doesnt load "loose file" texture packs that places resources directly in data folder
+    Bug #696: Draugr incorrect head offset
+    Bug #697: Sail transparency issue
+    Bug #700: "On the rocks" mod does not load its UV coordinates correctly.
+    Bug #702: Some race mods don't work
+    Bug #711: Crash during character creation
+    Bug #715: Growing Tauryon
+    Bug #725: Auto calculate stats
+    Bug #728: Failure to open container and talk dialogue
+    Bug #731: Crash with Mush-Mere's "background" topic
+    Feature #55/657: Item Repairing
+    Feature #62/87: Enchanting
+    Feature #99: Pathfinding
+    Feature #104: AI Package: Travel
+    Feature #129: Levelled items
+    Feature #204: Texture animations
+    Feature #239: Fallback-Settings
+    Feature #535: Console object selection improvements
+    Feature #629: Add levelup description in levelup layout dialog
+    Feature #630: Optional format subrecord in (tes3) header
+    Feature #641: Armor rating
+    Feature #645: OnDeath script function
+    Feature #683: Companion item UI
+    Feature #698: Basic Particles
+    Task #648: Split up components/esm/loadlocks
+    Task #695: mwgui cleanup
 
 0.22.0
-
-Bug #311: Potential infinite recursion in script compiler
-Bug #355: Keyboard repeat rate (in Xorg) are left disabled after game exit.
-Bug #382: Weird effect in 3rd person on water
-Bug #387: Always use detailed shape for physics raycasts
-Bug #420: Potion/ingredient effects do not stack
-Bug #429: Parts of dwemer door not picked up correctly for activation/tooltips
-Bug #434/Bug #605: Object movement between cells not properly implemented
-Bug #502: Duplicate player collision model at origin
-Bug #509: Dialogue topic list shifts inappropriately
-Bug #513: Sliding stairs
-Bug #515: Launcher does not support non-latin strings
-Bug #525: Race selection preview camera wrong position
-Bug #526: Attributes / skills should not go below zero
-Bug #529: Class and Birthsign menus options should be preselected
-Bug #530: Lock window button graphic missing
-Bug #532: Missing map menu graphics
-Bug #545: ESX selector does not list ESM files properly
-Bug #547: Global variables of type short are read incorrectly
-Bug #550: Invisible meshes collision and tooltip
-Bug #551: Performance drop when loading multiple ESM files
-Bug #552: Don't list CG in options if it is not available
-Bug #555: Character creation windows "OK" button broken
-Bug #558: Segmentation fault when Alt-tabbing with console opened
-Bug #559: Dialog window should not be available before character creation is finished
-Bug #560: Tooltip borders should be stretched
-Bug #562: Sound should not be played when an object cannot be picked up
-Bug #565: Water animation speed + timescale
-Bug #572: Better Bodies' textures don't work
-Bug #573: OpenMW doesn't load if TR_Mainland.esm is enabled (Tamriel Rebuilt mod)
-Bug #574: Moving left/right should not cancel auto-run
-Bug #575: Crash entering the Chamber of Song
-Bug #576: Missing includes
-Bug #577: Left Gloves Addon causes ESMReader exception
-Bug #579: Unable to open container "Kvama Egg Sack"
-Bug #581: Mimicking vanilla Morrowind water
-Bug #583: Gender not recognized
-Bug #586: Wrong char gen behaviour
-Bug #587: "End" script statements with spaces don't work
-Bug #589: Closing message boxes by pressing the activation key
-Bug #590: Ugly Dagoth Ur rendering
-Bug #591: Race selection issues
-Bug #593: Persuasion response should be random
-Bug #595: Footless guard
-Bug #599: Waterfalls are invisible from a certain distance
-Bug #600: Waterfalls rendered incorrectly, cut off by water
-Bug #607: New beast bodies mod crashes
-Bug #608: Crash in cell "Mournhold, Royal Palace"
-Bug #611: OpenMW doesn't find some of textures used in Tamriel Rebuilt
-Bug #613: Messagebox causing assert to fail
-Bug #615: Meshes invisible from above water
-Bug #617: Potion effects should be hidden until discovered
-Bug #619: certain moss hanging from tree has rendering bug
-Bug #621: Batching bloodmoon's trees
-Bug #623: NiMaterialProperty alpha unhandled
-Bug #628: Launcher in latest master crashes the game
-Bug #633: Crash on startup: Better Heads
-Bug #636: Incorrect Char Gen Menu Behavior
-Feature #29: Allow ESPs and multiple ESMs
-Feature #94: Finish class selection-dialogue
-Feature #149: Texture Alphas
-Feature #237: Run Morrowind-ini importer from launcher
-Feature #286: Update Active Spell Icons
-Feature #334: Swimming animation
-Feature #335: Walking animation
-Feature #360: Proper collision shapes for NPCs and creatures
-Feature #367: Lights that behave more like original morrowind implementation
-Feature #477: Special local scripting variables
-Feature #528: Message boxes should close when enter is pressed under certain conditions.
-Feature #543: Add bsa files to the settings imported by the ini importer
-Feature #594: coordinate space and utility functions
-Feature #625: Zoom in vanity mode
-Task #464: Refactor launcher ESX selector into a re-usable component
-Task #624: Unified implementation of type-variable sub-records
+------
+
+    Bug #311: Potential infinite recursion in script compiler
+    Bug #355: Keyboard repeat rate (in Xorg) are left disabled after game exit.
+    Bug #382: Weird effect in 3rd person on water
+    Bug #387: Always use detailed shape for physics raycasts
+    Bug #420: Potion/ingredient effects do not stack
+    Bug #429: Parts of dwemer door not picked up correctly for activation/tooltips
+    Bug #434/Bug #605: Object movement between cells not properly implemented
+    Bug #502: Duplicate player collision model at origin
+    Bug #509: Dialogue topic list shifts inappropriately
+    Bug #513: Sliding stairs
+    Bug #515: Launcher does not support non-latin strings
+    Bug #525: Race selection preview camera wrong position
+    Bug #526: Attributes / skills should not go below zero
+    Bug #529: Class and Birthsign menus options should be preselected
+    Bug #530: Lock window button graphic missing
+    Bug #532: Missing map menu graphics
+    Bug #545: ESX selector does not list ESM files properly
+    Bug #547: Global variables of type short are read incorrectly
+    Bug #550: Invisible meshes collision and tooltip
+    Bug #551: Performance drop when loading multiple ESM files
+    Bug #552: Don't list CG in options if it is not available
+    Bug #555: Character creation windows "OK" button broken
+    Bug #558: Segmentation fault when Alt-tabbing with console opened
+    Bug #559: Dialog window should not be available before character creation is finished
+    Bug #560: Tooltip borders should be stretched
+    Bug #562: Sound should not be played when an object cannot be picked up
+    Bug #565: Water animation speed + timescale
+    Bug #572: Better Bodies' textures don't work
+    Bug #573: OpenMW doesn't load if TR_Mainland.esm is enabled (Tamriel Rebuilt mod)
+    Bug #574: Moving left/right should not cancel auto-run
+    Bug #575: Crash entering the Chamber of Song
+    Bug #576: Missing includes
+    Bug #577: Left Gloves Addon causes ESMReader exception
+    Bug #579: Unable to open container "Kvama Egg Sack"
+    Bug #581: Mimicking vanilla Morrowind water
+    Bug #583: Gender not recognized
+    Bug #586: Wrong char gen behaviour
+    Bug #587: "End" script statements with spaces don't work
+    Bug #589: Closing message boxes by pressing the activation key
+    Bug #590: Ugly Dagoth Ur rendering
+    Bug #591: Race selection issues
+    Bug #593: Persuasion response should be random
+    Bug #595: Footless guard
+    Bug #599: Waterfalls are invisible from a certain distance
+    Bug #600: Waterfalls rendered incorrectly, cut off by water
+    Bug #607: New beast bodies mod crashes
+    Bug #608: Crash in cell "Mournhold, Royal Palace"
+    Bug #611: OpenMW doesn't find some of textures used in Tamriel Rebuilt
+    Bug #613: Messagebox causing assert to fail
+    Bug #615: Meshes invisible from above water
+    Bug #617: Potion effects should be hidden until discovered
+    Bug #619: certain moss hanging from tree has rendering bug
+    Bug #621: Batching bloodmoon's trees
+    Bug #623: NiMaterialProperty alpha unhandled
+    Bug #628: Launcher in latest master crashes the game
+    Bug #633: Crash on startup: Better Heads
+    Bug #636: Incorrect Char Gen Menu Behavior
+    Feature #29: Allow ESPs and multiple ESMs
+    Feature #94: Finish class selection-dialogue
+    Feature #149: Texture Alphas
+    Feature #237: Run Morrowind-ini importer from launcher
+    Feature #286: Update Active Spell Icons
+    Feature #334: Swimming animation
+    Feature #335: Walking animation
+    Feature #360: Proper collision shapes for NPCs and creatures
+    Feature #367: Lights that behave more like original morrowind implementation
+    Feature #477: Special local scripting variables
+    Feature #528: Message boxes should close when enter is pressed under certain conditions.
+    Feature #543: Add bsa files to the settings imported by the ini importer
+    Feature #594: coordinate space and utility functions
+    Feature #625: Zoom in vanity mode
+    Task #464: Refactor launcher ESX selector into a re-usable component
+    Task #624: Unified implementation of type-variable sub-records
 
 0.21.0
-
-Bug #253: Dialogs don't work for Russian version of Morrowind
-Bug #267: Activating creatures without dialogue can still activate the dialogue GUI
-Bug #354: True flickering lights
-Bug #386: The main menu's first entry is wrong (in french)
-Bug #479: Adding the spell "Ash Woe Blight" to the player causes strange attribute oscillations
-Bug #495: Activation Range
-Bug #497: Failed Disposition check doesn't stop a dialogue entry from being returned
-Bug #498: Failing a disposition check shouldn't eliminate topics from the the list of those available
-Bug #500: Disposition for most NPCs is 0/100
-Bug #501: Getdisposition command wrongly returns base disposition
-Bug #506: Journal UI doesn't update anymore
-Bug #507: EnableRestMenu is not a valid command - change it to EnableRest
-Bug #508: Crash in Ald Daedroth Shrine
-Bug #517: Wrong price calculation when untrading an item
-Bug #521: MWGui::InventoryWindow creates a duplicate player actor at the origin
-Bug #524: Beast races are able to wear shoes
-Bug #527: Background music fails to play
-Bug #533: The arch at Gnisis entrance is not displayed
-Bug #534: Terrain gets its correct shape only some time after the cell is loaded
-Bug #536: The same entry can be added multiple times to the journal
-Bug #539: Race selection is broken
-Bug #544: Terrain normal map corrupt when the map is rendered
-Feature #39: Video Playback
-Feature #151: ^-escape sequences in text output
-Feature #392: Add AI related script functions
-Feature #456: Determine required ini fallback values and adjust the ini importer accordingly
-Feature #460: Experimental DirArchives improvements
-Feature #540: Execute scripts of objects in containers/inventories in active cells
-Task #401: Review GMST fixing
-Task #453: Unify case smashing/folding
-Task #512: Rewrite utf8 component
+------
+
+    Bug #253: Dialogs don't work for Russian version of Morrowind
+    Bug #267: Activating creatures without dialogue can still activate the dialogue GUI
+    Bug #354: True flickering lights
+    Bug #386: The main menu's first entry is wrong (in french)
+    Bug #479: Adding the spell "Ash Woe Blight" to the player causes strange attribute oscillations
+    Bug #495: Activation Range
+    Bug #497: Failed Disposition check doesn't stop a dialogue entry from being returned
+    Bug #498: Failing a disposition check shouldn't eliminate topics from the the list of those available
+    Bug #500: Disposition for most NPCs is 0/100
+    Bug #501: Getdisposition command wrongly returns base disposition
+    Bug #506: Journal UI doesn't update anymore
+    Bug #507: EnableRestMenu is not a valid command - change it to EnableRest
+    Bug #508: Crash in Ald Daedroth Shrine
+    Bug #517: Wrong price calculation when untrading an item
+    Bug #521: MWGui::InventoryWindow creates a duplicate player actor at the origin
+    Bug #524: Beast races are able to wear shoes
+    Bug #527: Background music fails to play
+    Bug #533: The arch at Gnisis entrance is not displayed
+    Bug #534: Terrain gets its correct shape only some time after the cell is loaded
+    Bug #536: The same entry can be added multiple times to the journal
+    Bug #539: Race selection is broken
+    Bug #544: Terrain normal map corrupt when the map is rendered
+    Feature #39: Video Playback
+    Feature #151: ^-escape sequences in text output
+    Feature #392: Add AI related script functions
+    Feature #456: Determine required ini fallback values and adjust the ini importer accordingly
+    Feature #460: Experimental DirArchives improvements
+    Feature #540: Execute scripts of objects in containers/inventories in active cells
+    Task #401: Review GMST fixing
+    Task #453: Unify case smashing/folding
+    Task #512: Rewrite utf8 component
 
 0.20.0
-
-Bug #366: Changing the player's race during character creation does not change the look of the player character
-Bug #430: Teleporting and using loading doors linking within the same cell reloads the cell
-Bug #437: Stop animations when paused
-Bug #438: Time displays as "0 a.m." when it should be "12 a.m."
-Bug #439: Text in "name" field of potion/spell creation window is persistent
-Bug #440: Starting date at a new game is off by one day
-Bug #442: Console window doesn't close properly sometimes
-Bug #448: Do not break container window formatting when item names are very long
-Bug #458: Topics sometimes not automatically added to known topic list
-Bug #476: Auto-Moving allows player movement after using DisablePlayerControls
-Bug #478: After sleeping in a bed the rest dialogue window opens automtically again
-Bug #492: On creating potions the ingredients are removed twice
-Feature #63: Mercantile skill
-Feature #82: Persuasion Dialogue
-Feature #219: Missing dialogue filters/functions
-Feature #369: Add a FailedAction
-Feature #377: Select head/hair on character creation
-Feature #391: Dummy AI package classes
-Feature #435: Global Map, 2nd Layer
-Feature #450: Persuasion
-Feature #457: Add more script instructions
-Feature #474: update the global variable pcrace when the player's race is changed
-Task #158: Move dynamically generated classes from Player class to World Class
-Task #159: ESMStore rework and cleanup
-Task #163: More Component Namespace Cleanup
-Task #402: Move player data from MWWorld::Player to the player's NPC record
-Task #446: Fix no namespace in BulletShapeLoader
+------
+
+    Bug #366: Changing the player's race during character creation does not change the look of the player character
+    Bug #430: Teleporting and using loading doors linking within the same cell reloads the cell
+    Bug #437: Stop animations when paused
+    Bug #438: Time displays as "0 a.m." when it should be "12 a.m."
+    Bug #439: Text in "name" field of potion/spell creation window is persistent
+    Bug #440: Starting date at a new game is off by one day
+    Bug #442: Console window doesn't close properly sometimes
+    Bug #448: Do not break container window formatting when item names are very long
+    Bug #458: Topics sometimes not automatically added to known topic list
+    Bug #476: Auto-Moving allows player movement after using DisablePlayerControls
+    Bug #478: After sleeping in a bed the rest dialogue window opens automtically again
+    Bug #492: On creating potions the ingredients are removed twice
+    Feature #63: Mercantile skill
+    Feature #82: Persuasion Dialogue
+    Feature #219: Missing dialogue filters/functions
+    Feature #369: Add a FailedAction
+    Feature #377: Select head/hair on character creation
+    Feature #391: Dummy AI package classes
+    Feature #435: Global Map, 2nd Layer
+    Feature #450: Persuasion
+    Feature #457: Add more script instructions
+    Feature #474: update the global variable pcrace when the player's race is changed
+    Task #158: Move dynamically generated classes from Player class to World Class
+    Task #159: ESMStore rework and cleanup
+    Task #163: More Component Namespace Cleanup
+    Task #402: Move player data from MWWorld::Player to the player's NPC record
+    Task #446: Fix no namespace in BulletShapeLoader
 
 0.19.0
-
-Bug #374: Character shakes in 3rd person mode near the origin
-Bug #404: Gamma correct rendering
-Bug #407: Shoes of St. Rilm do not work
-Bug #408: Rugs has collision even if they are not supposed to
-Bug #412: Birthsign menu sorted incorrectly
-Bug #413: Resolutions presented multiple times in launcher
-Bug #414: launcher.cfg file stored in wrong directory
-Bug #415: Wrong esm order in openmw.cfg
-Bug #418: Sound listener position updates incorrectly
-Bug #423: wrong usage of "Version" entry in openmw.desktop
-Bug #426: Do not use hardcoded splash images
-Bug #431: Don't use markers for raycast
-Bug #432: Crash after picking up items from an NPC
-Feature #21/#95: Sleeping/resting
-Feature #61: Alchemy Skill
-Feature #68: Death
-Feature #69/#86: Spell Creation
-Feature #72/#84: Travel
-Feature #76: Global Map, 1st Layer
-Feature #120: Trainer Window
-Feature #152: Skill Increase from Skill Books
-Feature #160: Record Saving
-Task #400: Review GMST access
+------
+
+    Bug #374: Character shakes in 3rd person mode near the origin
+    Bug #404: Gamma correct rendering
+    Bug #407: Shoes of St. Rilm do not work
+    Bug #408: Rugs has collision even if they are not supposed to
+    Bug #412: Birthsign menu sorted incorrectly
+    Bug #413: Resolutions presented multiple times in launcher
+    Bug #414: launcher.cfg file stored in wrong directory
+    Bug #415: Wrong esm order in openmw.cfg
+    Bug #418: Sound listener position updates incorrectly
+    Bug #423: wrong usage of "Version" entry in openmw.desktop
+    Bug #426: Do not use hardcoded splash images
+    Bug #431: Don't use markers for raycast
+    Bug #432: Crash after picking up items from an NPC
+    Feature #21/#95: Sleeping/resting
+    Feature #61: Alchemy Skill
+    Feature #68: Death
+    Feature #69/#86: Spell Creation
+    Feature #72/#84: Travel
+    Feature #76: Global Map, 1st Layer
+    Feature #120: Trainer Window
+    Feature #152: Skill Increase from Skill Books
+    Feature #160: Record Saving
+    Task #400: Review GMST access
 
 0.18.0
-
-Bug #310: Button of the "preferences menu" are too small
-Bug #361: Hand-to-hand skill is always 100
-Bug #365: NPC and creature animation is jerky; Characters float around when they are not supposed to
-Bug #372: playSound3D uses original coordinates instead of current coordinates.
-Bug #373: Static OGRE build faulty
-Bug #375: Alt-tab toggle view
-Bug #376: Screenshots are disable
-Bug #378: Exception when drinking self-made potions
-Bug #380: Cloth visibility problem
-Bug #384: Weird character on doors tooltip.
-Bug #398: Some objects do not collide in MW, but do so in OpenMW
-Feature #22: Implement level-up
-Feature #36: Hide Marker
-Feature #88: Hotkey Window
-Feature #91: Level-Up Dialogue
-Feature #118: Keyboard and Mouse-Button bindings
-Feature #119: Spell Buying Window
-Feature #133: Handle resources across multiple data directories
-Feature #134: Generate a suitable default-value for --data-local
-Feature #292: Object Movement/Creation Script Instructions
-Feature #340: AIPackage data structures
-Feature #356: Ingredients use
-Feature #358: Input system rewrite
-Feature #370: Target handling in actions
-Feature #379: Door markers on the local map
-Feature #389: AI framework
-Feature #395: Using keys to open doors / containers
-Feature #396: Loading screens
-Feature #397: Inventory avatar image and race selection head preview
-Task #339: Move sounds into Action
+------
+
+    Bug #310: Button of the "preferences menu" are too small
+    Bug #361: Hand-to-hand skill is always 100
+    Bug #365: NPC and creature animation is jerky; Characters float around when they are not supposed to
+    Bug #372: playSound3D uses original coordinates instead of current coordinates.
+    Bug #373: Static OGRE build faulty
+    Bug #375: Alt-tab toggle view
+    Bug #376: Screenshots are disable
+    Bug #378: Exception when drinking self-made potions
+    Bug #380: Cloth visibility problem
+    Bug #384: Weird character on doors tooltip.
+    Bug #398: Some objects do not collide in MW, but do so in OpenMW
+    Feature #22: Implement level-up
+    Feature #36: Hide Marker
+    Feature #88: Hotkey Window
+    Feature #91: Level-Up Dialogue
+    Feature #118: Keyboard and Mouse-Button bindings
+    Feature #119: Spell Buying Window
+    Feature #133: Handle resources across multiple data directories
+    Feature #134: Generate a suitable default-value for --data-local
+    Feature #292: Object Movement/Creation Script Instructions
+    Feature #340: AIPackage data structures
+    Feature #356: Ingredients use
+    Feature #358: Input system rewrite
+    Feature #370: Target handling in actions
+    Feature #379: Door markers on the local map
+    Feature #389: AI framework
+    Feature #395: Using keys to open doors / containers
+    Feature #396: Loading screens
+    Feature #397: Inventory avatar image and race selection head preview
+    Task #339: Move sounds into Action
 
 0.17.0
-
-Bug #225: Valgrind reports about 40MB of leaked memory
-Bug #241: Some physics meshes still don't match
-Bug #248: Some textures are too dark
-Bug #300: Dependency on proprietary CG toolkit
-Bug #302: Some objects don't collide although they should
-Bug #308: Freeze in Balmora, Meldor: Armorer
-Bug #313: openmw without a ~/.config/openmw folder segfault.
-Bug #317: adding non-existing spell via console locks game
-Bug #318: Wrong character normals
-Bug #341: Building with Ogre Debug libraries does not use debug version of plugins
-Bug #347: Crash when running openmw with --start="XYZ"
-Bug #353: FindMyGUI.cmake breaks path on Windows
-Bug #359: WindowManager throws exception at destruction
-Bug #364: Laggy input on OS X due to bug in Ogre's event pump implementation
-Feature #33: Allow objects to cross cell-borders
-Feature #59: Dropping Items (replaced stopgap implementation with a proper one)
-Feature #93: Main Menu
-Feature #96/329/330/331/332/333: Player Control
-Feature #180: Object rotation and scaling.
-Feature #272: Incorrect NIF material sharing
-Feature #314: Potion usage
-Feature #324: Skill Gain
-Feature #342: Drain/fortify dynamic stats/attributes magic effects
-Feature #350: Allow console only script instructions
-Feature #352: Run scripts in console on startup
-Task #107: Refactor mw*-subsystems
-Task #325: Make CreatureStats into a class
-Task #345: Use Ogre's animation system
-Task #351: Rewrite Action class to support automatic sound playing
+------
+
+    Bug #225: Valgrind reports about 40MB of leaked memory
+    Bug #241: Some physics meshes still don't match
+    Bug #248: Some textures are too dark
+    Bug #300: Dependency on proprietary CG toolkit
+    Bug #302: Some objects don't collide although they should
+    Bug #308: Freeze in Balmora, Meldor: Armorer
+    Bug #313: openmw without a ~/.config/openmw folder segfault.
+    Bug #317: adding non-existing spell via console locks game
+    Bug #318: Wrong character normals
+    Bug #341: Building with Ogre Debug libraries does not use debug version of plugins
+    Bug #347: Crash when running openmw with --start="XYZ"
+    Bug #353: FindMyGUI.cmake breaks path on Windows
+    Bug #359: WindowManager throws exception at destruction
+    Bug #364: Laggy input on OS X due to bug in Ogre's event pump implementation
+    Feature #33: Allow objects to cross cell-borders
+    Feature #59: Dropping Items (replaced stopgap implementation with a proper one)
+    Feature #93: Main Menu
+    Feature #96/329/330/331/332/333: Player Control
+    Feature #180: Object rotation and scaling.
+    Feature #272: Incorrect NIF material sharing
+    Feature #314: Potion usage
+    Feature #324: Skill Gain
+    Feature #342: Drain/fortify dynamic stats/attributes magic effects
+    Feature #350: Allow console only script instructions
+    Feature #352: Run scripts in console on startup
+    Task #107: Refactor mw*-subsystems
+    Task #325: Make CreatureStats into a class
+    Task #345: Use Ogre's animation system
+    Task #351: Rewrite Action class to support automatic sound playing
 
 0.16.0
-
-Bug #250: OpenMW launcher erratic behaviour
-Bug #270: Crash because of underwater effect on OS X
-Bug #277: Auto-equipping in some cells not working
-Bug #294: Container GUI ignores disabled inventory menu
-Bug #297: Stats review dialog shows all skills and attribute values as 0
-Bug #298: MechanicsManager::buildPlayer does not remove previous bonuses
-Bug #299: Crash in World::disable
-Bug #306: Non-existent ~/.config/openmw "crash" the launcher.
-Bug #307: False "Data Files" location make the launcher "crash"
-Feature #81: Spell Window
-Feature #85: Alchemy Window
-Feature #181: Support for x.y script syntax
-Feature #242: Weapon and Spell icons
-Feature #254: Ingame settings window
-Feature #293: Allow "stacking" game modes
-Feature #295: Class creation dialog tooltips
-Feature #296: Clicking on the HUD elements should show/hide the respective window
-Feature #301: Direction after using a Teleport Door
-Feature #303: Allow object selection in the console
-Feature #305: Allow the use of = as a synonym for ==
-Feature #312: Compensation for slow object access in poorly written Morrowind.esm scripts
-Task #176: Restructure enabling/disabling of MW-references
-Task #283: Integrate ogre.cfg file in settings file
-Task #290: Auto-Close MW-reference related GUI windows
+------
+
+    Bug #250: OpenMW launcher erratic behaviour
+    Bug #270: Crash because of underwater effect on OS X
+    Bug #277: Auto-equipping in some cells not working
+    Bug #294: Container GUI ignores disabled inventory menu
+    Bug #297: Stats review dialog shows all skills and attribute values as 0
+    Bug #298: MechanicsManager::buildPlayer does not remove previous bonuses
+    Bug #299: Crash in World::disable
+    Bug #306: Non-existent ~/.config/openmw "crash" the launcher.
+    Bug #307: False "Data Files" location make the launcher "crash"
+    Feature #81: Spell Window
+    Feature #85: Alchemy Window
+    Feature #181: Support for x.y script syntax
+    Feature #242: Weapon and Spell icons
+    Feature #254: Ingame settings window
+    Feature #293: Allow "stacking" game modes
+    Feature #295: Class creation dialog tooltips
+    Feature #296: Clicking on the HUD elements should show/hide the respective window
+    Feature #301: Direction after using a Teleport Door
+    Feature #303: Allow object selection in the console
+    Feature #305: Allow the use of = as a synonym for ==
+    Feature #312: Compensation for slow object access in poorly written Morrowind.esm scripts
+    Task #176: Restructure enabling/disabling of MW-references
+    Task #283: Integrate ogre.cfg file in settings file
+    Task #290: Auto-Close MW-reference related GUI windows
 
 0.15.0
-
-Bug #5: Physics reimplementation (fixes various issues)
-Bug #258: Resizing arrow's background is not transparent
-Bug #268: Widening the stats window in X direction causes layout problems
-Bug #269: Topic pane in dialgoue window is too small for some longer topics
-Bug #271: Dialog choices are sorted incorrectly
-Bug #281: The single quote character is not rendered on dialog windows
-Bug #285: Terrain not handled properly in cells that are not predefined
-Bug #289: Dialogue filter isn't doing case smashing/folding for item IDs
-Feature #15: Collision with Terrain
-Feature #17: Inventory-, Container- and Trade-Windows
-Feature #44: Floating Labels above Focussed Objects
-Feature #80: Tooltips
-Feature #83: Barter Dialogue
-Feature #90: Book and Scroll Windows
-Feature #156: Item Stacking in Containers
-Feature #213: Pulsating lights
-Feature #218: Feather & Burden
-Feature #256: Implement magic effect bookkeeping
-Feature #259: Add missing information to Stats window
-Feature #260: Correct case for dialogue topics
-Feature #280: GUI texture atlasing
-Feature #291: Ability to use GMST strings from GUI layout files
-Task #255: Make MWWorld::Environment into a singleton
+------
+
+    Bug #5: Physics reimplementation (fixes various issues)
+    Bug #258: Resizing arrow's background is not transparent
+    Bug #268: Widening the stats window in X direction causes layout problems
+    Bug #269: Topic pane in dialgoue window is too small for some longer topics
+    Bug #271: Dialog choices are sorted incorrectly
+    Bug #281: The single quote character is not rendered on dialog windows
+    Bug #285: Terrain not handled properly in cells that are not predefined
+    Bug #289: Dialogue filter isn't doing case smashing/folding for item IDs
+    Feature #15: Collision with Terrain
+    Feature #17: Inventory-, Container- and Trade-Windows
+    Feature #44: Floating Labels above Focussed Objects
+    Feature #80: Tooltips
+    Feature #83: Barter Dialogue
+    Feature #90: Book and Scroll Windows
+    Feature #156: Item Stacking in Containers
+    Feature #213: Pulsating lights
+    Feature #218: Feather & Burden
+    Feature #256: Implement magic effect bookkeeping
+    Feature #259: Add missing information to Stats window
+    Feature #260: Correct case for dialogue topics
+    Feature #280: GUI texture atlasing
+    Feature #291: Ability to use GMST strings from GUI layout files
+    Task #255: Make MWWorld::Environment into a singleton
 
 0.14.0
-
-Bug #1: Meshes rendered with wrong orientation
-Bug #6/Task #220: Picking up small objects doesn't always work
-Bug #127: tcg doesn't work
-Bug #178: Compablity problems with Ogre 1.8.0 RC 1
-Bug #211: Wireframe mode (toggleWireframe command) should not apply to Console & other UI
-Bug #227: Terrain crashes when moving away from predefined cells
-Bug #229: On OS X Launcher cannot launch game if path to binary contains spaces
-Bug #235: TGA texture loading problem
-Bug #246: wireframe mode does not work in water
-Feature #8/#232: Water Rendering
-Feature #13: Terrain Rendering
-Feature #37: Render Path Grid
-Feature #66: Factions
-Feature #77: Local Map
-Feature #78: Compass/Mini-Map
-Feature #97: Render Clothing/Armour
-Feature #121: Window Pinning
-Feature #205: Auto equip
-Feature #217: Contiainer should track changes to its content
-Feature #221: NPC Dialogue Window Enhancements
-Feature #233: Game settings manager
-Feature #240: Spell List and selected spell (no GUI yet)
-Feature #243: Draw State
-Task #113: Morrowind.ini Importer
-Task #215: Refactor the sound code
-Task #216: Update MyGUI
+------
+
+    Bug #1: Meshes rendered with wrong orientation
+    Bug #6/Task #220: Picking up small objects doesn't always work
+    Bug #127: tcg doesn't work
+    Bug #178: Compablity problems with Ogre 1.8.0 RC 1
+    Bug #211: Wireframe mode (toggleWireframe command) should not apply to Console & other UI
+    Bug #227: Terrain crashes when moving away from predefined cells
+    Bug #229: On OS X Launcher cannot launch game if path to binary contains spaces
+    Bug #235: TGA texture loading problem
+    Bug #246: wireframe mode does not work in water
+    Feature #8/#232: Water Rendering
+    Feature #13: Terrain Rendering
+    Feature #37: Render Path Grid
+    Feature #66: Factions
+    Feature #77: Local Map
+    Feature #78: Compass/Mini-Map
+    Feature #97: Render Clothing/Armour
+    Feature #121: Window Pinning
+    Feature #205: Auto equip
+    Feature #217: Contiainer should track changes to its content
+    Feature #221: NPC Dialogue Window Enhancements
+    Feature #233: Game settings manager
+    Feature #240: Spell List and selected spell (no GUI yet)
+    Feature #243: Draw State
+    Task #113: Morrowind.ini Importer
+    Task #215: Refactor the sound code
+    Task #216: Update MyGUI
 
 0.13.0
-
-Bug #145: Fixed sound problems after cell change
-Bug #179: Pressing space in console triggers activation
-Bug #186: CMake doesn't use the debug versions of Ogre libraries on Linux
-Bug #189: ASCII 16 character added to console on it's activation on Mac OS X
-Bug #190: Case Folding fails with music files
-Bug #192: Keypresses write Text into Console no matter which gui element is active
-Bug #196: Collision shapes out of place
-Bug #202: ESMTool doesn't not work with localised ESM files anymore
-Bug #203: Torch lights only visible on short distance
-Bug #207: Ogre.log not written
-Bug #209: Sounds do not play
-Bug #210: Ogre crash at Dren plantation
-Bug #214: Unsupported file format version
-Bug #222: Launcher is writing openmw.cfg file to wrong location
-Feature #9: NPC Dialogue Window
-Feature #16/42: New sky/weather implementation
-Feature #40: Fading
-Feature #48: NPC Dialogue System
-Feature #117: Equipping Items (backend only, no GUI yet, no rendering of equipped items yet)
-Feature #161: Load REC_PGRD records
-Feature #195: Wireframe-mode
-Feature #198/199: Various sound effects
-Feature #206: Allow picking data path from launcher if non is set
-Task #108: Refactor window manager class
-Task #172: Sound Manager Cleanup
-Task #173: Create OpenEngine systems in the appropriate manager classes
-Task #184: Adjust MSVC and gcc warning levels
-Task #185: RefData rewrite
-Task #201: Workaround for transparency issues
-Task #208: silenced esm_reader.hpp warning
+------
+
+    Bug #145: Fixed sound problems after cell change
+    Bug #179: Pressing space in console triggers activation
+    Bug #186: CMake doesn't use the debug versions of Ogre libraries on Linux
+    Bug #189: ASCII 16 character added to console on it's activation on Mac OS X
+    Bug #190: Case Folding fails with music files
+    Bug #192: Keypresses write Text into Console no matter which gui element is active
+    Bug #196: Collision shapes out of place
+    Bug #202: ESMTool doesn't not work with localised ESM files anymore
+    Bug #203: Torch lights only visible on short distance
+    Bug #207: Ogre.log not written
+    Bug #209: Sounds do not play
+    Bug #210: Ogre crash at Dren plantation
+    Bug #214: Unsupported file format version
+    Bug #222: Launcher is writing openmw.cfg file to wrong location
+    Feature #9: NPC Dialogue Window
+    Feature #16/42: New sky/weather implementation
+    Feature #40: Fading
+    Feature #48: NPC Dialogue System
+    Feature #117: Equipping Items (backend only, no GUI yet, no rendering of equipped items yet)
+    Feature #161: Load REC_PGRD records
+    Feature #195: Wireframe-mode
+    Feature #198/199: Various sound effects
+    Feature #206: Allow picking data path from launcher if non is set
+    Task #108: Refactor window manager class
+    Task #172: Sound Manager Cleanup
+    Task #173: Create OpenEngine systems in the appropriate manager classes
+    Task #184: Adjust MSVC and gcc warning levels
+    Task #185: RefData rewrite
+    Task #201: Workaround for transparency issues
+    Task #208: silenced esm_reader.hpp warning
 
 0.12.0
-
-Bug #154: FPS Drop
-Bug #169: Local scripts continue running if associated object is deleted
-Bug #174: OpenMW fails to start if the config directory doesn't exist
-Bug #187: Missing lighting
-Bug #188: Lights without a mesh are not rendered
-Bug #191: Taking screenshot causes crash when running installed
-Feature #28: Sort out the cell load problem
-Feature #31: Allow the player to move away from pre-defined cells
-Feature #35: Use alternate storage location for modified object position
-Feature #45: NPC animations
-Feature #46: Creature Animation
-Feature #89: Basic Journal Window
-Feature #110: Automatically pick up the path of existing MW-installations
-Feature #183: More FPS display settings
-Task #19: Refactor engine class
-Task #109/Feature #162: Automate Packaging
-Task #112: Catch exceptions thrown in input handling functions
-Task #128/#168: Cleanup Configuration File Handling
-Task #131: NPC Activation doesn't work properly
-Task #144: MWRender cleanup
-Task #155: cmake cleanup
+------
+
+    Bug #154: FPS Drop
+    Bug #169: Local scripts continue running if associated object is deleted
+    Bug #174: OpenMW fails to start if the config directory doesn't exist
+    Bug #187: Missing lighting
+    Bug #188: Lights without a mesh are not rendered
+    Bug #191: Taking screenshot causes crash when running installed
+    Feature #28: Sort out the cell load problem
+    Feature #31: Allow the player to move away from pre-defined cells
+    Feature #35: Use alternate storage location for modified object position
+    Feature #45: NPC animations
+    Feature #46: Creature Animation
+    Feature #89: Basic Journal Window
+    Feature #110: Automatically pick up the path of existing MW-installations
+    Feature #183: More FPS display settings
+    Task #19: Refactor engine class
+    Task #109/Feature #162: Automate Packaging
+    Task #112: Catch exceptions thrown in input handling functions
+    Task #128/#168: Cleanup Configuration File Handling
+    Task #131: NPC Activation doesn't work properly
+    Task #144: MWRender cleanup
+    Task #155: cmake cleanup
 
 0.11.1
-
-Bug #2: Resources loading doesn't work outside of bsa files
-Bug #3: GUI does not render non-English characters
-Bug #7: openmw.cfg location doesn't match
-Bug #124: The TCL alias for ToggleCollision is missing.
-Bug #125: Some command line options can't be used from a .cfg file
-Bug #126: Toggle-type script instructions are less verbose compared with original MW
-Bug #130: NPC-Record Loading fails for some NPCs
-Bug #167: Launcher sets invalid parameters in ogre config
-Feature #10: Journal
-Feature #12: Rendering Optimisations
-Feature #23: Change Launcher GUI to a tabbed interface
-Feature #24: Integrate the OGRE settings window into the launcher
-Feature #25: Determine openmw.cfg location (Launcher)
-Feature #26: Launcher Profiles
-Feature #79: MessageBox
-Feature #116: Tab-Completion in Console
-Feature #132: --data-local and multiple --data
-Feature #143: Non-Rendering Performance-Optimisations
-Feature #150: Accessing objects in cells via ID does only work for objects with all lower case IDs
-Feature #157: Version Handling
-Task #14: Replace tabs with 4 spaces
-Task #18: Move components from global namespace into their own namespace
-Task #123: refactor header files in components/esm
+------
+
+    Bug #2: Resources loading doesn't work outside of bsa files
+    Bug #3: GUI does not render non-English characters
+    Bug #7: openmw.cfg location doesn't match
+    Bug #124: The TCL alias for ToggleCollision is missing.
+    Bug #125: Some command line options can't be used from a .cfg file
+    Bug #126: Toggle-type script instructions are less verbose compared with original MW
+    Bug #130: NPC-Record Loading fails for some NPCs
+    Bug #167: Launcher sets invalid parameters in ogre config
+    Feature #10: Journal
+    Feature #12: Rendering Optimisations
+    Feature #23: Change Launcher GUI to a tabbed interface
+    Feature #24: Integrate the OGRE settings window into the launcher
+    Feature #25: Determine openmw.cfg location (Launcher)
+    Feature #26: Launcher Profiles
+    Feature #79: MessageBox
+    Feature #116: Tab-Completion in Console
+    Feature #132: --data-local and multiple --data
+    Feature #143: Non-Rendering Performance-Optimisations
+    Feature #150: Accessing objects in cells via ID does only work for objects with all lower case IDs
+    Feature #157: Version Handling
+    Task #14: Replace tabs with 4 spaces
+    Task #18: Move components from global namespace into their own namespace
+    Task #123: refactor header files in components/esm
 
 0.10.0
+------
 
 * NPC dialogue window (not functional yet)
 * Collisions with objects
@@ -1384,6 +1409,7 @@ Task #123: refactor header files in components/esm
 * Mac OS X support is back!
 
 0.9.0
+-----
 
 * Exterior cells loading, unloading and management
 * Character Creation GUI
@@ -1393,6 +1419,7 @@ Task #123: refactor header files in components/esm
 * NPCs rendering
 
 0.8.0
+-----
 
 * GUI
 * Complete and working script engine
@@ -1402,12 +1429,14 @@ Task #123: refactor header files in components/esm
 * Tons of smaller stuff
 
 0.7.0
+-----
 
 * This release is a complete rewrite in C++.
 * All D code has been culled, and all modules have been rewritten.
 * The game is now back up to the level of rendering interior cells and moving around, but physics, sound, GUI, and scripting still remain to be ported from the old codebase.
 
 0.6.0
+-----
 
 * Coded a GUI system using MyGUI
 * Skinned MyGUI to look like Morrowind (work in progress)
@@ -1417,6 +1446,7 @@ Task #123: refactor header files in components/esm
 * Fixed Windows sound problems (replaced old openal32.dll)
 
 0.5.0
+-----
 
 * Collision detection with Bullet
 * Experimental walk & fall character physics
@@ -1428,6 +1458,7 @@ Task #123: refactor header files in components/esm
 * Various minor changes and updates
 
 0.4.0
+-----
 
 * Switched from Audiere to OpenAL
 * * (BIG thanks to Chris Robinson)
@@ -1440,6 +1471,7 @@ Task #123: refactor header files in components/esm
 * Cosmetic changes to placate gdc Wall
 
 0.3.0
+-----
 
 * Built and tested on Windows XP
 * Partial support for FreeBSD (exceptions do not work)
@@ -1454,12 +1486,13 @@ Task #123: refactor header files in components/esm
 * confirmed to work against OIS 1.0.0 (Ubuntu repository package)
 
 0.2.0
+-----
 
 * Compiles with gdc
 * Switched to DSSS for building D code
 * Includes the program esmtool
 
 0.1.0
+-----
 
 first release
-
From bc51fe4ec2a3db5df1d78f51364bdbf7ece02e86 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 17:22:12 +0100 Subject: [PATCH 170/740] Use indent instead of
 in AUTHORS.md (looks
 nicer in plaintext mode)

---
 AUTHORS.md | 331 ++++++++++++++++++++++++++---------------------------
 1 file changed, 165 insertions(+), 166 deletions(-)

diff --git a/AUTHORS.md b/AUTHORS.md
index f6da26e77..d2c5cdc04 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -9,184 +9,183 @@ If you feel your name is missing from this list, please notify a developer.
 
 Programmers
 -----------
-
-Marc Zinnschlag (Zini) - Lead Programmer/Project Manager
-
-Adam Hogan (aurix)
-Aleksandar Jovanov
-Alex Haddad (rainChu)
-Alex McKibben (WeirdSexy)
-Alexander Nadeau (wareya)
-Alexander Olofsson (Ace)
-Artem Kotsynyak (greye)
-Arthur Moore (EmperorArthur)
-athile
-Bret Curtis (psi29a)
-Britt Mathis (galdor557)
-cc9cii
-Chris Boyce (slothlife)
-Chris Robinson (KittyCat)
-Cory F. Cohen (cfcohen)
-Cris Mihalache (Mirceam)
-darkf
-Dmitry Shkurskiy (endorph)
-Douglas Diniz (Dgdiniz)
-Douglas Mencken (dougmencken)
-dreamer-dead
-dteviot
-Edmondo Tommasina (edmondo)
-Eduard Cot (trombonecot)
-Eli2
-Emanuel Guével (potatoesmaster)
-eroen
-Fil Krynicki (filkry)
-Gašper Sedej
-gugus/gus
-Hallfaer Tuilinn
-Internecine
-Jacob Essex (Yacoby)
-Jannik Heller (scrawl)
-Jason Hooks (jhooks)
-jeaye
-Jeffrey Haines (Jyby)
-Jengerer
-Joel Graff (graffy)
-John Blomberg (fstp)
-Jordan Ayers
-Jordan Milne
-Julien Voisin (jvoisin/ap0)
-Karl-Felix Glatzer (k1ll)
-Kevin Poitra (PuppyKevin)
-Lars Söderberg (Lazaroth)
-lazydev
-Leon Saunders (emoose)
-Lukasz Gromanowski (lgro)
-Manuel Edelmann (vorenon)
-Marc Bouvier (CramitDeFrog)
-Marcin Hulist (Gohan)
-Mark Siewert (mark76)
-Marco Melletti (mellotanica)
-Marco Schulze
-Mateusz Kołaczek (PL_kolek)
-megaton
-Michael Hogan (Xethik)
-Michael Mc Donnell
-Michael Papageorgiou (werdanith)
-Michał Bień (Glorf)
-Miroslav Puda (pakanek)
-MiroslavR
-Narmo
-Nathan Jeffords (blunted2night)
-Nikolay Kasyanov (corristo)
-nobrakal
-Nolan Poe (nopoe)
-Paul McElroy (Greendogo)
-Pieter van der Kloet (pvdk)
-Radu-Marius Popovici (rpopovici)
-riothamus
-Robert MacGregor (Ragora)
-Rohit Nirmal
-Roman Melnik (Kromgart)
-Roman Proskuryakov (humbug)
-sandstranger
-Sandy Carter (bwrsandman)
-Scott Howard
-Sebastian Wick (swick)
-Sergey Shambir
-sir_herrbatka
-Stefan Galowicz (bogglez)
-Stanislav Bobrov (Jiub)
-Sylvain Thesnieres (Garvek)
-terrorfisch
-Thomas Luppi (Digmaster)
-Tom Mason (wheybags)
-Torben Leif Carrington (TorbenC)
-viadanna
-Vincent Heuken
-vocollapse
-
+ + Marc Zinnschlag (Zini) - Lead Programmer/Project Manager + + Adam Hogan (aurix) + Aleksandar Jovanov + Alex Haddad (rainChu) + Alex McKibben (WeirdSexy) + Alexander Nadeau (wareya) + Alexander Olofsson (Ace) + Artem Kotsynyak (greye) + Arthur Moore (EmperorArthur) + athile + Bret Curtis (psi29a) + Britt Mathis (galdor557) + cc9cii + Chris Boyce (slothlife) + Chris Robinson (KittyCat) + Cory F. Cohen (cfcohen) + Cris Mihalache (Mirceam) + darkf + Dmitry Shkurskiy (endorph) + Douglas Diniz (Dgdiniz) + Douglas Mencken (dougmencken) + dreamer-dead + dteviot + Edmondo Tommasina (edmondo) + Eduard Cot (trombonecot) + Eli2 + Emanuel Guével (potatoesmaster) + eroen + Fil Krynicki (filkry) + Gašper Sedej + gugus/gus + Hallfaer Tuilinn + Internecine + Jacob Essex (Yacoby) + Jannik Heller (scrawl) + Jason Hooks (jhooks) + jeaye + Jeffrey Haines (Jyby) + Jengerer + Joel Graff (graffy) + John Blomberg (fstp) + Jordan Ayers + Jordan Milne + Julien Voisin (jvoisin/ap0) + Karl-Felix Glatzer (k1ll) + Kevin Poitra (PuppyKevin) + Lars Söderberg (Lazaroth) + lazydev + Leon Saunders (emoose) + Lukasz Gromanowski (lgro) + Manuel Edelmann (vorenon) + Marc Bouvier (CramitDeFrog) + Marcin Hulist (Gohan) + Mark Siewert (mark76) + Marco Melletti (mellotanica) + Marco Schulze + Mateusz Kołaczek (PL_kolek) + megaton + Michael Hogan (Xethik) + Michael Mc Donnell + Michael Papageorgiou (werdanith) + Michał Bień (Glorf) + Miroslav Puda (pakanek) + MiroslavR + Narmo + Nathan Jeffords (blunted2night) + Nikolay Kasyanov (corristo) + nobrakal + Nolan Poe (nopoe) + Paul McElroy (Greendogo) + Pieter van der Kloet (pvdk) + Radu-Marius Popovici (rpopovici) + riothamus + Robert MacGregor (Ragora) + Rohit Nirmal + Roman Melnik (Kromgart) + Roman Proskuryakov (humbug) + sandstranger + Sandy Carter (bwrsandman) + Scott Howard + Sebastian Wick (swick) + Sergey Shambir + sir_herrbatka + Stefan Galowicz (bogglez) + Stanislav Bobrov (Jiub) + Sylvain Thesnieres (Garvek) + terrorfisch + Thomas Luppi (Digmaster) + Tom Mason (wheybags) + Torben Leif Carrington (TorbenC) + viadanna + Vincent Heuken + vocollapse + Packagers --------- -
-Alexander Olofsson (Ace) - Windows
-Bret Curtis (psi29a) - Ubuntu Linux
-Edmondo Tommasina (edmondo) - Gentoo Linux
-Julian Ospald (hasufell) - Gentoo Linux
-Karl-Felix Glatzer (k1ll) - Linux Binaries
-Kenny Armstrong (artorius) - Fedora Linux
-Nikolay Kasyanov (corristo) - Mac OS X
-Sandy Carter (bwrsandman) - Arch Linux
-
+ + Alexander Olofsson (Ace) - Windows + Bret Curtis (psi29a) - Ubuntu Linux + Edmondo Tommasina (edmondo) - Gentoo Linux + Julian Ospald (hasufell) - Gentoo Linux + Karl-Felix Glatzer (k1ll) - Linux Binaries + Kenny Armstrong (artorius) - Fedora Linux + Nikolay Kasyanov (corristo) - Mac OS X + Sandy Carter (bwrsandman) - Arch Linux + Public Relations and Translations --------------------------------- -
-Alex McKibben (WeirdSexy) - Podcaster
-Artem Kotsynyak (greye) - Russian News Writer
-Jim Clauwaert (Zedd) - Public Outreach
-Julien Voisin (jvoisin/ap0) - French News Writer
-Tom Koenderink (Okulo) - English News Writer
-Lukasz Gromanowski (lgro) - English News Writer
-Mickey Lyle (raevol) - Release Manager
-Pithorn - Chinese News Writer
-sir_herrbatka - Polish News Writer
-Dawid Lakomy (Vedyimyn) - Polish News Writer
-
+ + Alex McKibben (WeirdSexy) - Podcaster + Artem Kotsynyak (greye) - Russian News Writer + Jim Clauwaert (Zedd) - Public Outreach + Julien Voisin (jvoisin/ap0) - French News Writer + Tom Koenderink (Okulo) - English News Writer + Lukasz Gromanowski (lgro) - English News Writer + Mickey Lyle (raevol) - Release Manager + Pithorn - Chinese News Writer + sir_herrbatka - Polish News Writer + Dawid Lakomy (Vedyimyn) - Polish News Writer + Website ------- -
-Lukasz Gromanowski (Lgro) - Website Administrator
-Ryan Sardonic (Wry) - Wiki Editor
-sir_herrbatka - Forum Administrator
-
+ + Lukasz Gromanowski (Lgro) - Website Administrator + Ryan Sardonic (Wry) - Wiki Editor + sir_herrbatka - Forum Administrator + Formula Research ---------------- -
-Hrnchamd
-Epsilon
-fragonard
-Greendogo
-HiPhish
-modred11
-Myckel
-natirips
-Sadler
-
+ + Hrnchamd + Epsilon + fragonard + Greendogo + HiPhish + modred11 + Myckel + natirips + Sadler + Artwork ------- -
-Necrod - OpenMW Logo
-Mickey Lyle (raevol) - Wordpress Theme
-Tom Koenderink (Okulo), SirHerrbatka, crysthala, Shnatsel - OpenMW Editor Icons
-
+ + Necrod - OpenMW Logo + Mickey Lyle (raevol) - Wordpress Theme + Tom Koenderink (Okulo), SirHerrbatka, crysthala, Shnatsel - OpenMW Editor Icons + Inactive Contributors --------------------- -
-Ardekantur
-Armin Preiml
-Berulacks
-Carl Maxwell
-Diggory Hardy
-Dmitry Marakasov (AMDmi3)
-ElderTroll
-guidoj
-Jan-Peter Nilsson (peppe)
-Jan Borsodi
-Josua Grawitter
-juanmnzsk8
-Kingpix
-Lordrea
-Michal Sciubidlo
-Nicolay Korslund
-Nekochan
-pchan3
-penguinroad
-psi29a
-sergoz
-spyboot
-Star-Demon
-Thoronador
-Yuri Krupenin
-
+ + Ardekantur + Armin Preiml + Berulacks + Carl Maxwell + Diggory Hardy + Dmitry Marakasov (AMDmi3) + ElderTroll + guidoj + Jan-Peter Nilsson (peppe) + Jan Borsodi + Josua Grawitter + juanmnzsk8 + Kingpix + Lordrea + Michal Sciubidlo + Nicolay Korslund + Nekochan + pchan3 + penguinroad + psi29a + sergoz + spyboot + Star-Demon + Thoronador + Yuri Krupenin Additional Credits ------------------ From 38c6859281ede92eb33fb5254f68b4b2c0386788 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 17:27:38 +0100 Subject: [PATCH 171/740] Add some Getting Started links from the wiki to Readme --- README.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index ff5185b5d..8bc3c0280 100644 --- a/README.md +++ b/README.md @@ -16,15 +16,16 @@ Morrowind by Bethesda Softworks. You need to own and install the original game f Font Licenses: * DejaVuLGCSansMono.ttf: custom (see docs/license/DejaVu Font License.txt for more information) -Installation -============ - -Head to [Downloads](http://openmw.org/downloads/) to find a packaged release for your platform of choice. - -Build from source -================= - -https://wiki.openmw.org/index.php?title=Development_Environment_Setup +Getting Started +=============== + +* [Official forums](https://forum.openmw.org/) +* [Installation instructions](https://wiki.openmw.org/index.php?title=Installation_Instructions) +* [Build from source](https://wiki.openmw.org/index.php?title=Development_Environment_Setup) +* [Testing the game](https://wiki.openmw.org/index.php?title=Testing) +* [How to contribute](https://wiki.openmw.org/index.php?title=Contribution_Wanted) +* [Report a bug](http://bugs.openmw.org/projects/openmw) - read the [guidelines](before submitting your first bug!) +* [Known issues] (http://bugs.openmw.org/projects/openmw/issues?utf8=%E2%9C%93&set_filter=1&f%5B%5D=status_id&op%5Bstatus_id%5D=%3D&v%5Bstatus_id%5D%5B%5D=7&f%5B%5D=tracker_id&op%5Btracker_id%5D=%3D&v%5Btracker_id%5D%5B%5D=1&f%5B%5D=&c%5B%5D=project&c%5B%5D=tracker&c%5B%5D=status&c%5B%5D=priority&c%5B%5D=subject&c%5B%5D=assigned_to&c%5B%5D=updated_on&group_by=tracker) The data path ============= From d4740b7533fe06bad16db365cd1e63be51e7ca3e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 17:36:36 +0100 Subject: [PATCH 172/740] Formatting, link fix --- README.md | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 8bc3c0280..168684e8d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -OpenMW: A reimplementation of The Elder Scrolls III: Morrowind -============================================================== +OpenMW +====== [![Build Status](https://travis-ci.org/OpenMW/openmw.svg?branch=coverity_scan)](https://travis-ci.org/OpenMW/openmw) @@ -17,23 +17,23 @@ Font Licenses: * DejaVuLGCSansMono.ttf: custom (see docs/license/DejaVu Font License.txt for more information) Getting Started -=============== +--------------- * [Official forums](https://forum.openmw.org/) * [Installation instructions](https://wiki.openmw.org/index.php?title=Installation_Instructions) * [Build from source](https://wiki.openmw.org/index.php?title=Development_Environment_Setup) * [Testing the game](https://wiki.openmw.org/index.php?title=Testing) * [How to contribute](https://wiki.openmw.org/index.php?title=Contribution_Wanted) -* [Report a bug](http://bugs.openmw.org/projects/openmw) - read the [guidelines](before submitting your first bug!) +* [Report a bug](http://bugs.openmw.org/projects/openmw) - read the [guidelines](https://wiki.openmw.org/index.php?title=Bug_Reporting_Guidelines) before submitting your first bug! * [Known issues] (http://bugs.openmw.org/projects/openmw/issues?utf8=%E2%9C%93&set_filter=1&f%5B%5D=status_id&op%5Bstatus_id%5D=%3D&v%5Bstatus_id%5D%5B%5D=7&f%5B%5D=tracker_id&op%5Btracker_id%5D=%3D&v%5Btracker_id%5D%5B%5D=1&f%5B%5D=&c%5B%5D=project&c%5B%5D=tracker&c%5B%5D=status&c%5B%5D=priority&c%5B%5D=subject&c%5B%5D=assigned_to&c%5B%5D=updated_on&group_by=tracker) The data path -============= +------------- The data path tells OpenMW where to find your Morrowind files. If you run the launcher, OpenMW should be able to pick up the location of these files on its own, if both Morrowind and OpenMW are installed properly (installing Morrowind under WINE is considered a proper install). Command line options -==================== +--------------------
 Syntax: openmw 
@@ -91,8 +91,3 @@ Allowed options:
   --no-grab                             Don't grab mouse cursor
   --activate-dist arg (=-1)             activation distance override
 
- -Changelog -========= - -See CHANGELOG.md From fcbf7d7deb602456f7140ebe68be428903d9371f Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 11 Jan 2015 08:33:33 +1300 Subject: [PATCH 173/740] Fixed string formatting minor error found by Mingun. --- apps/launcher/datafilespage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 8429aaadc..245665421 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -302,7 +302,7 @@ bool Launcher::DataFilesPage::showDeleteMessageBox (const QString &text) msgBox.setWindowTitle(tr("Delete Content List")); msgBox.setIcon(QMessageBox::Warning); msgBox.setStandardButtons(QMessageBox::Cancel); - msgBox.setText(tr("Are you sure you want to delete %0?").arg(text)); + msgBox.setText(tr("Are you sure you want to delete %1?").arg(text)); QAbstractButton *deleteButton = msgBox.addButton(tr("Delete"), QMessageBox::ActionRole); From 91571f51be4f6ecc339ffb2354e44cb35b55b5c3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 15:27:03 +0100 Subject: [PATCH 174/740] Ogre crash workaround (Fixes #1745) --- apps/openmw/mwrender/animation.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index ea40721cb..bf161442e 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -169,6 +169,9 @@ struct AddGlow instance->setProperty("env_map", sh::makeProperty(new sh::BooleanValue(true))); instance->setProperty("env_map_color", sh::makeProperty(new sh::Vector3(mColor->x, mColor->y, mColor->z))); + // Workaround for crash in Ogre (https://bitbucket.org/sinbad/ogre/pull-request/447/fix-shadows-crash-for-textureunitstates/diff) + // Remove when the fix is merged + instance->getMaterial()->setShadowCasterMaterial("openmw_shadowcaster_noalpha"); } }; From 579f5d232f5ea87716f3bfb44272052325a7ba75 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 23:21:39 +0100 Subject: [PATCH 175/740] Move interactive messageBox to separate function --- apps/openmw/mwbase/windowmanager.hpp | 4 ++- apps/openmw/mwdialogue/journalimp.cpp | 4 +-- apps/openmw/mwgui/windowmanagerimp.cpp | 35 +++++++++++++------- apps/openmw/mwgui/windowmanagerimp.hpp | 5 ++- apps/openmw/mwinput/inputmanagerimp.cpp | 3 +- apps/openmw/mwmechanics/npcstats.cpp | 6 ++-- apps/openmw/mwscript/containerextensions.cpp | 6 ++-- apps/openmw/mwscript/interpretercontext.cpp | 5 ++- apps/openmw/mwstate/statemanagerimp.cpp | 6 ++-- apps/openmw/mwworld/worldimp.cpp | 2 +- 10 files changed, 44 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index fb35157e8..3e957ef14 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -240,9 +240,11 @@ namespace MWBase /** No guarentee of actually closing the window **/ virtual void exitCurrentGuiMode() = 0; - virtual void messageBox (const std::string& message, const std::vector& buttons = std::vector(), enum MWGui::ShowInDialogueMode showInDialogueMode = MWGui::ShowInDialogueMode_IfPossible) = 0; + virtual void messageBox (const std::string& message, enum MWGui::ShowInDialogueMode showInDialogueMode = MWGui::ShowInDialogueMode_IfPossible) = 0; virtual void staticMessageBox(const std::string& message) = 0; virtual void removeStaticMessageBox() = 0; + virtual void interactiveMessageBox (const std::string& message, + const std::vector& buttons = std::vector(), bool block=false) = 0; /// returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox) virtual int readPressedButton() = 0; diff --git a/apps/openmw/mwdialogue/journalimp.cpp b/apps/openmw/mwdialogue/journalimp.cpp index 9497347e3..e8d5375e1 100644 --- a/apps/openmw/mwdialogue/journalimp.cpp +++ b/apps/openmw/mwdialogue/journalimp.cpp @@ -92,9 +92,7 @@ namespace MWDialogue quest.addEntry (entry); // we are doing slicing on purpose here - std::vector empty; - std::string notification = "#{sJournalEntry}"; - MWBase::Environment::get().getWindowManager()->messageBox (notification, empty); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sJournalEntry}"); } void Journal::setJournalIndex (const std::string& id, int index) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 5d737ec41..7d9e10d8f 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -805,19 +805,30 @@ namespace MWGui } } - void WindowManager::messageBox (const std::string& message, const std::vector& buttons, enum MWGui::ShowInDialogueMode showInDialogueMode) - { - if (buttons.empty()) { - /* If there are no buttons, and there is a dialogue window open, messagebox goes to the dialogue window */ - if (getMode() == GM_Dialogue && showInDialogueMode != MWGui::ShowInDialogueMode_Never) { - mDialogueWindow->addMessageBox(MyGUI::LanguageManager::getInstance().replaceTags(message)); - } else if (showInDialogueMode != MWGui::ShowInDialogueMode_Only) { - mMessageBoxManager->createMessageBox(message); + 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) + { + while (mMessageBoxManager->readPressedButton() == -1 + && !MWBase::Environment::get().getStateManager()->hasQuitRequest()) + { + MWBase::Environment::get().getInputManager()->update(0, true, false); + + mRendering->getWindow()->update(); } - } else { - mMessageBoxManager->createInteractiveMessageBox(message, buttons); - MWBase::Environment::get().getInputManager()->changeInputMode(isGuiMode()); - updateVisible(); + } + } + + void WindowManager::messageBox (const std::string& message, enum MWGui::ShowInDialogueMode showInDialogueMode) + { + if (getMode() == GM_Dialogue && showInDialogueMode != MWGui::ShowInDialogueMode_Never) { + mDialogueWindow->addMessageBox(MyGUI::LanguageManager::getInstance().replaceTags(message)); + } else if (showInDialogueMode != MWGui::ShowInDialogueMode_Only) { + mMessageBoxManager->createMessageBox(message); } } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 015f200d5..44d5819c2 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -238,9 +238,12 @@ namespace MWGui ///Gracefully attempts to exit the topmost GUI mode virtual void exitCurrentGuiMode(); - virtual void messageBox (const std::string& message, const std::vector& buttons = std::vector(), enum MWGui::ShowInDialogueMode showInDialogueMode = MWGui::ShowInDialogueMode_IfPossible); + virtual void messageBox (const std::string& message, enum MWGui::ShowInDialogueMode showInDialogueMode = MWGui::ShowInDialogueMode_IfPossible); virtual void staticMessageBox(const std::string& message); virtual void removeStaticMessageBox(); + virtual void interactiveMessageBox (const std::string& message, + const std::vector& buttons = std::vector(), bool block=false); + virtual int readPressedButton (); ///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox) virtual void onFrame (float frameDuration); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index ece189c75..846cce6a2 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -743,8 +743,7 @@ namespace MWInput { mEngine.screenshot(); - std::vector empty; - MWBase::Environment::get().getWindowManager()->messageBox ("Screenshot saved", empty); + MWBase::Environment::get().getWindowManager()->messageBox ("Screenshot saved"); } void InputManager::toggleInventory() diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index ec7b232a2..ba01caf95 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -257,18 +257,16 @@ void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &clas /// \todo check if character is the player, if levelling is ever implemented for NPCs MWBase::Environment::get().getSoundManager ()->playSound ("skillraise", 1, 1); - std::vector noButtons; - std::stringstream message; message << boost::format(MWBase::Environment::get().getWindowManager ()->getGameSettingString ("sNotifyMessage39", "")) % std::string("#{" + ESM::Skill::sSkillNameIds[skillIndex] + "}") % static_cast (base); - MWBase::Environment::get().getWindowManager ()->messageBox(message.str(), noButtons, MWGui::ShowInDialogueMode_Never); + MWBase::Environment::get().getWindowManager ()->messageBox(message.str(), MWGui::ShowInDialogueMode_Never); if (mLevelProgress >= gmst.find("iLevelUpTotal")->getInt()) { // levelup is possible now - MWBase::Environment::get().getWindowManager ()->messageBox ("#{sLevelUpMsg}", noButtons, MWGui::ShowInDialogueMode_Never); + MWBase::Environment::get().getWindowManager ()->messageBox ("#{sLevelUpMsg}", MWGui::ShowInDialogueMode_Never); } getSkill (skillIndex).setBase (base); diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 96e30e396..58b1b375b 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -71,8 +71,7 @@ namespace MWScript msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage61}"); msgBox = boost::str(boost::format(msgBox) % count % itemName); } - std::vector noButtons; - MWBase::Environment::get().getWindowManager()->messageBox(msgBox, noButtons, MWGui::ShowInDialogueMode_Only); + MWBase::Environment::get().getWindowManager()->messageBox(msgBox, MWGui::ShowInDialogueMode_Only); } } }; @@ -143,8 +142,7 @@ namespace MWScript msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage62}"); msgBox = boost::str (boost::format(msgBox) % itemName); } - std::vector noButtons; - MWBase::Environment::get().getWindowManager()->messageBox(msgBox, noButtons, MWGui::ShowInDialogueMode_Only); + MWBase::Environment::get().getWindowManager()->messageBox(msgBox, MWGui::ShowInDialogueMode_Only); } } }; diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 5d52033a8..5cc4d69b6 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -200,7 +200,10 @@ namespace MWScript void InterpreterContext::messageBox (const std::string& message, const std::vector& buttons) { - MWBase::Environment::get().getWindowManager()->messageBox (message, buttons); + if (buttons.empty()) + MWBase::Environment::get().getWindowManager()->messageBox (message); + else + MWBase::Environment::get().getWindowManager()->interactiveMessageBox(message, buttons); } void InterpreterContext::report (const std::string& message) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 94b1ab4dc..8ae7fb355 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -118,7 +118,7 @@ void MWState::StateManager::askLoadRecent() std::string message = MWBase::Environment::get().getWindowManager()->getGameSettingString("sLoadLastSaveMsg", tag); size_t pos = message.find(tag); message.replace(pos, tag.length(), lastSave.mProfile.mDescription); - MWBase::Environment::get().getWindowManager()->messageBox(message, buttons); + MWBase::Environment::get().getWindowManager()->interactiveMessageBox(message, buttons); mAskLoadRecent = true; } } @@ -259,7 +259,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot std::vector buttons; buttons.push_back("#{sOk}"); - MWBase::Environment::get().getWindowManager()->messageBox(error.str(), buttons); + MWBase::Environment::get().getWindowManager()->interactiveMessageBox(error.str(), buttons); // If no file was written, clean up the slot if (slot && !boost::filesystem::exists(slot->mPath)) @@ -459,7 +459,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::str std::vector buttons; buttons.push_back("#{sOk}"); - MWBase::Environment::get().getWindowManager()->messageBox(error.str(), buttons); + MWBase::Environment::get().getWindowManager()->interactiveMessageBox(error.str(), buttons); } } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f9642226b..810b7f80d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3047,7 +3047,7 @@ namespace MWWorld std::vector buttons; buttons.push_back("#{sOk}"); - MWBase::Environment::get().getWindowManager()->messageBox(message, buttons); + MWBase::Environment::get().getWindowManager()->interactiveMessageBox(message, buttons); } } From f9227beedd787e2386ce85310b11c663b07c6770 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Jan 2015 23:58:55 +0100 Subject: [PATCH 176/740] Add warning when loading a savegame that depends on non-existing content files (Fixes #2261) --- apps/openmw/mwgui/messagebox.cpp | 5 +-- apps/openmw/mwgui/messagebox.hpp | 3 +- apps/openmw/mwgui/windowmanagerimp.cpp | 5 +-- apps/openmw/mwstate/statemanagerimp.cpp | 33 +++++++++++++++++++ apps/openmw/mwstate/statemanagerimp.hpp | 2 ++ .../openmw_interactive_messagebox.layout | 2 +- files/mygui/openmw_layers.xml | 1 + 7 files changed, 45 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index c45136eb3..9cb778ea2 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -146,10 +146,11 @@ namespace MWGui return false; } - int MessageBoxManager::readPressedButton () + int MessageBoxManager::readPressedButton (bool reset) { int pressed = mLastButtonPressed; - mLastButtonPressed = -1; + if (reset) + mLastButtonPressed = -1; return pressed; } diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index 59804e097..48a92c844 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -33,7 +33,8 @@ namespace MWGui bool removeMessageBox (MessageBox *msgbox); - int readPressedButton (); + /// @param reset Reset the pressed button to -1 after reading it. + int readPressedButton (bool reset=true); typedef MyGUI::delegates::CMultiDelegate1 EventHandle_Int; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 7d9e10d8f..077ca4fe3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -607,7 +607,7 @@ namespace MWGui // GM_Loading uses a texture of the last rendered frame so everything previously visible will be rendered. mHud->setVisible(false); mToolTips->setVisible(false); - setCursorVisible(false); + setCursorVisible(mMessageBoxManager && mMessageBoxManager->isInteractiveMessageBox()); break; default: // Unsupported mode, switch back to game @@ -813,9 +813,10 @@ namespace MWGui if (block) { - while (mMessageBoxManager->readPressedButton() == -1 + while (mMessageBoxManager->readPressedButton(false) == -1 && !MWBase::Environment::get().getStateManager()->hasQuitRequest()) { + mMessageBoxManager->onFrame(0.f); MWBase::Environment::get().getInputManager()->update(0, true, false); mRendering->getWindow()->update(); diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 8ae7fb355..f756ee42a 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -353,6 +353,12 @@ void MWState::StateManager::loadGame (const Character *character, const std::str { ESM::SavedGame profile; profile.load(reader); + if (!verifyProfile(profile)) + { + cleanup (true); + MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); + return; + } mTimePlayed = profile.mTimePlayed; } break; @@ -517,3 +523,30 @@ void MWState::StateManager::update (float duration) } } } + +bool MWState::StateManager::verifyProfile(const ESM::SavedGame& profile) const +{ + const std::vector& selectedContentFiles = MWBase::Environment::get().getWorld()->getContentFiles(); + bool notFound = false; + for (std::vector::const_iterator it = profile.mContentFiles.begin(); + it != profile.mContentFiles.end(); ++it) + { + if (std::find(selectedContentFiles.begin(), selectedContentFiles.end(), *it) + == selectedContentFiles.end()) + { + notFound = true; + break; + } + } + if (notFound) + { + std::vector buttons; + buttons.push_back("#{sYes}"); + buttons.push_back("#{sNo}"); + MWBase::Environment::get().getWindowManager()->interactiveMessageBox("#{sMissingMastersMsg}", buttons, true); + int selectedButton = MWBase::Environment::get().getWindowManager()->readPressedButton(); + if (selectedButton == 1 || selectedButton == -1) + return false; + } + return true; +} diff --git a/apps/openmw/mwstate/statemanagerimp.hpp b/apps/openmw/mwstate/statemanagerimp.hpp index 956a2d73c..37f38f8df 100644 --- a/apps/openmw/mwstate/statemanagerimp.hpp +++ b/apps/openmw/mwstate/statemanagerimp.hpp @@ -23,6 +23,8 @@ namespace MWState void cleanup (bool force = false); + bool verifyProfile (const ESM::SavedGame& profile) const; + std::map buildContentFileIndexMap (const ESM::ESMReader& reader) const; public: diff --git a/files/mygui/openmw_interactive_messagebox.layout b/files/mygui/openmw_interactive_messagebox.layout index a1dbc5aa8..a72bebf3a 100644 --- a/files/mygui/openmw_interactive_messagebox.layout +++ b/files/mygui/openmw_interactive_messagebox.layout @@ -1,7 +1,7 @@ - + diff --git a/files/mygui/openmw_layers.xml b/files/mygui/openmw_layers.xml index 38a98d133..50f83aaa2 100644 --- a/files/mygui/openmw_layers.xml +++ b/files/mygui/openmw_layers.xml @@ -11,6 +11,7 @@ + From 7aa0f887c0d992c96fa260e06b40234a50ca76b8 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 11 Jan 2015 12:20:22 +1300 Subject: [PATCH 177/740] Minor changes to ESM::RefNum 1. Changed mIndex to unsigned, to solve potential implementation defined behavior with right shift. 2. Refactoring to minimize use of magic number -1 to indicate "no Content File". --- apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwscript/miscextensions.cpp | 2 +- apps/openmw/mwworld/cellref.cpp | 8 ++++++-- apps/openmw/mwworld/cellref.hpp | 3 +++ apps/openmw/mwworld/cellreflist.hpp | 2 +- apps/openmw/mwworld/cellstore.cpp | 10 +++++----- apps/openmw/mwworld/manualref.hpp | 3 +-- apps/openmw/mwworld/worldimp.cpp | 4 ++-- components/esm/cellref.cpp | 3 +-- components/esm/cellref.hpp | 8 ++++++-- 11 files changed, 28 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index e21676f10..9eb5b1b69 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -872,7 +872,7 @@ namespace MWClass { // Note we do not respawn moved references in the cell they were moved to. Instead they are respawned in the original cell. // This also means we cannot respawn dynamically placed references with no content file connection. - if (ptr.getCellRef().getRefNum().mContentFile != -1) + if (ptr.getCellRef().hasContentFile()) { if (ptr.getRefData().getCount() == 0) ptr.getRefData().setCount(1); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 22263d820..596b56acd 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1331,7 +1331,7 @@ namespace MWClass { // Note we do not respawn moved references in the cell they were moved to. Instead they are respawned in the original cell. // This also means we cannot respawn dynamically placed references with no content file connection. - if (ptr.getCellRef().getRefNum().mContentFile != -1) + if (ptr.getCellRef().hasContentFile()) { if (ptr.getRefData().getCount() == 0) ptr.getRefData().setCount(1); diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index f20c9967d..d4431016a 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -1035,7 +1035,7 @@ namespace MWScript msg << "Content file: "; - if (ptr.getCellRef().getRefNum().mContentFile == -1) + if (!ptr.getCellRef().hasContentFile()) msg << "[None]" << std::endl; else { diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index 3ea3ed8bf..aa6627de5 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -10,10 +10,14 @@ namespace MWWorld return mCellRef.mRefNum; } + bool CellRef::hasContentFile() const + { + return getRefNum().hasContentFile(); + } + void CellRef::unsetRefNum() { - mCellRef.mRefNum.mContentFile = -1; - mCellRef.mRefNum.mIndex = 0; + getRefNum().unset(); } std::string CellRef::getRefId() const diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index d7c0ce221..a7ffbe08b 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -28,6 +28,9 @@ namespace MWWorld // Set RefNum to its default state. void unsetRefNum(); + /// Does the RefNum have a content file? + bool hasContentFile() const; + // Id of object being referenced std::string getRefId() const; diff --git a/apps/openmw/mwworld/cellreflist.hpp b/apps/openmw/mwworld/cellreflist.hpp index 037de8645..2c5e01aaa 100644 --- a/apps/openmw/mwworld/cellreflist.hpp +++ b/apps/openmw/mwworld/cellreflist.hpp @@ -28,7 +28,7 @@ namespace MWWorld { for (typename List::iterator iter (mList.begin()); iter!=mList.end(); ++iter) if (!iter->mData.isDeletedByContentFile() - && (iter->mRef.getRefNum().mContentFile != -1 || iter->mData.getCount() > 0) + && (iter->mRef.hasContentFile() || iter->mData.getCount() > 0) && iter->mRef.getRefId() == name) return &*iter; diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index f1a8451ea..1c0e7e385 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -72,12 +72,12 @@ namespace iter (collection.mList.begin()); iter!=collection.mList.end(); ++iter) { - if (!iter->mData.hasChanged() && !iter->mRef.hasChanged() && iter->mRef.getRefNum().mContentFile != -1) + if (!iter->mData.hasChanged() && !iter->mRef.hasChanged() && iter->mRef.hasContentFile()) { // Reference that came from a content file and has not been changed -> ignore continue; } - if (iter->mData.getCount()==0 && iter->mRef.getRefNum().mContentFile==-1) + if (iter->mData.getCount()==0 && !iter->mRef.hasContentFile()) { // Deleted reference that did not come from a content file -> ignore continue; @@ -102,7 +102,7 @@ namespace state.load (reader); // If the reference came from a content file, make sure this content file is loaded - if (state.mRef.mRefNum.mContentFile != -1) + if (state.mRef.mRefNum.hasContentFile()) { std::map::const_iterator iter = contentFileMap.find (state.mRef.mRefNum.mContentFile); @@ -121,7 +121,7 @@ namespace if (!record) return; - if (state.mRef.mRefNum.mContentFile != -1) + if (state.mRef.mRefNum.hasContentFile()) { for (typename MWWorld::CellRefList::List::iterator iter (collection.mList.begin()); iter!=collection.mList.end(); ++iter) @@ -487,7 +487,7 @@ namespace MWWorld mCell->restore (esm[index], i); ESM::CellRef ref; - ref.mRefNum.mContentFile = -1; + ref.mRefNum.mContentFile = ESM::RefNum::RefNum_NoContentFile; // Get each reference in turn bool deleted = false; diff --git a/apps/openmw/mwworld/manualref.hpp b/apps/openmw/mwworld/manualref.hpp index 0becd7524..4eb93543b 100644 --- a/apps/openmw/mwworld/manualref.hpp +++ b/apps/openmw/mwworld/manualref.hpp @@ -24,8 +24,7 @@ namespace MWWorld const T* base = list.find(name); ESM::CellRef cellRef; - cellRef.mRefNum.mIndex = 0; - cellRef.mRefNum.mContentFile = -1; + cellRef.mRefNum.unset(); cellRef.mRefID = name; cellRef.mScale = 1; cellRef.mFactionRank = 0; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f9642226b..7dfd41408 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1089,7 +1089,7 @@ namespace MWWorld void World::undeleteObject(const Ptr& ptr) { - if (ptr.getCellRef().getRefNum().mContentFile == -1) + if (!ptr.getCellRef().hasContentFile()) return; if (ptr.getRefData().isDeleted()) { @@ -3206,7 +3206,7 @@ namespace MWWorld { // Can't reset actors that were moved to a different cell, because we don't know what cell they came from. // This could be fixed once we properly track actor cell changes, but may not be desirable behaviour anyhow. - if (ptr.getClass().isActor() && ptr.getCellRef().getRefNum().mContentFile != -1) + if (ptr.getClass().isActor() && ptr.getCellRef().hasContentFile()) { const ESM::Position& origPos = ptr.getCellRef().getPosition(); MWBase::Environment::get().getWorld()->moveObject(ptr, origPos.pos[0], origPos.pos[1], origPos.pos[2]); diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index 29d26d013..f93fe1535 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -129,8 +129,7 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) cons void ESM::CellRef::blank() { - mRefNum.mIndex = 0; - mRefNum.mContentFile = -1; + mRefNum.unset(); mRefID.clear(); mScale = 1; mOwner.clear(); diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index 9c57061b0..f3986ccf3 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -13,8 +13,12 @@ namespace ESM struct RefNum { - int mIndex; - int mContentFile; // -1 no content file + unsigned int mIndex; + int mContentFile; + + enum { RefNum_NoContentFile = -1 }; + inline bool hasContentFile() const { return mContentFile != RefNum_NoContentFile; } + inline void unset() { mIndex = 0; mContentFile = RefNum_NoContentFile; } }; /* Cell reference. This represents ONE object (of many) inside the From 458b82c308ec62156e0c250f75dce75f3760901a Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 11 Jan 2015 14:25:46 +1300 Subject: [PATCH 178/740] Centralized "fish can't attack non-swimmer" logic. --- apps/openmw/mwmechanics/actors.cpp | 7 ++++--- apps/openmw/mwmechanics/aicombat.cpp | 9 +++------ apps/openmw/mwmechanics/combat.cpp | 20 ++++++++++++++++++++ apps/openmw/mwmechanics/combat.hpp | 4 ++++ 4 files changed, 31 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 0a25ddd42..a90277160 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -37,6 +37,7 @@ #include "actor.hpp" #include "summoning.hpp" +#include "combat.hpp" namespace { @@ -309,10 +310,10 @@ namespace MWMechanics // pure water creatures won't try to fight with the target on the ground // except that creature is already hostile if ((againstPlayer || !creatureStats.getAiSequence().isInCombat()) - && ((actor1.getClass().isPureWaterCreature(actor1) - && !MWBase::Environment::get().getWorld()->isWading(actor2)) - || (!actor1.getClass().canSwim(actor1) && MWBase::Environment::get().getWorld()->isSwimming(actor2)))) // creature can't swim to target + && !MWMechanics::isEnvironmentCompatible(actor1, actor2)) // creature can't swim to target + { return; + } bool aggressive; diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index ce5963a91..f7e285ff5 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -23,6 +23,7 @@ #include "character.hpp" // fixme: for getActiveWeapon #include "aicombataction.hpp" +#include "combat.hpp" namespace { @@ -206,12 +207,8 @@ namespace MWMechanics const MWWorld::Class& actorClass = actor.getClass(); MWBase::World* world = MWBase::Environment::get().getWorld(); - if (!actorClass.isNpc() && - // 1. pure water creature and Player moved out of water - ((target == world->getPlayerPtr() && - actorClass.isPureWaterCreature(actor) && !world->isWading(target)) - // 2. creature can't swim to target - || (!actorClass.canSwim(actor) && world->isSwimming(target)))) + // can't fight if attacker can't go where target is. E.g. A fish can't attack person on land. + if (!actorClass.isNpc() && !MWMechanics::isEnvironmentCompatible(actor, target)) { actorClass.getCreatureStats(actor).setAttackingOrSpell(false); return true; diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 459ff8aef..ad4d3aabf 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -367,4 +367,24 @@ namespace MWMechanics else sndMgr->playSound3D(victim, "Hand To Hand Hit", 1.0f, 1.0f); } + + 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; + } } diff --git a/apps/openmw/mwmechanics/combat.hpp b/apps/openmw/mwmechanics/combat.hpp index c6fc9ff92..41dd2d1a4 100644 --- a/apps/openmw/mwmechanics/combat.hpp +++ b/apps/openmw/mwmechanics/combat.hpp @@ -34,6 +34,10 @@ void adjustWeaponDamage (float& damage, const MWWorld::Ptr& weapon); void getHandToHandDamage (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, float& damage, bool& healthdmg); +/// 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); + } #endif From 1795fdaf034928b9e995eb64b98c6e0be8be3dd8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 11 Jan 2015 13:50:50 +0100 Subject: [PATCH 179/740] Command line options readme fix --- README.md | 104 ++++++++++++++++++++++++++---------------------------- 1 file changed, 51 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index 168684e8d..bb59b7e02 100644 --- a/README.md +++ b/README.md @@ -35,59 +35,57 @@ The data path tells OpenMW where to find your Morrowind files. If you run the la Command line options -------------------- -
-Syntax: openmw 
-Allowed options:
-  --help                                print help message
-  --version                             print version information and quit
-  --data arg (=data)                    set data directories (later directories
-                                        have higher priority)
-  --data-local arg                      set local data directory (highest
-                                        priority)
-  --fallback-archive arg (=fallback-archive)
-                                        set fallback BSA archives (later
-                                        archives have higher priority)
-  --resources arg (=resources)          set resources directory
-  --start arg (=Beshara)                set initial cell
-  --content arg                         content file(s): esm/esp, or
-                                        omwgame/omwaddon
-  --anim-verbose [=arg(=1)] (=0)        output animation indices files
-  --no-sound [=arg(=1)] (=0)            disable all sounds
-  --script-verbose [=arg(=1)] (=0)      verbose script output
-  --script-all [=arg(=1)] (=0)          compile all scripts (excluding dialogue
-                                        scripts) at startup
-  --script-console [=arg(=1)] (=0)      enable console-only script
-                                        functionality
-  --script-run arg                      select a file containing a list of
-                                        console commands that is executed on
-                                        startup
-   --script-warn [=arg(=1)] (=1)        handling of warnings when compiling
-                                        scripts
-                                        0 - ignore warning
-                                        1 - show warning but consider script as
-                                        correctly compiled anyway
-                                        2 - treat warnings as errors
-  --skip-menu [=arg(=1)] (=0)           skip main menu on game startup
-  --new-game [=arg(=1)] (=0)            run new game sequence (ignored if
-                                        skip-menu=0)
-  --fs-strict [=arg(=1)] (=0)           strict file system handling (no case
-                                        folding)
-  --encoding arg (=win1252)             Character encoding used in OpenMW game
-                                        messages:
+    Syntax: openmw 
+    Allowed options:
+      --help                                print help message
+      --version                             print version information and quit
+      --data arg (=data)                    set data directories (later directories
+                                            have higher priority)
+      --data-local arg                      set local data directory (highest
+                                            priority)
+      --fallback-archive arg (=fallback-archive)
+                                            set fallback BSA archives (later
+                                            archives have higher priority)
+      --resources arg (=resources)          set resources directory
+      --start arg (=Beshara)                set initial cell
+      --content arg                         content file(s): esm/esp, or
+                                            omwgame/omwaddon
+      --anim-verbose [=arg(=1)] (=0)        output animation indices files
+      --no-sound [=arg(=1)] (=0)            disable all sounds
+      --script-verbose [=arg(=1)] (=0)      verbose script output
+      --script-all [=arg(=1)] (=0)          compile all scripts (excluding dialogue
+                                            scripts) at startup
+      --script-console [=arg(=1)] (=0)      enable console-only script
+                                            functionality
+      --script-run arg                      select a file containing a list of
+                                            console commands that is executed on
+                                            startup
+       --script-warn [=arg(=1)] (=1)        handling of warnings when compiling
+                                            scripts
+                                            0 - ignore warning
+                                            1 - show warning but consider script as
+                                            correctly compiled anyway
+                                            2 - treat warnings as errors
+      --skip-menu [=arg(=1)] (=0)           skip main menu on game startup
+      --new-game [=arg(=1)] (=0)            run new game sequence (ignored if
+                                            skip-menu=0)
+      --fs-strict [=arg(=1)] (=0)           strict file system handling (no case
+                                            folding)
+      --encoding arg (=win1252)             Character encoding used in OpenMW game
+                                            messages:
 
-                                        win1250 - Central and Eastern European
-                                        such as Polish, Czech, Slovak,
-                                        Hungarian, Slovene, Bosnian, Croatian,
-                                        Serbian (Latin script), Romanian and
-                                        Albanian languages
+                                            win1250 - Central and Eastern European
+                                            such as Polish, Czech, Slovak,
+                                            Hungarian, Slovene, Bosnian, Croatian,
+                                            Serbian (Latin script), Romanian and
+                                            Albanian languages
 
-                                        win1251 - Cyrillic alphabet such as
-                                        Russian, Bulgarian, Serbian Cyrillic
-                                        and other languages
+                                            win1251 - Cyrillic alphabet such as
+                                            Russian, Bulgarian, Serbian Cyrillic
+                                            and other languages
 
-                                        win1252 - Western European (Latin)
-                                        alphabet, used by default
-  --fallback arg                        fallback values
-  --no-grab                             Don't grab mouse cursor
-  --activate-dist arg (=-1)             activation distance override
-
+ win1252 - Western European (Latin) + alphabet, used by default + --fallback arg fallback values + --no-grab Don't grab mouse cursor + --activate-dist arg (=-1) activation distance override From e2fe9693f3a9be047eb785fae49aa4e5c06ece93 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 11 Jan 2015 00:17:55 +0100 Subject: [PATCH 180/740] Add missing tooltips in edit effect dialog --- files/mygui/openmw_edit_effect.layout | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/files/mygui/openmw_edit_effect.layout b/files/mygui/openmw_edit_effect.layout index 5dc53e505..6123f90a7 100644 --- a/files/mygui/openmw_edit_effect.layout +++ b/files/mygui/openmw_edit_effect.layout @@ -12,9 +12,12 @@ - + + + + @@ -22,9 +25,12 @@ - + + + + @@ -49,9 +55,12 @@ - + + + + @@ -66,9 +75,12 @@ - + + + + From 716e14a37a8cd86d8711bd2ba5e1ac8e597d0d66 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 11 Jan 2015 15:12:47 +0100 Subject: [PATCH 181/740] Print missing savegame dependencies on the console --- apps/openmw/mwstate/statemanagerimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index f756ee42a..77e3452e3 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -534,8 +534,8 @@ bool MWState::StateManager::verifyProfile(const ESM::SavedGame& profile) const if (std::find(selectedContentFiles.begin(), selectedContentFiles.end(), *it) == selectedContentFiles.end()) { + std::cerr << "Savegame dependency " << *it << " is missing." << std::endl; notFound = true; - break; } } if (notFound) From b108fbe9866d97c853489defff91b41996cb39e0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 11 Jan 2015 15:47:56 +0100 Subject: [PATCH 182/740] Remove incorrect implementation of fGreetDistanceReset This can't be right. A reset distance of 512 is smaller than the maximum greeting distance for certain NPCs, which would then say greetings non-stop. --- apps/openmw/mwmechanics/aiwander.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 94c4542f8..30e17c7f4 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -477,10 +477,8 @@ namespace MWMechanics if (greetingState == MWMechanics::AiWander::Greet_Done) { - static float fGreetDistanceReset = MWBase::Environment::get().getWorld()->getStore() - .get().find("fGreetDistanceReset")->getFloat(); - - if (playerDistSqr >= fGreetDistanceReset*fGreetDistanceReset) + float resetDist = 2*helloDistance; + if (playerDistSqr >= resetDist*resetDist) greetingState = Greet_None; } } From 4d4f2fc475a2f42bd07bf6d235debb7a09c83375 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 11 Jan 2015 16:51:24 +0100 Subject: [PATCH 183/740] Add maximum distance for teleporting followers on using a door --- apps/openmw/mwworld/actionteleport.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/actionteleport.cpp b/apps/openmw/mwworld/actionteleport.cpp index 7fd6ba024..8bbb08008 100644 --- a/apps/openmw/mwworld/actionteleport.cpp +++ b/apps/openmw/mwworld/actionteleport.cpp @@ -37,7 +37,11 @@ namespace MWWorld getFollowers(actor, followers); for(std::set::iterator it = followers.begin();it != followers.end();++it) { - teleport(*it); + MWWorld::Ptr follower = *it; + if (Ogre::Vector3(follower.getRefData().getPosition().pos).squaredDistance( + Ogre::Vector3( actor.getRefData().getPosition().pos)) + <= 800*800) + teleport(*it); } teleport(actor); From 1780bcc238e06230815f4090cca3e96cdd88d036 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 11 Jan 2015 16:52:04 +0100 Subject: [PATCH 184/740] Print RefNum in BetaComment --- apps/openmw/mwscript/miscextensions.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index d4431016a..37bb4235e 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -1042,6 +1042,7 @@ namespace MWScript std::vector contentFiles = MWBase::Environment::get().getWorld()->getContentFiles(); msg << contentFiles.at (ptr.getCellRef().getRefNum().mContentFile) << std::endl; + msg << "RefNum: " << ptr.getCellRef().getRefNum().mIndex << std::endl; } msg << "RefID: " << ptr.getCellRef().getRefId() << std::endl; From 0ec018f7f1f77c22750bb7f6a6649808c4ec1e1a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 11 Jan 2015 17:54:15 +0100 Subject: [PATCH 185/740] More accurate savegame loading progress bar, uses position in the file (Bug #2259) --- apps/openmw/mwstate/statemanagerimp.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 77e3452e3..e9b549dc9 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -337,11 +337,13 @@ void MWState::StateManager::loadGame (const Character *character, const std::str Loading::Listener& listener = *MWBase::Environment::get().getWindowManager()->getLoadingScreen(); - listener.setProgressRange(reader.getRecordCount()); + listener.setProgressRange(100); listener.setLabel("#{sLoadingMessage14}"); Loading::ScopedLoad load(&listener); + size_t total = reader.getFileSize(); + int currentPercent = 0; while (reader.hasMoreRecs()) { ESM::NAME n = reader.getRecName(); @@ -423,7 +425,12 @@ void MWState::StateManager::loadGame (const Character *character, const std::str std::cerr << "Ignoring unknown record: " << n.name << std::endl; reader.skipRecord(); } - listener.increaseProgress(); + int progressPercent = static_cast(float(reader.getFileOffset())/total*100); + if (progressPercent > currentPercent) + { + listener.increaseProgress(progressPercent-currentPercent); + currentPercent = progressPercent; + } } mCharacterManager.setCurrentCharacter(character); @@ -446,7 +453,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::str // Use detectWorldSpaceChange=false, otherwise some of the data we just loaded would be cleared again MWBase::Environment::get().getWorld()->changeToCell (cellId, ptr.getRefData().getPosition(), false); - // Vanilla MW will restart startup scripts when a save game is loaded. This is unintuive, + // Vanilla MW will restart startup scripts when a save game is loaded. This is unintuitive, // but some mods may be using it as a reload detector. MWBase::Environment::get().getScriptManager()->getGlobalScripts().addStartup(); @@ -472,8 +479,11 @@ void MWState::StateManager::loadGame (const Character *character, const std::str void MWState::StateManager::quickLoad() { if (Character* mCurrentCharacter = getCurrentCharacter (false)) - if (const MWState::Slot* slot = &*mCurrentCharacter->begin()) //Get newest save - loadGame (mCurrentCharacter, slot->mPath.string()); + { + if (mCurrentCharacter->begin() == mCurrentCharacter->end()) + return; + loadGame (mCurrentCharacter, mCurrentCharacter->begin()->mPath.string()); //Get newest save + } } void MWState::StateManager::deleteGame(const MWState::Character *character, const MWState::Slot *slot) From c3f3f8b3d0fd4f8845c54fa0666d4b208fb33ee2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 11 Jan 2015 18:01:06 +0100 Subject: [PATCH 186/740] Use only Cell records for saving progress bar (Fixes #2259) --- apps/openmw/mwbase/world.hpp | 1 + apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 1 - apps/openmw/mwdialogue/journalimp.cpp | 4 ---- apps/openmw/mwgui/mapwindow.cpp | 1 - apps/openmw/mwgui/windowmanagerimp.cpp | 3 --- apps/openmw/mwmechanics/actors.cpp | 2 -- apps/openmw/mwrender/globalmap.cpp | 1 - apps/openmw/mwscript/globalscripts.cpp | 1 - apps/openmw/mwstate/statemanagerimp.cpp | 4 ++-- apps/openmw/mwworld/cells.cpp | 4 ++-- apps/openmw/mwworld/esmstore.cpp | 1 - apps/openmw/mwworld/globals.cpp | 1 - apps/openmw/mwworld/player.cpp | 2 -- apps/openmw/mwworld/projectilemanager.cpp | 4 ---- apps/openmw/mwworld/store.hpp | 1 - apps/openmw/mwworld/weather.cpp | 1 - apps/openmw/mwworld/worldimp.cpp | 8 +++++--- apps/openmw/mwworld/worldimp.hpp | 1 + 18 files changed, 11 insertions(+), 30 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 7432db734..db0f0a763 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -104,6 +104,7 @@ namespace MWBase virtual void clear() = 0; virtual int countSavedGameRecords() const = 0; + virtual int countSavedGameCells() const = 0; virtual void write (ESM::ESMWriter& writer, Loading::Listener& listener) const = 0; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index a42a48696..dd0fa21fa 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -645,7 +645,6 @@ namespace MWDialogue writer.startRecord (ESM::REC_DIAS); state.save (writer); writer.endRecord (ESM::REC_DIAS); - progress.increaseProgress(); } void DialogueManager::readRecord (ESM::ESMReader& reader, int32_t type) diff --git a/apps/openmw/mwdialogue/journalimp.cpp b/apps/openmw/mwdialogue/journalimp.cpp index e8d5375e1..1d17134df 100644 --- a/apps/openmw/mwdialogue/journalimp.cpp +++ b/apps/openmw/mwdialogue/journalimp.cpp @@ -187,7 +187,6 @@ namespace MWDialogue writer.startRecord (ESM::REC_QUES); state.save (writer); writer.endRecord (ESM::REC_QUES); - progress.increaseProgress(); for (Topic::TEntryIter iter (quest.begin()); iter!=quest.end(); ++iter) { @@ -198,7 +197,6 @@ namespace MWDialogue writer.startRecord (ESM::REC_JOUR); entry.save (writer); writer.endRecord (ESM::REC_JOUR); - progress.increaseProgress(); } } @@ -210,7 +208,6 @@ namespace MWDialogue writer.startRecord (ESM::REC_JOUR); entry.save (writer); writer.endRecord (ESM::REC_JOUR); - progress.increaseProgress(); } for (TTopicIter iter (mTopics.begin()); iter!=mTopics.end(); ++iter) @@ -226,7 +223,6 @@ namespace MWDialogue writer.startRecord (ESM::REC_JOUR); entry.save (writer); writer.endRecord (ESM::REC_JOUR); - progress.increaseProgress(); } } } diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 0f9fa2775..4de9af108 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -903,7 +903,6 @@ namespace MWGui writer.startRecord(ESM::REC_GMAP); map.save(writer); writer.endRecord(ESM::REC_GMAP); - progress.increaseProgress(); } void MapWindow::readRecord(ESM::ESMReader &reader, int32_t type) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 077ca4fe3..d5a71bc77 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1604,14 +1604,12 @@ namespace MWGui mMap->write(writer, progress); mQuickKeysMenu->write(writer); - progress.increaseProgress(); if (!mSelectedSpell.empty()) { writer.startRecord(ESM::REC_ASPL); writer.writeHNString("ID__", mSelectedSpell); writer.endRecord(ESM::REC_ASPL); - progress.increaseProgress(); } for (std::vector::const_iterator it = mCustomMarkers.begin(); it != mCustomMarkers.end(); ++it) @@ -1619,7 +1617,6 @@ namespace MWGui writer.startRecord(ESM::REC_MARK); (*it).save(writer); writer.endRecord(ESM::REC_MARK); - progress.increaseProgress(); } } diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index a90277160..adabff092 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1460,8 +1460,6 @@ namespace MWMechanics writer.writeHNT ("COUN", it->second); } writer.endRecord(ESM::REC_DCOU); - - listener.increaseProgress(1); } void Actors::readRecord (ESM::ESMReader& reader, int32_t type) diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 5546c401b..9816b0f41 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -157,7 +157,6 @@ namespace MWRender data[texelY * mWidth * 3 + texelX * 3+2] = b; } } - loadingListener->increaseProgress(1); } } diff --git a/apps/openmw/mwscript/globalscripts.cpp b/apps/openmw/mwscript/globalscripts.cpp index b409a304c..c7371100f 100644 --- a/apps/openmw/mwscript/globalscripts.cpp +++ b/apps/openmw/mwscript/globalscripts.cpp @@ -142,7 +142,6 @@ namespace MWScript writer.startRecord (ESM::REC_GSCR); script.save (writer); writer.endRecord (ESM::REC_GSCR); - progress.increaseProgress(); } } diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index e9b549dc9..9bd2dbd3e 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -221,7 +221,8 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot writer.save (stream); Loading::Listener& listener = *MWBase::Environment::get().getWindowManager()->getLoadingScreen(); - listener.setProgressRange(recordCount); + // Using only Cells for progress information, since they typically have the largest records by far + listener.setProgressRange(MWBase::Environment::get().getWorld()->countSavedGameCells()); listener.setLabel("#{sNotifyMessage4}"); Loading::ScopedLoad load(&listener); @@ -229,7 +230,6 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot writer.startRecord (ESM::REC_SAVE); slot->mProfile.save (writer); writer.endRecord (ESM::REC_SAVE); - listener.increaseProgress(); MWBase::Environment::get().getJournal()->write (writer, listener); MWBase::Environment::get().getDialogueManager()->write (writer, listener); diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index ef3d299a9..3a8b7d5c4 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -287,7 +287,7 @@ void MWWorld::Cells::write (ESM::ESMWriter& writer, Loading::Listener& progress) if (iter->second.hasState()) { writeCell (writer, iter->second); - progress.increaseProgress(); // Assumes that each cell writes one record + progress.increaseProgress(); } for (std::map::iterator iter (mInteriors.begin()); @@ -295,7 +295,7 @@ void MWWorld::Cells::write (ESM::ESMWriter& writer, Loading::Listener& progress) if (iter->second.hasState()) { writeCell (writer, iter->second); - progress.increaseProgress(); // Assumes that each cell writes one record + progress.increaseProgress(); } } diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 8e0f58a6b..b096f4b90 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -161,7 +161,6 @@ void ESMStore::setUp() writer.writeT(mDynamicCount); writer.endRecord("COUN"); writer.endRecord(ESM::REC_DYNA); - progress.increaseProgress(); mPotions.write (writer, progress); mArmors.write (writer, progress); diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index 15ba27498..302a05824 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -85,7 +85,6 @@ namespace MWWorld writer.writeHNString ("NAME", iter->first); iter->second.write (writer, ESM::Variant::Format_Global); writer.endRecord (ESM::REC_GLOB); - progress.increaseProgress(); } } diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index b3996f756..a57934bd3 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -225,8 +225,6 @@ namespace MWWorld writer.startRecord (ESM::REC_PLAY); player.save (writer); writer.endRecord (ESM::REC_PLAY); - - progress.increaseProgress(); } bool Player::readRecord (ESM::ESMReader& reader, int32_t type) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 100ff0ba9..e4b2d5a1e 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -318,8 +318,6 @@ namespace MWWorld state.save(writer); writer.endRecord(ESM::REC_PROJ); - - progress.increaseProgress(); } for (std::vector::const_iterator it = mMagicBolts.begin(); it != mMagicBolts.end(); ++it) @@ -342,8 +340,6 @@ namespace MWWorld state.save(writer); writer.endRecord(ESM::REC_MPRJ); - - progress.increaseProgress(); } } diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index d9e4285fe..adca81adc 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -325,7 +325,6 @@ namespace MWWorld writer.writeHNString ("NAME", iter->second.mId); iter->second.save (writer); writer.endRecord (T::sRecordId); - progress.increaseProgress(); } } diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 3f9b7d562..cd05cb798 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -760,7 +760,6 @@ void WeatherManager::write(ESM::ESMWriter& writer, Loading::Listener& progress) writer.startRecord(ESM::REC_WTHR); state.save(writer); writer.endRecord(ESM::REC_WTHR); - progress.increaseProgress(); } bool WeatherManager::readRecord(ESM::ESMReader& reader, int32_t type) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5461e8405..4c34f2a04 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -309,6 +309,11 @@ namespace MWWorld +1; // camera } + int World::countSavedGameCells() const + { + return mCells.countSavedGameRecords(); + } + void World::write (ESM::ESMWriter& writer, Loading::Listener& progress) const { // Active cells could have a dirty fog of war, sync it to the CellStore first @@ -320,7 +325,6 @@ namespace MWWorld } MWMechanics::CreatureStats::writeActorIdCounter(writer); - progress.increaseProgress(); mStore.write (writer, progress); // dynamic Store must be written (and read) before Cells, so that // references to custom made records will be recognized @@ -334,12 +338,10 @@ namespace MWWorld writer.writeHNT("TELE", mTeleportEnabled); writer.writeHNT("LEVT", mLevitationEnabled); writer.endRecord(ESM::REC_ENAB); - progress.increaseProgress(); writer.startRecord(ESM::REC_CAM_); writer.writeHNT("FIRS", isFirstPerson()); writer.endRecord(ESM::REC_CAM_); - progress.increaseProgress(); } void World::readRecord (ESM::ESMReader& reader, int32_t type, diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index dfaa9f789..f050c498d 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -166,6 +166,7 @@ namespace MWWorld virtual void clear(); virtual int countSavedGameRecords() const; + virtual int countSavedGameCells() const; virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; From e95b513cfcdbe1dedb95fffaa12a0ba736b6761f Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 11 Jan 2015 16:33:03 +1300 Subject: [PATCH 187/740] Use icon to show files with problem (Fixes #2268) Launcher now indicates files with problem using an icon. Using red text for files with load order issue removed because it doesn't work well with dark themes. --- components/contentselector/model/contentmodel.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 6c5614f13..5760a327e 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "components/esm/esmreader.hpp" @@ -177,14 +178,9 @@ QVariant ContentSelectorModel::ContentModel::data(const QModelIndex &index, int switch (role) { - case Qt::ForegroundRole: + case Qt::DecorationRole: { - if (isLoadOrderError(file)) - { - QBrush redBackground(Qt::red, Qt::SolidPattern); - return redBackground; - } - break; + return isLoadOrderError(file) ? QIcon::fromTheme("edit-delete") : QVariant(); } case Qt::EditRole: @@ -618,7 +614,7 @@ QString ContentSelectorModel::ContentModel::toolTip(const EsmFile *file) const { if (isLoadOrderError(file)) { - QString text(""); + QString text(""); int index = indexFromItem(item(file->filePath())).row(); foreach(const LoadOrderError& error, checkForLoadOrderErrors(file, index)) { @@ -626,7 +622,7 @@ QString ContentSelectorModel::ContentModel::toolTip(const EsmFile *file) const text += error.toolTip(); text += "

"; } - text += ("
"); + text += (""); text += file->toolTip(); return text; } From 82eaa9f1bc7af41be5193db065e67dbd26d4132a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 11 Jan 2015 20:07:17 +0100 Subject: [PATCH 188/740] Fix loading crash (don't apply viewmode before player is set up) (Fixes #2272) --- apps/openmw/mwstate/statemanagerimp.cpp | 11 +++++++++-- apps/openmw/mwworld/worldimp.cpp | 6 ------ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 9bd2dbd3e..54c3726bd 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -342,6 +342,8 @@ void MWState::StateManager::loadGame (const Character *character, const std::str Loading::ScopedLoad load(&listener); + bool firstPersonCam = false; + size_t total = reader.getFileSize(); int currentPercent = 0; while (reader.hasMoreRecs()) @@ -396,9 +398,11 @@ void MWState::StateManager::loadGame (const Character *character, const std::str case ESM::REC_ENAB: case ESM::REC_LEVC: case ESM::REC_LEVI: - case ESM::REC_CAM_: + MWBase::Environment::get().getWorld()->readRecord(reader, n.val, contentFileMap); + break; - MWBase::Environment::get().getWorld()->readRecord (reader, n.val, contentFileMap); + case ESM::REC_CAM_: + reader.getHNT(firstPersonCam, "FIRS"); break; case ESM::REC_GSCR: @@ -446,6 +450,9 @@ void MWState::StateManager::loadGame (const Character *character, const std::str MWBase::Environment::get().getWindowManager()->updatePlayer(); MWBase::Environment::get().getMechanicsManager()->playerLoaded(); + if (firstPersonCam != MWBase::Environment::get().getWorld()->isFirstPerson()) + MWBase::Environment::get().getWorld()->togglePOV(); + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); ESM::CellId cellId = ptr.getCell()->getCell()->getCellId(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 4c34f2a04..5e773f5d3 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -356,12 +356,6 @@ namespace MWWorld reader.getHNT(mTeleportEnabled, "TELE"); reader.getHNT(mLevitationEnabled, "LEVT"); return; - case ESM::REC_CAM_: - bool firstperson; - reader.getHNT(firstperson, "FIRS"); - if (firstperson != isFirstPerson()) - togglePOV(); - break; default: if (!mStore.readRecord (reader, type) && !mGlobalVariables.readRecord (reader, type) && From 04d6cead3b3738fbf4aeebb355a71592797f043d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 11 Jan 2015 20:34:26 +0100 Subject: [PATCH 189/740] Autogenerated collision should only be disabled if RootCollisionNode is a child of the root node (Fixes #2133) --- components/nifbullet/bulletnifloader.cpp | 20 ++++++++------------ components/nifbullet/bulletnifloader.hpp | 2 +- libs/openengine/bullet/BulletShapeLoader.cpp | 2 +- libs/openengine/bullet/BulletShapeLoader.h | 5 ++--- libs/openengine/bullet/physic.cpp | 2 +- 5 files changed, 13 insertions(+), 18 deletions(-) diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 3abe0c171..6c56fbba8 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -95,7 +95,7 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) return; } - mShape->mHasCollisionNode = hasRootCollisionNode(node); + mShape->mAutogenerated = hasAutoGeneratedCollision(node); //do a first pass handleNode(node,0,false,false,false); @@ -152,12 +152,9 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) mShape->mRaycastingShape = new TriangleMeshShape(mStaticMesh,true); } -bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node const * node) +bool ManualBulletShapeLoader::hasAutoGeneratedCollision(Nif::Node const * rootNode) { - if(node->recType == Nif::RC_RootCollisionNode) - return true; - - const Nif::NiNode *ninode = dynamic_cast(node); + const Nif::NiNode *ninode = dynamic_cast(rootNode); if(ninode) { const Nif::NodeList &list = ninode->children; @@ -165,13 +162,12 @@ bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node const * node) { if(!list[i].empty()) { - if(hasRootCollisionNode(list[i].getPtr())) - return true; + if(list[i].getPtr()->recType == Nif::RC_RootCollisionNode) + return false; } } } - - return false; + return true; } void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, @@ -230,8 +226,8 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, } } - if ( (isCollisionNode || (!mShape->mHasCollisionNode && !raycasting)) - && (!isMarker || (mShape->mHasCollisionNode && !raycasting))) + if ( (isCollisionNode || (mShape->mAutogenerated && !raycasting)) + && (!isMarker || (!mShape->mAutogenerated && !raycasting))) { // NOTE: a trishape with hasBounds=true, but no BBoxCollision flag should NOT go through handleNiTriShape! // It must be ignored completely. diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index a9ee968b9..8a77e9e9e 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -112,7 +112,7 @@ private: /** *Helper function */ - bool hasRootCollisionNode(const Nif::Node *node); + bool hasAutoGeneratedCollision(const Nif::Node *rootNode); /** *convert a NiTriShape to a bullet trishape. diff --git a/libs/openengine/bullet/BulletShapeLoader.cpp b/libs/openengine/bullet/BulletShapeLoader.cpp index 5e3eeec96..fd9204b44 100644 --- a/libs/openengine/bullet/BulletShapeLoader.cpp +++ b/libs/openengine/bullet/BulletShapeLoader.cpp @@ -19,7 +19,7 @@ Ogre::Resource(creator, name, handle, group, isManual, loader) */ mCollisionShape = NULL; mRaycastingShape = NULL; - mHasCollisionNode = false; + mAutogenerated = true; mCollide = true; createParamDictionary("BulletShape"); } diff --git a/libs/openengine/bullet/BulletShapeLoader.h b/libs/openengine/bullet/BulletShapeLoader.h index a95640cf1..472a9861f 100644 --- a/libs/openengine/bullet/BulletShapeLoader.h +++ b/libs/openengine/bullet/BulletShapeLoader.h @@ -41,9 +41,8 @@ public: btCollisionShape* mCollisionShape; btCollisionShape* mRaycastingShape; - // Whether or not a NiRootCollisionNode was present in the .nif. If there is none, the collision behaviour - // depends on object type, so we need to expose this variable. - bool mHasCollisionNode; + // Does this .nif have an autogenerated collision mesh? + bool mAutogenerated; Ogre::Vector3 mBoxTranslation; Ogre::Quaternion mBoxRotation; diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 0b08e28d9..94bd39788 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -456,7 +456,7 @@ namespace Physic BulletShapeManager::getSingletonPtr()->load(outputstring,"General"); BulletShapePtr shape = BulletShapeManager::getSingleton().getByName(outputstring,"General"); - if (placeable && !raycasting && shape->mCollisionShape && !shape->mHasCollisionNode) + if (placeable && !raycasting && shape->mCollisionShape && shape->mAutogenerated) return NULL; if (!shape->mCollisionShape && !raycasting) From 871d59de6ce9f910c5792aacb00e0cbd546b45e5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 12 Jan 2015 12:09:26 +0100 Subject: [PATCH 190/740] Reduce Idle voice chance (Fixes #1964) --- apps/openmw/mwmechanics/aiwander.cpp | 43 ++++++++++++++++------------ 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 30e17c7f4..c3278a5ad 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -9,6 +9,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/dialoguemanager.hpp" +#include "../mwbase/soundmanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" @@ -301,28 +302,32 @@ namespace MWMechanics playIdle(actor, playedIdle); chooseAction = false; idleNow = true; - - // Play idle voiced dialogue entries randomly - int hello = cStats.getAiSetting(CreatureStats::AI_Hello).getModified(); - if (hello > 0) - { - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - - // Don't bother if the player is out of hearing range - static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore() - .get().find("fVoiceIdleOdds")->getFloat(); - - // Only say Idle voices when player is in LOS - // A bit counterintuitive, likely vanilla did this to reduce the appearance of - // voices going through walls? - if (roll < fVoiceIdleOdds && Ogre::Vector3(player.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(pos.pos)) < 1500*1500 - && MWBase::Environment::get().getWorld()->getLOS(player, actor)) - MWBase::Environment::get().getDialogueManager()->say(actor, "idle"); - } } } + // Play idle voiced dialogue entries randomly + int hello = cStats.getAiSetting(CreatureStats::AI_Hello).getModified(); + if (hello > 0 && !MWBase::Environment::get().getWorld()->isSwimming(actor) + && actor.getRefData().getPosition().pos[2] < 3000 && + MWBase::Environment::get().getSoundManager()->sayDone(actor)) + { + float roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 10000; // [0, 9999] + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + + // Don't bother if the player is out of hearing range + static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore() + .get().find("fVoiceIdleOdds")->getFloat(); + + float x = fVoiceIdleOdds * MWBase::Environment::get().getFrameDuration(); + + // Only say Idle voices when player is in LOS + // A bit counterintuitive, likely vanilla did this to reduce the appearance of + // voices going through walls? + if (roll < x && Ogre::Vector3(player.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(pos.pos)) < 1500*1500 + && MWBase::Environment::get().getWorld()->getLOS(player, actor)) + MWBase::Environment::get().getDialogueManager()->say(actor, "idle"); + } + float& lastReaction = storage.mReaction; lastReaction += duration; if(lastReaction < REACTION_INTERVAL) From cda2eea906531709599a7a0768db87bb7ee975ed Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 12 Jan 2015 19:51:05 +0100 Subject: [PATCH 191/740] Enchanting: use fEnchantmentConstantDurationMult and fEffectCostMult --- apps/openmw/mwmechanics/enchanting.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 96afe2e2a..31ad4a01a 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -176,23 +176,25 @@ namespace MWMechanics int magMax = (it->mMagnMax == 0) ? 1 : it->mMagnMax; int area = (it->mArea == 0) ? 1 : it->mArea; - float magnitudeCost = 0; + float magnitudeCost = (magMin + magMax) * baseCost * 0.05; if (mCastStyle == ESM::Enchantment::ConstantEffect) { - magnitudeCost = (magMin + magMax) * baseCost * 2.5; + magnitudeCost *= store.get().find("fEnchantmentConstantDurationMult")->getFloat(); } else { - magnitudeCost = (magMin + magMax) * it->mDuration * baseCost * 0.025; + magnitudeCost *= it->mDuration; if(it->mRange == ESM::RT_Target) magnitudeCost *= 1.5; } - float areaCost = area * 0.025 * baseCost; + float areaCost = area * 0.05 * baseCost; if (it->mRange == ESM::RT_Target) areaCost *= 1.5; - enchantmentCost += (magnitudeCost + areaCost) * effectsLeftCnt; + const float fEffectCostMult = store.get().find("fEffectCostMult")->getFloat(); + + enchantmentCost += (magnitudeCost + areaCost) * fEffectCostMult * effectsLeftCnt; --effectsLeftCnt; } From de23ad5c8d6ef3440ef9a7b4fe3a86dacf4e0b34 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 12 Jan 2015 19:57:54 +0100 Subject: [PATCH 192/740] Change dynamic_cast to static_cast to make coverity happy --- apps/openmw/mwgui/bookpage.cpp | 6 +++--- apps/openmw/mwmechanics/actors.cpp | 10 +++++----- apps/openmw/mwmechanics/aisequence.cpp | 14 +++++++------- apps/openmw/mwrender/globalmap.cpp | 2 +- apps/openmw/mwrender/localmap.cpp | 2 +- components/nifogre/mesh.cpp | 4 ++-- components/nifogre/ogrenifloader.cpp | 6 +++--- libs/openengine/bullet/physic.cpp | 2 +- 8 files changed, 23 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index 0f2df494a..3b1d40fc3 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -246,7 +246,7 @@ struct TypesetBookImpl::Typesetter : BookTypesetter Style* createHotStyle (Style* baseStyle, Colour normalColour, Colour hoverColour, Colour activeColour, InteractiveId id, bool unique) { - StyleImpl* BaseStyle = dynamic_cast (baseStyle); + StyleImpl* BaseStyle = static_cast (baseStyle); if (!unique) for (Styles::iterator i = mBook->mStyles.begin (); i != mBook->mStyles.end (); ++i) @@ -268,7 +268,7 @@ struct TypesetBookImpl::Typesetter : BookTypesetter { Range range = mBook->addContent (text); - writeImpl (dynamic_cast (style), range.first, range.second); + writeImpl (static_cast (style), range.first, range.second); } intptr_t addContent (Utf8Span text, bool select) @@ -295,7 +295,7 @@ struct TypesetBookImpl::Typesetter : BookTypesetter Utf8Point begin_ = &mCurrentContent->front () + begin; Utf8Point end_ = &mCurrentContent->front () + end ; - writeImpl (dynamic_cast (style), begin_, end_); + writeImpl (static_cast (style), begin_, end_); } void lineBreak (float margin) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index adabff092..a454d816a 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -131,7 +131,7 @@ void adjustCommandedActor (const MWWorld::Ptr& actor) for (it = stats.getAiSequence().begin(); it != stats.getAiSequence().end(); ++it) { if ((*it)->getTypeId() == MWMechanics::AiPackage::TypeIdFollow && - dynamic_cast(*it)->isCommanded()) + static_cast(*it)->isCommanded()) { hasCommandPackage = true; break; @@ -355,7 +355,7 @@ namespace MWMechanics { if ((*it)->getTypeId() == MWMechanics::AiPackage::TypeIdFollow) { - MWWorld::Ptr followTarget = dynamic_cast(*it)->getTarget(); + MWWorld::Ptr followTarget = static_cast(*it)->getTarget(); if (followTarget.isEmpty()) continue; @@ -1389,7 +1389,7 @@ namespace MWMechanics { if ((*it)->getTypeId() == MWMechanics::AiPackage::TypeIdFollow) { - MWWorld::Ptr followTarget = dynamic_cast(*it)->getTarget(); + MWWorld::Ptr followTarget = static_cast(*it)->getTarget(); if (followTarget.isEmpty()) continue; if (followTarget == actor) @@ -1419,11 +1419,11 @@ namespace MWMechanics { if ((*it)->getTypeId() == MWMechanics::AiPackage::TypeIdFollow) { - MWWorld::Ptr followTarget = dynamic_cast(*it)->getTarget(); + MWWorld::Ptr followTarget = static_cast(*it)->getTarget(); if (followTarget.isEmpty()) continue; if (followTarget == actor) - list.push_back(dynamic_cast(*it)->getFollowIndex()); + list.push_back(static_cast(*it)->getFollowIndex()); else break; } diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 13d09af7e..364e6effe 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -342,49 +342,49 @@ void AiSequence::readState(const ESM::AiSequence::AiSequence &sequence) case ESM::AiSequence::Ai_Wander: { MWMechanics::AiWander* wander = new AiWander( - dynamic_cast(it->mPackage)); + static_cast(it->mPackage)); mPackages.push_back(wander); break; } case ESM::AiSequence::Ai_Travel: { MWMechanics::AiTravel* travel = new AiTravel( - dynamic_cast(it->mPackage)); + static_cast(it->mPackage)); mPackages.push_back(travel); break; } case ESM::AiSequence::Ai_Escort: { MWMechanics::AiEscort* escort = new AiEscort( - dynamic_cast(it->mPackage)); + static_cast(it->mPackage)); mPackages.push_back(escort); break; } case ESM::AiSequence::Ai_Follow: { MWMechanics::AiFollow* follow = new AiFollow( - dynamic_cast(it->mPackage)); + static_cast(it->mPackage)); mPackages.push_back(follow); break; } case ESM::AiSequence::Ai_Activate: { MWMechanics::AiActivate* activate = new AiActivate( - dynamic_cast(it->mPackage)); + static_cast(it->mPackage)); mPackages.push_back(activate); break; } case ESM::AiSequence::Ai_Combat: { MWMechanics::AiCombat* combat = new AiCombat( - dynamic_cast(it->mPackage)); + static_cast(it->mPackage)); mPackages.push_back(combat); break; } case ESM::AiSequence::Ai_Pursue: { MWMechanics::AiPursue* pursue = new AiPursue( - dynamic_cast(it->mPackage)); + static_cast(it->mPackage)); mPackages.push_back(pursue); break; } diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 9816b0f41..a4460c59d 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -245,7 +245,7 @@ namespace MWRender void GlobalMap::loadResource(Ogre::Resource *resource) { - Ogre::Texture* tex = dynamic_cast(resource); + Ogre::Texture* tex = static_cast(resource); Ogre::ConstImagePtrList list; list.push_back(&mOverlayImage); tex->_loadImages(list); diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 059d83e79..c152d1513 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -494,7 +494,7 @@ void LocalMap::loadResource(Ogre::Resource* resource) std::vector& buffer = mBuffers[resourceName]; - Ogre::Texture* tex = dynamic_cast(resource); + Ogre::Texture* tex = static_cast(resource); tex->createInternalResources(); memcpy(tex->getBuffer()->lock(HardwareBuffer::HBL_DISCARD), &buffer[0], sFogOfWarResolution*sFogOfWarResolution*4); tex->getBuffer()->unlock(); diff --git a/components/nifogre/mesh.cpp b/components/nifogre/mesh.cpp index 4932dd009..85c3a7b65 100644 --- a/components/nifogre/mesh.cpp +++ b/components/nifogre/mesh.cpp @@ -382,7 +382,7 @@ NIFMeshLoader::NIFMeshLoader(const std::string &name, const std::string &group, void NIFMeshLoader::loadResource(Ogre::Resource *resource) { - Ogre::Mesh *mesh = dynamic_cast(resource); + Ogre::Mesh *mesh = static_cast(resource); OgreAssert(mesh, "Attempting to load a mesh into a non-mesh resource!"); Nif::NIFFilePtr nif = Nif::Cache::getInstance().load(mName); @@ -395,7 +395,7 @@ void NIFMeshLoader::loadResource(Ogre::Resource *resource) } const Nif::Record *record = nif->getRecord(mShapeIndex); - createSubMesh(mesh, dynamic_cast(record)); + createSubMesh(mesh, static_cast(record)); } diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 9c5f4a016..7ec2c2c24 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -799,7 +799,7 @@ class NIFObjectLoader { if (ctrls->recType == Nif::RC_NiAlphaController) { - const Nif::NiAlphaController *alphaCtrl = dynamic_cast(ctrls.getPtr()); + const Nif::NiAlphaController *alphaCtrl = static_cast(ctrls.getPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW AlphaController::Value(movable, alphaCtrl->data.getPtr(), &scene->mMaterialControllerMgr)); AlphaController::Function* function = OGRE_NEW AlphaController::Function(alphaCtrl, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); @@ -808,7 +808,7 @@ class NIFObjectLoader } else if (ctrls->recType == Nif::RC_NiMaterialColorController) { - const Nif::NiMaterialColorController *matCtrl = dynamic_cast(ctrls.getPtr()); + const Nif::NiMaterialColorController *matCtrl = static_cast(ctrls.getPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW MaterialColorController::Value(movable, matCtrl->data.getPtr(), &scene->mMaterialControllerMgr)); MaterialColorController::Function* function = OGRE_NEW MaterialColorController::Function(matCtrl, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); @@ -826,7 +826,7 @@ class NIFObjectLoader { if (ctrls->recType == Nif::RC_NiFlipController) { - const Nif::NiFlipController *flipCtrl = dynamic_cast(ctrls.getPtr()); + const Nif::NiFlipController *flipCtrl = static_cast(ctrls.getPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW FlipController::Value( diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 94bd39788..ed6d74b9b 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -35,7 +35,7 @@ btCollisionShape *duplicateCollisionShape(btCollisionShape *shape) if(btBvhTriangleMeshShape *trishape = dynamic_cast(shape)) { - btTriangleMesh* oldMesh = dynamic_cast(trishape->getMeshInterface()); + btTriangleMesh* oldMesh = static_cast(trishape->getMeshInterface()); btTriangleMesh* newMesh = new btTriangleMesh(*oldMesh); NifBullet::TriangleMeshShape *newShape = new NifBullet::TriangleMeshShape(newMesh, true); From 08d8dd287cb59b4759764b34c06dbba672015dc0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 12 Jan 2015 20:25:06 +0100 Subject: [PATCH 193/740] I think this was committed by accident --- apps/openmw/mwrender/localmap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index c152d1513..638a08623 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -200,7 +200,7 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, // Get the cell's NorthMarker rotation. This is used to rotate the entire map. const Vector2& north = MWBase::Environment::get().getWorld()->getNorthVector(cell); - Radian angle = Ogre::Math::ATan2 (north.x, north.y) + Ogre::Degree(2); + Radian angle = Ogre::Math::ATan2 (north.x, north.y); mAngle = angle.valueRadians(); // Rotate the cell and merge the rotated corners to the bounding box From bb718f216db6216ed886172bd23bf7a0b6d5ef4b Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 12 Jan 2015 20:25:25 +0100 Subject: [PATCH 194/740] Initialize ENAMstruct in SpellCreationDialog (Coverity) --- apps/openmw/mwgui/spellcreationdialog.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index a00afdab8..f4c9d021a 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -36,6 +36,18 @@ namespace return gmst.find(ESM::MagicEffect::effectIdToString (id1))->getString() < gmst.find(ESM::MagicEffect::effectIdToString (id2))->getString(); } + + void init(ESM::ENAMstruct& effect) + { + effect.mArea = 0; + effect.mDuration = 0; + effect.mEffectID = -1; + effect.mMagnMax = 0; + effect.mMagnMin = 0; + effect.mRange = 0; + effect.mSkill = -1; + effect.mAttribute = -1; + } } namespace MWGui @@ -47,6 +59,9 @@ namespace MWGui , mMagicEffect(NULL) , mConstantEffect(false) { + init(mEffect); + init(mOldEffect); + getWidget(mCancelButton, "CancelButton"); getWidget(mOkButton, "OkButton"); getWidget(mDeleteButton, "DeleteButton"); From 4ed3e7bbb7714d93771689114d6867494385b30a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 12 Jan 2015 23:28:52 +0100 Subject: [PATCH 195/740] Enchanting code cleanup --- apps/openmw/mwmechanics/enchanting.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 31ad4a01a..002831acc 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -171,7 +171,6 @@ namespace MWMechanics for (std::vector::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it) { float baseCost = (store.get().find(it->mEffectID))->mData.mBaseCost; - // To reflect vanilla behavior int magMin = (it->mMagnMin == 0) ? 1 : it->mMagnMin; int magMax = (it->mMagnMax == 0) ? 1 : it->mMagnMax; int area = (it->mArea == 0) ? 1 : it->mArea; @@ -184,17 +183,18 @@ namespace MWMechanics else { magnitudeCost *= it->mDuration; - if(it->mRange == ESM::RT_Target) - magnitudeCost *= 1.5; } float areaCost = area * 0.05 * baseCost; - if (it->mRange == ESM::RT_Target) - areaCost *= 1.5; const float fEffectCostMult = store.get().find("fEffectCostMult")->getFloat(); - enchantmentCost += (magnitudeCost + areaCost) * fEffectCostMult * effectsLeftCnt; + float cost = (magnitudeCost + areaCost) * fEffectCostMult; + if (it->mRange == ESM::RT_Target) + cost *= 1.5; + + enchantmentCost += cost * effectsLeftCnt; + enchantmentCost = std::max(1.f, enchantmentCost); --effectsLeftCnt; } From 41b3a9dba9206d24778140d668c7a4290273a4a7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 12 Jan 2015 11:29:56 +0100 Subject: [PATCH 196/740] Rewrite animated collision shape support (Fixes #2123) --- apps/openmw/mwclass/activator.cpp | 10 ++- apps/openmw/mwclass/activator.hpp | 4 +- apps/openmw/mwclass/apparatus.cpp | 8 +-- apps/openmw/mwclass/apparatus.hpp | 4 +- apps/openmw/mwclass/armor.cpp | 8 +-- apps/openmw/mwclass/armor.hpp | 4 +- apps/openmw/mwclass/book.cpp | 8 +-- apps/openmw/mwclass/book.hpp | 4 +- apps/openmw/mwclass/clothing.cpp | 8 +-- apps/openmw/mwclass/clothing.hpp | 4 +- apps/openmw/mwclass/container.cpp | 10 ++- apps/openmw/mwclass/container.hpp | 4 +- apps/openmw/mwclass/creature.cpp | 9 ++- apps/openmw/mwclass/creature.hpp | 4 +- apps/openmw/mwclass/door.cpp | 10 ++- apps/openmw/mwclass/door.hpp | 4 +- apps/openmw/mwclass/ingredient.cpp | 8 +-- apps/openmw/mwclass/ingredient.hpp | 4 +- apps/openmw/mwclass/light.cpp | 10 ++- apps/openmw/mwclass/light.hpp | 4 +- apps/openmw/mwclass/lockpick.cpp | 8 +-- apps/openmw/mwclass/lockpick.hpp | 4 +- apps/openmw/mwclass/misc.cpp | 8 +-- apps/openmw/mwclass/misc.hpp | 4 +- apps/openmw/mwclass/npc.cpp | 6 +- apps/openmw/mwclass/npc.hpp | 4 +- apps/openmw/mwclass/potion.cpp | 8 +-- apps/openmw/mwclass/potion.hpp | 4 +- apps/openmw/mwclass/probe.cpp | 8 +-- apps/openmw/mwclass/probe.hpp | 4 +- apps/openmw/mwclass/repair.cpp | 8 +-- apps/openmw/mwclass/repair.hpp | 4 +- apps/openmw/mwclass/static.cpp | 8 +-- apps/openmw/mwclass/static.hpp | 4 +- apps/openmw/mwclass/weapon.cpp | 8 +-- apps/openmw/mwclass/weapon.hpp | 4 +- apps/openmw/mwrender/activatoranimation.cpp | 8 +-- apps/openmw/mwrender/activatoranimation.hpp | 2 +- apps/openmw/mwrender/actors.cpp | 10 +-- apps/openmw/mwrender/actors.hpp | 4 +- apps/openmw/mwrender/animation.cpp | 46 ++++++------- apps/openmw/mwrender/animation.hpp | 4 ++ apps/openmw/mwrender/creatureanimation.cpp | 10 ++- apps/openmw/mwrender/creatureanimation.hpp | 4 +- apps/openmw/mwrender/npcanimation.cpp | 15 +++-- apps/openmw/mwrender/renderingmanager.cpp | 4 +- apps/openmw/mwrender/renderingmanager.hpp | 2 +- apps/openmw/mwworld/class.cpp | 4 +- apps/openmw/mwworld/class.hpp | 4 +- apps/openmw/mwworld/physicssystem.cpp | 33 ++++----- apps/openmw/mwworld/physicssystem.hpp | 4 +- apps/openmw/mwworld/scene.cpp | 14 ++-- apps/openmw/mwworld/worldimp.cpp | 5 +- components/misc/resourcehelpers.cpp | 17 +++++ components/misc/resourcehelpers.hpp | 2 + components/nifbullet/bulletnifloader.cpp | 75 +++++++++++++++++++-- components/nifbullet/bulletnifloader.hpp | 2 + libs/openengine/bullet/BulletShapeLoader.h | 6 +- libs/openengine/bullet/physic.cpp | 13 ++-- libs/openengine/bullet/physic.hpp | 4 +- 60 files changed, 286 insertions(+), 229 deletions(-) diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 46b23e942..457b0cec1 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -31,20 +31,18 @@ namespace MWClass return ptr.get()->mBase->mId; } - void Activator::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Activator::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - const std::string model = getModel(ptr); if (!model.empty()) { MWRender::Actors& actors = renderingInterface.getActors(); - actors.insertActivator(ptr); + actors.insertActivator(ptr, model); } } - void Activator::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Activator::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { - const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr); + physics.addObject(ptr, model); MWBase::Environment::get().getMechanicsManager()->add(ptr); } diff --git a/apps/openmw/mwclass/activator.hpp b/apps/openmw/mwclass/activator.hpp index 3e4bc3de4..e79318a55 100644 --- a/apps/openmw/mwclass/activator.hpp +++ b/apps/openmw/mwclass/activator.hpp @@ -16,10 +16,10 @@ namespace MWClass /// Return ID of \a ptr virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index c466cbc33..316ba3ab6 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -26,19 +26,17 @@ namespace MWClass return ptr.get()->mBase->mId; } - void Apparatus::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Apparatus::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - const std::string model = getModel(ptr); if (!model.empty()) { renderingInterface.getObjects().insertModel(ptr, model); } } - void Apparatus::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Apparatus::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { - const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr,true); + physics.addObject(ptr, model, true); } std::string Apparatus::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index 5cdda8f26..2ab0a47e3 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -18,10 +18,10 @@ namespace MWClass virtual float getWeight (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 2fa6602c4..64043157d 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -31,19 +31,17 @@ namespace MWClass return ptr.get()->mBase->mId; } - void Armor::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Armor::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - const std::string model = getModel(ptr); if (!model.empty()) { renderingInterface.getObjects().insertModel(ptr, model); } } - void Armor::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Armor::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { - const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr,true); + physics.addObject(ptr, model, true); } std::string Armor::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 8b7804c63..8c8e74cf4 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -17,10 +17,10 @@ namespace MWClass virtual float getWeight (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index b99d71a06..a9c96e7c7 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -28,19 +28,17 @@ namespace MWClass return ptr.get()->mBase->mId; } - void Book::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Book::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - const std::string model = getModel(ptr); if (!model.empty()) { renderingInterface.getObjects().insertModel(ptr, model); } } - void Book::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Book::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { - const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr,true); + physics.addObject(ptr, model, true); } std::string Book::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 49d21e8bf..05ff88bb2 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -15,10 +15,10 @@ namespace MWClass /// Return ID of \a ptr virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index eb2dec0ab..0fa686dda 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -28,19 +28,17 @@ namespace MWClass return ptr.get()->mBase->mId; } - void Clothing::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Clothing::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - const std::string model = getModel(ptr); if (!model.empty()) { renderingInterface.getObjects().insertModel(ptr, model); } } - void Clothing::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Clothing::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { - const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr,true); + physics.addObject(ptr, model, true); } std::string Clothing::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 99ce61ece..570054348 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -15,10 +15,10 @@ namespace MWClass /// Return ID of \a ptr virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index b05837cb6..c6a7bbf74 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -85,20 +85,18 @@ namespace MWClass store.restock(list, ptr, ptr.getCellRef().getOwner(), ptr.getCellRef().getFaction(), ptr.getCellRef().getFactionRank()); } - void Container::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Container::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - const std::string model = getModel(ptr); if (!model.empty()) { MWRender::Actors& actors = renderingInterface.getActors(); - actors.insertActivator(ptr); + actors.insertActivator(ptr, model); } } - void Container::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Container::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { - const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr); + physics.addObject(ptr, model); MWBase::Environment::get().getMechanicsManager()->add(ptr); } diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index e926a71fe..52873374e 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -18,10 +18,10 @@ namespace MWClass /// Return ID of \a ptr virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 9eb5b1b69..a3614af96 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -160,20 +160,19 @@ namespace MWClass MWBase::Environment::get().getWorld()->adjustPosition(ptr, force); } - void Creature::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Creature::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { MWWorld::LiveCellRef *ref = ptr.get(); MWRender::Actors& actors = renderingInterface.getActors(); - actors.insertCreature(ptr, ref->mBase->mFlags & ESM::Creature::Weapon); + actors.insertCreature(ptr, model, ref->mBase->mFlags & ESM::Creature::Weapon); } - void Creature::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Creature::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { - const std::string model = getModel(ptr); if(!model.empty()) { - physics.addActor(ptr); + physics.addActor(ptr, model); if (getCreatureStats(ptr).isDead()) MWBase::Environment::get().getWorld()->enableActorCollision(ptr, false); } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 4b5886448..e11529b2e 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -44,10 +44,10 @@ namespace MWClass virtual std::string getId (const MWWorld::Ptr& ptr) const; ///< Return ID of \a ptr - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual void adjustPosition(const MWWorld::Ptr& ptr, bool force) const; ///< Adjust position to stand on ground. Must be called post model load diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index ee3993fc5..84c6c66fd 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -49,20 +49,18 @@ namespace MWClass return ptr.get()->mBase->mId; } - void Door::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Door::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - const std::string model = getModel(ptr); if (!model.empty()) { MWRender::Actors& actors = renderingInterface.getActors(); - actors.insertActivator(ptr); + actors.insertActivator(ptr, model); } } - void Door::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Door::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { - const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr); + physics.addObject(ptr, model); // Resume the door's opening/closing animation if it wasn't finished if (ptr.getRefData().getCustomData()) diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index 23e11d336..c5f258d3e 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -19,10 +19,10 @@ namespace MWClass /// Return ID of \a ptr virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 610a0b478..9f662a60e 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -32,19 +32,17 @@ namespace MWClass return ref->mBase->mId; } - void Ingredient::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Ingredient::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - const std::string model = getModel(ptr); if (!model.empty()) { renderingInterface.getObjects().insertModel(ptr, model); } } - void Ingredient::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Ingredient::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { - const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr,true); + physics.addObject(ptr, model, true); } std::string Ingredient::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index 690dd601a..a4681f462 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -15,10 +15,10 @@ namespace MWClass virtual std::string getId (const MWWorld::Ptr& ptr) const; ///< Return ID of \a ptr - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 7ad81232d..669b8187c 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -54,26 +54,24 @@ namespace MWClass return ptr.get()->mBase->mId; } - void Light::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Light::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { MWWorld::LiveCellRef *ref = ptr.get(); // Insert even if model is empty, so that the light is added MWRender::Actors& actors = renderingInterface.getActors(); - actors.insertActivator(ptr, !(ref->mBase->mData.mFlags & ESM::Light::OffDefault)); + actors.insertActivator(ptr, model, !(ref->mBase->mData.mFlags & ESM::Light::OffDefault)); } - void Light::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Light::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { MWWorld::LiveCellRef *ref = ptr.get(); assert (ref->mBase != NULL); - const std::string &model = ref->mBase->mModel; - if(!model.empty()) - physics.addObject(ptr,ref->mBase->mData.mFlags & ESM::Light::Carry); + physics.addObject(ptr, model, ref->mBase->mData.mFlags & ESM::Light::Carry); 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, diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index a3b841261..bbca30113 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -17,10 +17,10 @@ namespace MWClass /// Return ID of \a ptr virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 9df587024..e78c43eee 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -27,19 +27,17 @@ namespace MWClass return ptr.get()->mBase->mId; } - void Lockpick::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Lockpick::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - const std::string model = getModel(ptr); if (!model.empty()) { renderingInterface.getObjects().insertModel(ptr, model); } } - void Lockpick::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Lockpick::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { - const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr,true); + physics.addObject(ptr, model, true); } std::string Lockpick::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index d4bdf3fa6..293a40be1 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -15,10 +15,10 @@ namespace MWClass /// Return ID of \a ptr virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 1b4719c6e..271a7510e 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -43,19 +43,17 @@ namespace MWClass return ptr.get()->mBase->mId; } - void Miscellaneous::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Miscellaneous::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - const std::string model = getModel(ptr); if (!model.empty()) { renderingInterface.getObjects().insertModel(ptr, model); } } - void Miscellaneous::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Miscellaneous::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { - const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr,true); + physics.addObject(ptr, model, true); } std::string Miscellaneous::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index 53a8e050b..23160d41c 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -15,10 +15,10 @@ namespace MWClass /// Return ID of \a ptr virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 596b56acd..ac4182734 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -428,14 +428,14 @@ namespace MWClass MWBase::Environment::get().getWorld()->adjustPosition(ptr, force); } - void Npc::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Npc::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { renderingInterface.getActors().insertNPC(ptr); } - void Npc::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Npc::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { - physics.addActor(ptr); + physics.addActor(ptr, model); MWBase::Environment::get().getMechanicsManager()->add(ptr); if (getCreatureStats(ptr).isDead()) MWBase::Environment::get().getWorld()->enableActorCollision(ptr, false); diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 8c89686af..56931a419 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -50,10 +50,10 @@ namespace MWClass virtual std::string getId (const MWWorld::Ptr& ptr) const; ///< Return ID of \a ptr - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual void adjustPosition(const MWWorld::Ptr& ptr, bool force) const; ///< Adjust position to stand on ground. Must be called post model load diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 814d903ff..bd06f89fc 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -30,19 +30,17 @@ namespace MWClass return ptr.get()->mBase->mId; } - void Potion::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Potion::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - const std::string model = getModel(ptr); if (!model.empty()) { renderingInterface.getObjects().insertModel(ptr, model); } } - void Potion::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Potion::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { - const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr,true); + physics.addObject(ptr, model, true); } std::string Potion::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index 4c407d161..32e390115 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -15,10 +15,10 @@ namespace MWClass /// Return ID of \a ptr virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 82f487986..a11725f26 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -27,19 +27,17 @@ namespace MWClass return ptr.get()->mBase->mId; } - void Probe::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Probe::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - const std::string model = getModel(ptr); if (!model.empty()) { renderingInterface.getObjects().insertModel(ptr, model); } } - void Probe::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Probe::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { - const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr,true); + physics.addObject(ptr, model, true); } std::string Probe::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index 047cb8ed4..bb90ac153 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -15,10 +15,10 @@ namespace MWClass /// Return ID of \a ptr virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 4b18aced0..e9c4ac9b1 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -26,19 +26,17 @@ namespace MWClass return ptr.get()->mBase->mId; } - void Repair::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Repair::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - const std::string model = getModel(ptr); if (!model.empty()) { renderingInterface.getObjects().insertModel(ptr, model); } } - void Repair::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Repair::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { - const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr,true); + physics.addObject(ptr, model, true); } std::string Repair::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index f89258234..2589a4af3 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -15,10 +15,10 @@ namespace MWClass /// Return ID of \a ptr virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/static.cpp b/apps/openmw/mwclass/static.cpp index c241935ab..dbbe7e43a 100644 --- a/apps/openmw/mwclass/static.cpp +++ b/apps/openmw/mwclass/static.cpp @@ -17,22 +17,20 @@ namespace MWClass return ptr.get()->mBase->mId; } - void Static::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Static::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { MWWorld::LiveCellRef *ref = ptr.get(); - const std::string model = getModel(ptr); if (!model.empty()) { renderingInterface.getObjects().insertModel(ptr, model, !ref->mBase->mPersistent); } } - void Static::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Static::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { - const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr); + physics.addObject(ptr, model); } std::string Static::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/static.hpp b/apps/openmw/mwclass/static.hpp index 2ac2e8682..a94dff394 100644 --- a/apps/openmw/mwclass/static.hpp +++ b/apps/openmw/mwclass/static.hpp @@ -15,10 +15,10 @@ namespace MWClass /// Return ID of \a ptr virtual std::string getId (const MWWorld::Ptr& ptr) const; - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 8456c72e6..122c8eeae 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -30,19 +30,17 @@ namespace MWClass return ref->mBase->mId; } - void Weapon::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Weapon::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - const std::string model = getModel(ptr); if (!model.empty()) { renderingInterface.getObjects().insertModel(ptr, model); } } - void Weapon::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Weapon::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const { - const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr,true); + physics.addObject(ptr, model, true); } std::string Weapon::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 97ee10291..47f1c5251 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -15,10 +15,10 @@ namespace MWClass virtual std::string getId (const MWWorld::Ptr& ptr) const; ///< Return ID of \a ptr - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index 4c63e2cf2..1ef68f619 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -5,10 +5,6 @@ #include -#include "../mwbase/world.hpp" - -#include "../mwworld/class.hpp" - #include "renderconst.hpp" namespace MWRender @@ -18,11 +14,9 @@ ActivatorAnimation::~ActivatorAnimation() { } -ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) +ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr, const std::string& model) : Animation(ptr, ptr.getRefData().getBaseNode()) { - const std::string& model = mPtr.getClass().getModel(mPtr); - if(!model.empty()) { setObjectRoot(model, false); diff --git a/apps/openmw/mwrender/activatoranimation.hpp b/apps/openmw/mwrender/activatoranimation.hpp index ec0114ccd..a234defe7 100644 --- a/apps/openmw/mwrender/activatoranimation.hpp +++ b/apps/openmw/mwrender/activatoranimation.hpp @@ -13,7 +13,7 @@ namespace MWRender class ActivatorAnimation : public Animation { public: - ActivatorAnimation(const MWWorld::Ptr& ptr); + ActivatorAnimation(const MWWorld::Ptr& ptr, const std::string &model); virtual ~ActivatorAnimation(); void addLight(const ESM::Light *light); diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index db666e890..3da6c40c8 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -71,22 +71,22 @@ void Actors::insertNPC(const MWWorld::Ptr& ptr) mAllActors[ptr] = anim; mRendering->addWaterRippleEmitter (ptr); } -void Actors::insertCreature (const MWWorld::Ptr& ptr, bool weaponsShields) +void Actors::insertCreature (const MWWorld::Ptr& ptr, const std::string &model, bool weaponsShields) { insertBegin(ptr); Animation* anim = NULL; if (weaponsShields) - anim = new CreatureWeaponAnimation(ptr); + anim = new CreatureWeaponAnimation(ptr, model); else - anim = new CreatureAnimation(ptr); + anim = new CreatureAnimation(ptr, model); delete mAllActors[ptr]; mAllActors[ptr] = anim; mRendering->addWaterRippleEmitter (ptr); } -void Actors::insertActivator (const MWWorld::Ptr& ptr, bool addLight) +void Actors::insertActivator (const MWWorld::Ptr& ptr, const std::string &model, bool addLight) { insertBegin(ptr); - ActivatorAnimation* anim = new ActivatorAnimation(ptr); + ActivatorAnimation* anim = new ActivatorAnimation(ptr, model); if(ptr.getTypeName() == typeid(ESM::Light).name()) { diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index f81082e41..4f6c1bec2 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -40,8 +40,8 @@ namespace MWRender void setRootNode(Ogre::SceneNode* root); void insertNPC(const MWWorld::Ptr& ptr); - void insertCreature (const MWWorld::Ptr& ptr, bool weaponsShields); - void insertActivator (const MWWorld::Ptr& ptr, bool addLight=false); + void insertCreature (const MWWorld::Ptr& ptr, const std::string& model, bool weaponsShields); + void insertActivator (const MWWorld::Ptr& ptr, const std::string& model, bool addLight=false); bool deleteObject (const MWWorld::Ptr& ptr); ///< \return found? diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index bf161442e..117830c09 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -86,6 +86,12 @@ Animation::~Animation() mAnimSources.clear(); } +std::string Animation::getObjectRootName() const +{ + if (mSkelBase) + return mSkelBase->getMesh()->getName(); + return std::string(); +} void Animation::setObjectRoot(const std::string &model, bool baseonly) { @@ -97,22 +103,8 @@ void Animation::setObjectRoot(const std::string &model, bool baseonly) if(model.empty()) return; - std::string mdlname = Misc::StringUtils::lowerCase(model); - std::string::size_type p = mdlname.rfind('\\'); - if(p == std::string::npos) - p = mdlname.rfind('/'); - if(p != std::string::npos) - mdlname.insert(mdlname.begin()+p+1, 'x'); - else - mdlname.insert(mdlname.begin(), 'x'); - if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(mdlname)) - { - mdlname = model; - Misc::StringUtils::toLower(mdlname); - } - - mObjectRoot = (!baseonly ? NifOgre::Loader::createObjects(mInsert, mdlname) : - NifOgre::Loader::createObjectBase(mInsert, mdlname)); + mObjectRoot = (!baseonly ? NifOgre::Loader::createObjects(mInsert, model) : + NifOgre::Loader::createObjectBase(mInsert, model)); if(mObjectRoot->mSkelBase) { @@ -255,14 +247,8 @@ void Animation::addAnimSource(const std::string &model) if(!mSkelBase) return; - std::string kfname = Misc::StringUtils::lowerCase(model); - std::string::size_type p = kfname.rfind('\\'); - if(p == std::string::npos) - p = kfname.rfind('/'); - if(p != std::string::npos) - kfname.insert(kfname.begin()+p+1, 'x'); - else - kfname.insert(kfname.begin(), 'x'); + std::string kfname = model; + Misc::StringUtils::toLower(kfname); if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0) kfname.replace(kfname.size()-4, 4, ".kf"); @@ -417,7 +403,7 @@ void Animation::addExtraLight(Ogre::SceneManager *sceneMgr, NifOgre::ObjectScene } -Ogre::Node *Animation::getNode(const std::string &name) +Ogre::Node* Animation::getNode(const std::string &name) { if(mSkelBase) { @@ -428,6 +414,16 @@ Ogre::Node *Animation::getNode(const std::string &name) return NULL; } +Ogre::Node* Animation::getNode(int handle) +{ + if (mSkelBase) + { + Ogre::SkeletonInstance *skel = mSkelBase->getSkeleton(); + return skel->getBone(handle); + } + return NULL; +} + NifOgre::TextKeyMap::const_iterator Animation::findGroupStart(const NifOgre::TextKeyMap &keys, const std::string &groupname) { NifOgre::TextKeyMap::const_iterator iter(keys.begin()); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 73d10fd06..dab8cfebb 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -206,6 +206,9 @@ public: Ogre::uint8 transqueue, Ogre::Real dist=0.0f, bool enchantedGlow=false, Ogre::Vector3* glowColor=NULL); + /// Returns the name of the .nif file that makes up this animation's base skeleton. + /// If there is no skeleton, returns "". + std::string getObjectRootName() const; Animation(const MWWorld::Ptr &ptr, Ogre::SceneNode *node); virtual ~Animation(); @@ -334,6 +337,7 @@ public: Ogre::AxisAlignedBox getWorldBounds(); Ogre::Node *getNode(const std::string &name); + Ogre::Node *getNode(int handle); // Attaches the given object to a bone on this object's base skeleton. If the bone doesn't // exist, the object isn't attached and NULL is returned. The returned TagPoint is only diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index c1957d7a8..2bdf8a499 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -16,39 +16,37 @@ namespace MWRender { -CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) +CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr, const std::string& model) : Animation(ptr, ptr.getRefData().getBaseNode()) { MWWorld::LiveCellRef *ref = mPtr.get(); - std::string model = ptr.getClass().getModel(ptr); if(!model.empty()) { setObjectRoot(model, false); setRenderProperties(mObjectRoot, RV_Actors, RQG_Main, RQG_Alpha); if((ref->mBase->mFlags&ESM::Creature::Bipedal)) - addAnimSource("meshes\\base_anim.nif"); + addAnimSource("meshes\\xbase_anim.nif"); addAnimSource(model); } } -CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr) +CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const std::string& model) : Animation(ptr, ptr.getRefData().getBaseNode()) , mShowWeapons(false) , mShowCarriedLeft(false) { MWWorld::LiveCellRef *ref = mPtr.get(); - std::string model = ptr.getClass().getModel(ptr); if(!model.empty()) { setObjectRoot(model, false); setRenderProperties(mObjectRoot, RV_Actors, RQG_Main, RQG_Alpha); if((ref->mBase->mFlags&ESM::Creature::Bipedal)) - addAnimSource("meshes\\base_anim.nif"); + addAnimSource("meshes\\xbase_anim.nif"); addAnimSource(model); mPtr.getClass().getInventoryStore(mPtr).setListener(this, mPtr); diff --git a/apps/openmw/mwrender/creatureanimation.hpp b/apps/openmw/mwrender/creatureanimation.hpp index d6cd8a517..6201c7af4 100644 --- a/apps/openmw/mwrender/creatureanimation.hpp +++ b/apps/openmw/mwrender/creatureanimation.hpp @@ -15,7 +15,7 @@ namespace MWRender class CreatureAnimation : public Animation { public: - CreatureAnimation(const MWWorld::Ptr& ptr); + CreatureAnimation(const MWWorld::Ptr& ptr, const std::string &model); virtual ~CreatureAnimation() {} }; @@ -25,7 +25,7 @@ namespace MWRender class CreatureWeaponAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener { public: - CreatureWeaponAnimation(const MWWorld::Ptr& ptr); + CreatureWeaponAnimation(const MWWorld::Ptr& ptr, const std::string &model); virtual ~CreatureWeaponAnimation() {} virtual void equipmentChanged() { updateParts(); } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 32c1e7e05..5e73a95f2 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -12,6 +12,8 @@ #include +#include + #include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/class.hpp" @@ -282,6 +284,7 @@ void NpcAnimation::updateNpcBase() (!isWerewolf ? !isBeast ? "meshes\\base_anim.1st.nif" : "meshes\\base_animkna.1st.nif" : "meshes\\wolf\\skin.1st.nif"); + smodel = Misc::ResourceHelpers::correctActorModelPath(smodel); setObjectRoot(smodel, true); if(mViewMode != VM_FirstPerson) @@ -290,11 +293,11 @@ void NpcAnimation::updateNpcBase() if(!isWerewolf) { if(Misc::StringUtils::lowerCase(mNpc->mRace).find("argonian") != std::string::npos) - addAnimSource("meshes\\argonian_swimkna.nif"); + addAnimSource("meshes\\xargonian_swimkna.nif"); else if(!mNpc->isMale() && !isBeast) - addAnimSource("meshes\\base_anim_female.nif"); + addAnimSource("meshes\\xbase_anim_female.nif"); if(mNpc->mModel.length() > 0) - addAnimSource("meshes\\"+mNpc->mModel); + addAnimSource("meshes\\x"+mNpc->mModel); } } else @@ -306,11 +309,11 @@ void NpcAnimation::updateNpcBase() /* A bit counter-intuitive, but unlike third-person anims, it seems * beast races get both base_anim.1st.nif and base_animkna.1st.nif. */ - addAnimSource("meshes\\base_anim.1st.nif"); + addAnimSource("meshes\\xbase_anim.1st.nif"); if(isBeast) - addAnimSource("meshes\\base_animkna.1st.nif"); + addAnimSource("meshes\\xbase_animkna.1st.nif"); if(!mNpc->isMale() && !isBeast) - addAnimSource("meshes\\base_anim_female.1st.nif"); + addAnimSource("meshes\\xbase_anim_female.1st.nif"); } } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 4a87104ad..8e8b18cd1 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -256,10 +256,10 @@ void RenderingManager::cellAdded (MWWorld::CellStore *store) mDebugging->cellAdded(store); } -void RenderingManager::addObject (const MWWorld::Ptr& ptr){ +void RenderingManager::addObject (const MWWorld::Ptr& ptr, const std::string& model){ const MWWorld::Class& class_ = ptr.getClass(); - class_.insertObjectRendering(ptr, *this); + class_.insertObjectRendering(ptr, model, *this); } void RenderingManager::removeObject (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index c3eedce7b..d4b85133d 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -111,7 +111,7 @@ public: /// Write current fog of war for this cell to the CellStore void writeFog (MWWorld::CellStore* store); - void addObject (const MWWorld::Ptr& ptr); + void addObject (const MWWorld::Ptr& ptr, const std::string& model); void removeObject (const MWWorld::Ptr& ptr); void moveObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& position); diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 939b72ddb..edb3f3788 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -38,12 +38,12 @@ namespace MWWorld throw std::runtime_error ("class does not support ID retrieval"); } - void Class::insertObjectRendering (const Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Class::insertObjectRendering (const Ptr& ptr, const std::string& mesh, MWRender::RenderingInterface& renderingInterface) const { } - void Class::insertObject(const Ptr& ptr, MWWorld::PhysicsSystem& physics) const + void Class::insertObject(const Ptr& ptr, const std::string& mesh, MWWorld::PhysicsSystem& physics) const { } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 7e605d6a2..3c44abe66 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -81,8 +81,8 @@ namespace MWWorld ///< Return ID of \a ptr or throw an exception, if class does not support ID retrieval /// (default implementation: throw an exception) - virtual void insertObjectRendering (const Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; - virtual void insertObject(const Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void insertObjectRendering (const Ptr& ptr, const std::string& mesh, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObject(const Ptr& ptr, const std::string& mesh, MWWorld::PhysicsSystem& physics) const; ///< Add reference into a cell for rendering (default implementation: don't render anything). virtual std::string getName (const Ptr& ptr) const = 0; diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 5b712648c..7375fa4f8 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -17,6 +17,8 @@ #include #include +#include +#include #include @@ -51,25 +53,22 @@ void animateCollisionShapes (std::mapgetAnimation(ptr); - if (!animation) // Shouldn't happen either, since keyframe-controlled objects are not batched in StaticGeometry - throw std::runtime_error("can't find Animation for " + ptr.getCellRef().getRefId()); + if (!animation) + continue; OEngine::Physic::AnimatedShapeInstance& instance = it->second; - std::map& shapes = instance.mAnimatedShapes; - for (std::map::iterator shapeIt = shapes.begin(); + std::map& shapes = instance.mAnimatedShapes; + for (std::map::iterator shapeIt = shapes.begin(); shapeIt != shapes.end(); ++shapeIt) { - Ogre::Node* bone; - if (shapeIt->first.empty()) - // HACK: see NifSkeletonLoader::buildBones - bone = animation->getNode(" "); - else - bone = animation->getNode(shapeIt->first); + const std::string& mesh = animation->getObjectRootName(); + int boneHandle = NifOgre::NIFSkeletonLoader::lookupOgreBoneHandle(mesh, shapeIt->first); + Ogre::Node* bone = animation->getNode(boneHandle); if (bone == NULL) - throw std::runtime_error("can't find bone"); + continue; btCompoundShape* compound = dynamic_cast(instance.mCompound); @@ -689,9 +688,8 @@ namespace MWWorld mEngine->removeHeightField(x, y); } - void PhysicsSystem::addObject (const Ptr& ptr, bool placeable) + void PhysicsSystem::addObject (const Ptr& ptr, const std::string& mesh, bool placeable) { - std::string mesh = ptr.getClass().getModel(ptr); Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); handleToMesh[node->getName()] = mesh; mEngine->createAndAdjustRigidBody( @@ -700,9 +698,8 @@ namespace MWWorld mesh, node->getName(), ptr.getCellRef().getScale(), node->getPosition(), node->getOrientation(), 0, 0, true, placeable); } - void PhysicsSystem::addActor (const Ptr& ptr) + void PhysicsSystem::addActor (const Ptr& ptr, const std::string& mesh) { - std::string mesh = ptr.getClass().getModel(ptr); Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); //TODO:optimize this. Searching the std::map isn't very efficient i think. mEngine->addCharacter(node->getName(), mesh, node->getPosition(), node->getScale().x, node->getOrientation()); @@ -773,13 +770,16 @@ namespace MWWorld const std::string &handle = node->getName(); if(handleToMesh.find(handle) != handleToMesh.end()) { + std::string model = ptr.getClass().getModel(ptr); + model = Misc::ResourceHelpers::correctActorModelPath(model); // FIXME: scaling shouldn't require model + bool placeable = false; if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle,true)) placeable = body->mPlaceable; else if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle,false)) placeable = body->mPlaceable; removeObject(handle); - addObject(ptr, placeable); + addObject(ptr, model, placeable); } if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle)) @@ -820,6 +820,7 @@ namespace MWWorld bool PhysicsSystem::getObjectAABB(const MWWorld::Ptr &ptr, Ogre::Vector3 &min, Ogre::Vector3 &max) { std::string model = ptr.getClass().getModel(ptr); + model = Misc::ResourceHelpers::correctActorModelPath(model); if (model.empty()) { return false; } diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 7dc8acaa1..c1046aacb 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -38,9 +38,9 @@ namespace MWWorld void setWaterHeight(float height); void disableWater(); - void addObject (const MWWorld::Ptr& ptr, bool placeable=false); + void addObject (const MWWorld::Ptr& ptr, const std::string& mesh, bool placeable=false); - void addActor (const MWWorld::Ptr& ptr); + void addActor (const MWWorld::Ptr& ptr, const std::string& mesh); void addHeightField (float* heights, int x, int y, float yoffset, diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index efe88c406..d7548018f 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -3,6 +3,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -79,8 +80,9 @@ namespace { try { - mRendering.addObject (ptr); - ptr.getClass().insertObject (ptr, mPhysics); + const std::string& model = Misc::ResourceHelpers::correctActorModelPath(ptr.getClass().getModel(ptr)); + mRendering.addObject(ptr, model); + ptr.getClass().insertObject (ptr, model, mPhysics); updateObjectLocalRotation(ptr, mPhysics, mRendering); if (ptr.getRefData().getBaseNode()) @@ -486,8 +488,7 @@ namespace MWWorld // Sky system MWBase::Environment::get().getWorld()->adjustSky(); - mCellChanged = true; - MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.5); + mCellChanged = true; MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.5); MWBase::Environment::get().getWindowManager()->changeCell(mCurrentCell); @@ -529,8 +530,9 @@ namespace MWWorld void Scene::addObjectToScene (const Ptr& ptr) { - mRendering.addObject(ptr); - ptr.getClass().insertObject(ptr, *mPhysics); + const std::string& model = Misc::ResourceHelpers::correctActorModelPath(ptr.getClass().getModel(ptr)); + mRendering.addObject(ptr, model); + ptr.getClass().insertObject (ptr, model, *mPhysics); MWBase::Environment::get().getWorld()->rotateObject(ptr, 0, 0, 0, true); MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale()); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5e773f5d3..011f6c330 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include @@ -2092,7 +2093,9 @@ namespace MWWorld // so we should make sure not to use a "stale" controller for that. MWBase::Environment::get().getMechanicsManager()->add(mPlayer->getPlayer()); - mPhysics->addActor(mPlayer->getPlayer()); + std::string model = getPlayerPtr().getClass().getModel(getPlayerPtr()); + model = Misc::ResourceHelpers::correctActorModelPath(model); + mPhysics->addActor(mPlayer->getPlayer(), model); } int World::canRest () diff --git a/components/misc/resourcehelpers.cpp b/components/misc/resourcehelpers.cpp index ee911c566..dc08b352a 100644 --- a/components/misc/resourcehelpers.cpp +++ b/components/misc/resourcehelpers.cpp @@ -121,3 +121,20 @@ std::string Misc::ResourceHelpers::correctBookartPath(const std::string &resPath return image; } + +std::string Misc::ResourceHelpers::correctActorModelPath(const std::string &resPath) +{ + std::string mdlname = resPath; + std::string::size_type p = mdlname.rfind('\\'); + if(p == std::string::npos) + p = mdlname.rfind('/'); + if(p != std::string::npos) + mdlname.insert(mdlname.begin()+p+1, 'x'); + else + mdlname.insert(mdlname.begin(), 'x'); + if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(mdlname)) + { + return resPath; + } + return mdlname; +} diff --git a/components/misc/resourcehelpers.hpp b/components/misc/resourcehelpers.hpp index 3cf0f4c27..2ce3dce1e 100644 --- a/components/misc/resourcehelpers.hpp +++ b/components/misc/resourcehelpers.hpp @@ -13,6 +13,8 @@ namespace Misc std::string correctIconPath(const std::string &resPath); std::string correctBookartPath(const std::string &resPath); std::string correctBookartPath(const std::string &resPath, int width, int height); + /// Uses "xfoo.nif" instead of "foo.nif" if available + std::string correctActorModelPath(const std::string &resPath); } } diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 6c56fbba8..130787797 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -48,6 +48,57 @@ http://www.gnu.org/licenses/ . typedef unsigned char ubyte; +// Extract a list of keyframe-controlled nodes from a .kf file +// FIXME: this is a similar copy of OgreNifLoader::loadKf +void extractControlledNodes(Nif::NIFFilePtr kfFile, std::set& controlled) +{ + if(kfFile->numRoots() < 1) + { + kfFile->warn("Found no root nodes in "+kfFile->getFilename()+"."); + return; + } + + const Nif::Record *r = kfFile->getRoot(0); + assert(r != NULL); + + if(r->recType != Nif::RC_NiSequenceStreamHelper) + { + kfFile->warn("First root was not a NiSequenceStreamHelper, but a "+ + r->recName+"."); + return; + } + const Nif::NiSequenceStreamHelper *seq = static_cast(r); + + Nif::ExtraPtr extra = seq->extra; + if(extra.empty() || extra->recType != Nif::RC_NiTextKeyExtraData) + { + kfFile->warn("First extra data was not a NiTextKeyExtraData, but a "+ + (extra.empty() ? std::string("nil") : extra->recName)+"."); + return; + } + + extra = extra->extra; + Nif::ControllerPtr ctrl = seq->controller; + for(;!extra.empty() && !ctrl.empty();(extra=extra->extra),(ctrl=ctrl->next)) + { + if(extra->recType != Nif::RC_NiStringExtraData || ctrl->recType != Nif::RC_NiKeyframeController) + { + kfFile->warn("Unexpected extra data "+extra->recName+" with controller "+ctrl->recName); + continue; + } + + if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) + continue; + + const Nif::NiStringExtraData *strdata = static_cast(extra.getPtr()); + const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); + + if(key->data.empty()) + continue; + controlled.insert(strdata->string); + } +} + namespace NifBullet { @@ -72,10 +123,6 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) mCompoundShape = NULL; mStaticMesh = NULL; - // Load the NIF. TODO: Wrap this in a try-catch block once we're out - // of the early stages of development. Right now we WANT to catch - // every error as early and intrusively as possible, as it's most - // likely a sign of incomplete code rather than faulty input. Nif::NIFFilePtr pnif (Nif::Cache::getInstance().load(mResourceName.substr(0, mResourceName.length()-7))); Nif::NIFFile & nif = *pnif.get (); if (nif.numRoots() < 1) @@ -84,6 +131,19 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) return; } + // Have to load controlled nodes from the .kf + // FIXME: the .kf has to be loaded both for rendering and physics, ideally it should be opened once and then reused + mControlledNodes.clear(); + std::string kfname = mResourceName.substr(0, mResourceName.length()-7); + Misc::StringUtils::toLower(kfname); + if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0) + kfname.replace(kfname.size()-4, 4, ".kf"); + if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(kfname)) + { + Nif::NIFFilePtr kf (Nif::Cache::getInstance().load(kfname)); + extractControlledNodes(kf, mControlledNodes); + } + Nif::Record *r = nif.getRoot(0); assert(r != NULL); @@ -182,6 +242,9 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, && (node->controller->flags & Nif::NiNode::ControllerFlag_Active)) isAnimated = true; + if (mControlledNodes.find(node->name) != mControlledNodes.end()) + isAnimated = true; + if (!raycasting) isCollisionNode = isCollisionNode || (node->recType == Nif::RC_RootCollisionNode); else @@ -318,9 +381,9 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int btTransform trans(btQuaternion(q.x, q.y, q.z, q.w), btVector3(v.x, v.y, v.z)); if (raycasting) - mShape->mAnimatedRaycastingShapes.insert(std::make_pair(shape->name, mCompoundShape->getNumChildShapes())); + mShape->mAnimatedRaycastingShapes.insert(std::make_pair(shape->recIndex, mCompoundShape->getNumChildShapes())); else - mShape->mAnimatedShapes.insert(std::make_pair(shape->name, mCompoundShape->getNumChildShapes())); + mShape->mAnimatedShapes.insert(std::make_pair(shape->recIndex, mCompoundShape->getNumChildShapes())); mCompoundShape->addChildShape(trans, childShape); } diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index 8a77e9e9e..f95bdfccf 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -128,6 +128,8 @@ private: btTriangleMesh* mStaticMesh; btBoxShape *mBoundingBox; + + std::set mControlledNodes; }; diff --git a/libs/openengine/bullet/BulletShapeLoader.h b/libs/openengine/bullet/BulletShapeLoader.h index 472a9861f..31ee3cc7d 100644 --- a/libs/openengine/bullet/BulletShapeLoader.h +++ b/libs/openengine/bullet/BulletShapeLoader.h @@ -33,10 +33,10 @@ public: // Stores animated collision shapes. If any collision nodes in the NIF are animated, then mCollisionShape // will be a btCompoundShape (which consists of one or more child shapes). // In this map, for each animated collision shape, - // we store the bone name mapped to the child index of the shape in the btCompoundShape. - std::map mAnimatedShapes; + // we store the node's record index mapped to the child index of the shape in the btCompoundShape. + std::map mAnimatedShapes; - std::map mAnimatedRaycastingShapes; + std::map mAnimatedRaycastingShapes; btCollisionShape* mCollisionShape; btCollisionShape* mRaycastingShape; diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index ed6d74b9b..a3ec25e22 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -1,16 +1,21 @@ #include "physic.hpp" + #include #include #include + +#include +#include + +#include + #include -#include "OgreRoot.h" +#include + #include "BtOgrePG.h" #include "BtOgreGP.h" #include "BtOgreExtras.h" -#include -#include - namespace { diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index fb6ae0ceb..f497150f9 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -182,8 +182,8 @@ namespace Physic { btCollisionShape* mCompound; - // Maps bone name to child index in the compound shape - std::map mAnimatedShapes; + // Maps node record index to child index in the compound shape + std::map mAnimatedShapes; }; /** From f7bac58b39125c6466cb187578291cb75cf20a52 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 13 Jan 2015 01:00:33 +0100 Subject: [PATCH 197/740] Terrain: change index buffer flags to unsigned --- components/terrain/buffercache.cpp | 2 +- components/terrain/buffercache.hpp | 2 +- components/terrain/quadtreenode.cpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/terrain/buffercache.cpp b/components/terrain/buffercache.cpp index a3e67af5b..c26e47553 100644 --- a/components/terrain/buffercache.cpp +++ b/components/terrain/buffercache.cpp @@ -39,7 +39,7 @@ namespace Terrain return buffer; } - Ogre::HardwareIndexBufferSharedPtr BufferCache::getIndexBuffer(int flags) + Ogre::HardwareIndexBufferSharedPtr BufferCache::getIndexBuffer(unsigned int flags) { unsigned int verts = mNumVerts; diff --git a/components/terrain/buffercache.hpp b/components/terrain/buffercache.hpp index f0aea9bfd..51c0a61af 100644 --- a/components/terrain/buffercache.hpp +++ b/components/terrain/buffercache.hpp @@ -17,7 +17,7 @@ namespace Terrain /// @param flags first 4*4 bits are LOD deltas on each edge, respectively (4 bits each) /// next 4 bits are LOD level of the index buffer (LOD 0 = don't omit any vertices) - Ogre::HardwareIndexBufferSharedPtr getIndexBuffer (int flags); + Ogre::HardwareIndexBufferSharedPtr getIndexBuffer (unsigned int flags); Ogre::HardwareVertexBufferSharedPtr getUVBuffer (); diff --git a/components/terrain/quadtreenode.cpp b/components/terrain/quadtreenode.cpp index 57379a334..755c45c21 100644 --- a/components/terrain/quadtreenode.cpp +++ b/components/terrain/quadtreenode.cpp @@ -415,7 +415,7 @@ void QuadTreeNode::updateIndexBuffers() // Fetch a suitable index buffer (which may be shared) size_t ourLod = getActualLodLevel(); - int flags = 0; + unsigned int flags = 0; for (int i=0; i<4; ++i) { @@ -436,7 +436,7 @@ void QuadTreeNode::updateIndexBuffers() if (lod > 0) { assert (lod - ourLod < (1 << 4)); - flags |= int(lod - ourLod) << (4*i); + flags |= static_cast(lod - ourLod) << (4*i); } } flags |= 0 /*((int)mAdditionalLod)*/ << (4*4); From 261da8dd0ac6ddb64aa4154a863c950087a1e05a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 13 Jan 2015 01:47:42 +0100 Subject: [PATCH 198/740] Terrain: use 32-bit indices if necessary --- components/terrain/buffercache.cpp | 305 +++++++++++++++-------------- 1 file changed, 161 insertions(+), 144 deletions(-) diff --git a/components/terrain/buffercache.cpp b/components/terrain/buffercache.cpp index c26e47553..3d0b35910 100644 --- a/components/terrain/buffercache.cpp +++ b/components/terrain/buffercache.cpp @@ -4,6 +4,162 @@ #include "defs.hpp" +namespace +{ + +template +Ogre::HardwareIndexBufferSharedPtr createIndexBuffer(unsigned int flags, unsigned int verts, Ogre::HardwareIndexBuffer::IndexType type) +{ + // LOD level n means every 2^n-th vertex is kept + size_t lodLevel = (flags >> (4*4)); + + size_t lodDeltas[4]; + for (int i=0; i<4; ++i) + lodDeltas[i] = (flags >> (4*i)) & (0xf); + + bool anyDeltas = (lodDeltas[Terrain::North] || lodDeltas[Terrain::South] || lodDeltas[Terrain::West] || lodDeltas[Terrain::East]); + + size_t increment = 1 << lodLevel; + assert(increment < verts); + std::vector indices; + indices.reserve((verts-1)*(verts-1)*2*3 / increment); + + size_t rowStart = 0, colStart = 0, rowEnd = verts-1, colEnd = verts-1; + // If any edge needs stitching we'll skip all edges at this point, + // mainly because stitching one edge would have an effect on corners and on the adjacent edges + if (anyDeltas) + { + colStart += increment; + colEnd -= increment; + rowEnd -= increment; + rowStart += increment; + } + for (size_t row = rowStart; row < rowEnd; row += increment) + { + for (size_t col = colStart; col < colEnd; col += increment) + { + indices.push_back(verts*col+row); + indices.push_back(verts*(col+increment)+row+increment); + indices.push_back(verts*col+row+increment); + + indices.push_back(verts*col+row); + indices.push_back(verts*(col+increment)+row); + indices.push_back(verts*(col+increment)+row+increment); + } + } + + size_t innerStep = increment; + if (anyDeltas) + { + // Now configure LOD transitions at the edges - this is pretty tedious, + // and some very long and boring code, but it works great + + // South + size_t row = 0; + size_t outerStep = 1 << (lodDeltas[Terrain::South] + lodLevel); + for (size_t col = 0; col < verts-1; col += outerStep) + { + indices.push_back(verts*col+row); + indices.push_back(verts*(col+outerStep)+row); + // Make sure not to touch the right edge + if (col+outerStep == verts-1) + indices.push_back(verts*(col+outerStep-innerStep)+row+innerStep); + else + indices.push_back(verts*(col+outerStep)+row+innerStep); + + for (size_t i = 0; i < outerStep; i += innerStep) + { + // Make sure not to touch the left or right edges + if (col+i == 0 || col+i == verts-1-innerStep) + continue; + indices.push_back(verts*(col)+row); + indices.push_back(verts*(col+i+innerStep)+row+innerStep); + indices.push_back(verts*(col+i)+row+innerStep); + } + } + + // North + row = verts-1; + outerStep = size_t(1) << (lodDeltas[Terrain::North] + lodLevel); + for (size_t col = 0; col < verts-1; col += outerStep) + { + indices.push_back(verts*(col+outerStep)+row); + indices.push_back(verts*col+row); + // Make sure not to touch the left edge + if (col == 0) + indices.push_back(verts*(col+innerStep)+row-innerStep); + else + indices.push_back(verts*col+row-innerStep); + + for (size_t i = 0; i < outerStep; i += innerStep) + { + // Make sure not to touch the left or right edges + if (col+i == 0 || col+i == verts-1-innerStep) + continue; + indices.push_back(verts*(col+i)+row-innerStep); + indices.push_back(verts*(col+i+innerStep)+row-innerStep); + indices.push_back(verts*(col+outerStep)+row); + } + } + + // West + size_t col = 0; + outerStep = size_t(1) << (lodDeltas[Terrain::West] + lodLevel); + for (size_t row = 0; row < verts-1; row += outerStep) + { + indices.push_back(verts*col+row+outerStep); + indices.push_back(verts*col+row); + // Make sure not to touch the top edge + if (row+outerStep == verts-1) + indices.push_back(verts*(col+innerStep)+row+outerStep-innerStep); + else + indices.push_back(verts*(col+innerStep)+row+outerStep); + + for (size_t i = 0; i < outerStep; i += innerStep) + { + // Make sure not to touch the top or bottom edges + if (row+i == 0 || row+i == verts-1-innerStep) + continue; + indices.push_back(verts*col+row); + indices.push_back(verts*(col+innerStep)+row+i); + indices.push_back(verts*(col+innerStep)+row+i+innerStep); + } + } + + // East + col = verts-1; + outerStep = size_t(1) << (lodDeltas[Terrain::East] + lodLevel); + for (size_t row = 0; row < verts-1; row += outerStep) + { + indices.push_back(verts*col+row); + indices.push_back(verts*col+row+outerStep); + // Make sure not to touch the bottom edge + if (row == 0) + indices.push_back(verts*(col-innerStep)+row+innerStep); + else + indices.push_back(verts*(col-innerStep)+row); + + for (size_t i = 0; i < outerStep; i += innerStep) + { + // Make sure not to touch the top or bottom edges + if (row+i == 0 || row+i == verts-1-innerStep) + continue; + indices.push_back(verts*col+row+outerStep); + indices.push_back(verts*(col-innerStep)+row+i+innerStep); + indices.push_back(verts*(col-innerStep)+row+i); + } + } + } + + Ogre::HardwareBufferManager* mgr = Ogre::HardwareBufferManager::getSingletonPtr(); + Ogre::HardwareIndexBufferSharedPtr buffer = mgr->createIndexBuffer(type, + indices.size(), Ogre::HardwareBuffer::HBU_STATIC); + buffer->writeData(0, buffer->getSizeInBytes(), &indices[0], true); + return buffer; +} + +} + namespace Terrain { @@ -48,151 +204,12 @@ namespace Terrain return mIndexBufferMap[flags]; } - // LOD level n means every 2^n-th vertex is kept - size_t lodLevel = (flags >> (4*4)); - - size_t lodDeltas[4]; - for (int i=0; i<4; ++i) - lodDeltas[i] = (flags >> (4*i)) & (0xf); - - bool anyDeltas = (lodDeltas[North] || lodDeltas[South] || lodDeltas[West] || lodDeltas[East]); + Ogre::HardwareIndexBufferSharedPtr buffer; + if (verts*verts > (0xffffu)) + buffer = createIndexBuffer(flags, verts, Ogre::HardwareIndexBuffer::IT_32BIT); + else + buffer = createIndexBuffer(flags, verts, Ogre::HardwareIndexBuffer::IT_16BIT); - size_t increment = 1 << lodLevel; - assert(increment < verts); - std::vector indices; - indices.reserve((verts-1)*(verts-1)*2*3 / increment); - - size_t rowStart = 0, colStart = 0, rowEnd = verts-1, colEnd = verts-1; - // If any edge needs stitching we'll skip all edges at this point, - // mainly because stitching one edge would have an effect on corners and on the adjacent edges - if (anyDeltas) - { - colStart += increment; - colEnd -= increment; - rowEnd -= increment; - rowStart += increment; - } - for (size_t row = rowStart; row < rowEnd; row += increment) - { - for (size_t col = colStart; col < colEnd; col += increment) - { - indices.push_back(verts*col+row); - indices.push_back(verts*(col+increment)+row+increment); - indices.push_back(verts*col+row+increment); - - indices.push_back(verts*col+row); - indices.push_back(verts*(col+increment)+row); - indices.push_back(verts*(col+increment)+row+increment); - } - } - - size_t innerStep = increment; - if (anyDeltas) - { - // Now configure LOD transitions at the edges - this is pretty tedious, - // and some very long and boring code, but it works great - - // South - size_t row = 0; - size_t outerStep = 1 << (lodDeltas[South] + lodLevel); - for (size_t col = 0; col < verts-1; col += outerStep) - { - indices.push_back(verts*col+row); - indices.push_back(verts*(col+outerStep)+row); - // Make sure not to touch the right edge - if (col+outerStep == verts-1) - indices.push_back(verts*(col+outerStep-innerStep)+row+innerStep); - else - indices.push_back(verts*(col+outerStep)+row+innerStep); - - for (size_t i = 0; i < outerStep; i += innerStep) - { - // Make sure not to touch the left or right edges - if (col+i == 0 || col+i == verts-1-innerStep) - continue; - indices.push_back(verts*(col)+row); - indices.push_back(verts*(col+i+innerStep)+row+innerStep); - indices.push_back(verts*(col+i)+row+innerStep); - } - } - - // North - row = verts-1; - outerStep = size_t(1) << (lodDeltas[North] + lodLevel); - for (size_t col = 0; col < verts-1; col += outerStep) - { - indices.push_back(verts*(col+outerStep)+row); - indices.push_back(verts*col+row); - // Make sure not to touch the left edge - if (col == 0) - indices.push_back(verts*(col+innerStep)+row-innerStep); - else - indices.push_back(verts*col+row-innerStep); - - for (size_t i = 0; i < outerStep; i += innerStep) - { - // Make sure not to touch the left or right edges - if (col+i == 0 || col+i == verts-1-innerStep) - continue; - indices.push_back(verts*(col+i)+row-innerStep); - indices.push_back(verts*(col+i+innerStep)+row-innerStep); - indices.push_back(verts*(col+outerStep)+row); - } - } - - // West - size_t col = 0; - outerStep = size_t(1) << (lodDeltas[West] + lodLevel); - for (size_t row = 0; row < verts-1; row += outerStep) - { - indices.push_back(verts*col+row+outerStep); - indices.push_back(verts*col+row); - // Make sure not to touch the top edge - if (row+outerStep == verts-1) - indices.push_back(verts*(col+innerStep)+row+outerStep-innerStep); - else - indices.push_back(verts*(col+innerStep)+row+outerStep); - - for (size_t i = 0; i < outerStep; i += innerStep) - { - // Make sure not to touch the top or bottom edges - if (row+i == 0 || row+i == verts-1-innerStep) - continue; - indices.push_back(verts*col+row); - indices.push_back(verts*(col+innerStep)+row+i); - indices.push_back(verts*(col+innerStep)+row+i+innerStep); - } - } - - // East - col = verts-1; - outerStep = size_t(1) << (lodDeltas[East] + lodLevel); - for (size_t row = 0; row < verts-1; row += outerStep) - { - indices.push_back(verts*col+row); - indices.push_back(verts*col+row+outerStep); - // Make sure not to touch the bottom edge - if (row == 0) - indices.push_back(verts*(col-innerStep)+row+innerStep); - else - indices.push_back(verts*(col-innerStep)+row); - - for (size_t i = 0; i < outerStep; i += innerStep) - { - // Make sure not to touch the top or bottom edges - if (row+i == 0 || row+i == verts-1-innerStep) - continue; - indices.push_back(verts*col+row+outerStep); - indices.push_back(verts*(col-innerStep)+row+i+innerStep); - indices.push_back(verts*(col-innerStep)+row+i); - } - } - } - - Ogre::HardwareBufferManager* mgr = Ogre::HardwareBufferManager::getSingletonPtr(); - Ogre::HardwareIndexBufferSharedPtr buffer = mgr->createIndexBuffer(Ogre::HardwareIndexBuffer::IT_16BIT, - indices.size(), Ogre::HardwareBuffer::HBU_STATIC); - buffer->writeData(0, buffer->getSizeInBytes(), &indices[0], true); mIndexBufferMap[flags] = buffer; return buffer; } From fafc14d5a08f9a38ab4e3924e6d44f0aa2064b02 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 13 Jan 2015 03:11:29 +0100 Subject: [PATCH 199/740] Add proper air movement mechanics (Fixes #2077) --- apps/openmw/mwmechanics/character.cpp | 10 ++++---- apps/openmw/mwworld/physicssystem.cpp | 33 ++++++++------------------- 2 files changed, 14 insertions(+), 29 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 6632f0275..fa7e52af2 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1496,12 +1496,12 @@ void CharacterController::update(float duration) forcestateupdate = (mJumpState != JumpState_InAir); mJumpState = JumpState_InAir; - // This is a guess. All that seems to be known is that "While the player is in the - // air, fJumpMoveBase and fJumpMoveMult governs air control". What does fJumpMoveMult do? static const float fJumpMoveBase = gmst.find("fJumpMoveBase")->getFloat(); - - vec.x *= fJumpMoveBase; - vec.y *= fJumpMoveBase; + static const float fJumpMoveMult = gmst.find("fJumpMoveMult")->getFloat(); + float factor = fJumpMoveBase + fJumpMoveMult * mPtr.getClass().getSkill(mPtr, ESM::Skill::Acrobatics)/100.f; + factor = std::min(1.f, factor); + vec.x *= factor; + vec.y *= factor; vec.z = 0.0f; } else if(vec.z > 0.0f && mJumpState == JumpState_None) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 7375fa4f8..77c5b4460 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -289,7 +289,7 @@ namespace MWWorld // Reset per-frame data physicActor->setWalkingOnWater(false); - /* Anything to collide with? */ + // Anything to collide with? if(!physicActor->getCollisionMode()) { return position + (Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * @@ -317,12 +317,11 @@ namespace MWWorld */ OEngine::Physic::ActorTracer tracer; - Ogre::Vector3 inertia(0.0f); + Ogre::Vector3 inertia = physicActor->getInertialForce(); Ogre::Vector3 velocity; - if(position.z < waterlevel || isFlying) // under water by 3/4 or can fly + if(position.z < waterlevel || isFlying) { - // TODO: Shouldn't water have higher drag in calculating velocity? velocity = (Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z)* Ogre::Quaternion(Ogre::Radian(refpos.rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X)) * movement; } @@ -330,25 +329,12 @@ namespace MWWorld { velocity = Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * movement; - // not in water nor can fly, so need to deal with gravity - if(!physicActor->getOnGround()) // if current OnGround status is false, must be falling or jumping + if (velocity.z > 0.f) + inertia = velocity; + if(!physicActor->getOnGround()) { - // If falling or jumping up, add part of the incoming velocity with the current inertia, - // but don't allow increasing inertia beyond actor's speed (except on the initial jump impulse) - float actorSpeed = ptr.getClass().getSpeed(ptr); - float cap = std::max(actorSpeed, Ogre::Vector2(physicActor->getInertialForce().x, physicActor->getInertialForce().y).length()); - Ogre::Vector3 newVelocity = velocity + physicActor->getInertialForce(); - if (Ogre::Vector2(newVelocity.x, newVelocity.y).squaredLength() > cap*cap) - { - velocity = newVelocity; - float speedXY = Ogre::Vector2(velocity.x, velocity.y).length(); - velocity.x *= cap / speedXY; - velocity.y *= cap / speedXY; - } - else - velocity = newVelocity; + velocity = velocity + physicActor->getInertialForce(); } - inertia = velocity; // NOTE: velocity is for z axis only in this code block } ptr.getClass().getMovementSettings(ptr).mPosition[2] = 0; @@ -371,7 +357,6 @@ namespace MWWorld float remainingTime = time; for(int iterations = 0; iterations < sMaxIterations && remainingTime > 0.01f; ++iterations) { - // NOTE: velocity is either z axis only or x & z axis Ogre::Vector3 nextpos = newPosition + velocity * remainingTime; // If not able to fly, don't allow to swim up into the air @@ -482,7 +467,7 @@ namespace MWWorld // so that we do not stay suspended in air indefinitely. if (tracer.mFraction < 1.0f && tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup == OEngine::Physic::CollisionType_Actor) { - if (Ogre::Vector3(inertia.x, inertia.y, 0).squaredLength() < 100.f*100.f) + if (Ogre::Vector3(velocity.x, velocity.y, 0).squaredLength() < 100.f*100.f) { btVector3 aabbMin, aabbMax; tracer.mHitObject->getCollisionShape()->getAabb(tracer.mHitObject->getWorldTransform(), aabbMin, aabbMax); @@ -508,7 +493,7 @@ namespace MWWorld } physicActor->setOnGround(isOnGround); - newPosition.z -= halfExtents.z; // remove what was added at the beggining + newPosition.z -= halfExtents.z; // remove what was added at the beginning return newPosition; } }; From 7b4665c6234f7190e085396a524c40220a50a3ed Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 13 Jan 2015 03:30:14 +0100 Subject: [PATCH 200/740] Terrain: documentation update --- components/esmterrain/storage.hpp | 2 ++ components/terrain/storage.hpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/components/esmterrain/storage.hpp b/components/esmterrain/storage.hpp index d25f7552b..e184cbc4c 100644 --- a/components/esmterrain/storage.hpp +++ b/components/esmterrain/storage.hpp @@ -38,6 +38,8 @@ namespace ESMTerrain /// Fill vertex buffers for a terrain chunk. /// @note May be called from background threads. Make sure to only call thread-safe functions from here! /// @note returned colors need to be in render-system specific format! Use RenderSystem::convertColourValue. + /// @note Vertices should be written in row-major order (a row is defined as parallel to the x-axis). + /// The specified positions should be in local space, i.e. relative to the center of the terrain chunk. /// @param lodLevel LOD level, 0 = most detailed /// @param size size of the terrain chunk in cell units /// @param center center of the chunk in cell units diff --git a/components/terrain/storage.hpp b/components/terrain/storage.hpp index d3770ea57..aa52ffc4b 100644 --- a/components/terrain/storage.hpp +++ b/components/terrain/storage.hpp @@ -30,6 +30,8 @@ namespace Terrain /// Fill vertex buffers for a terrain chunk. /// @note May be called from background threads. Make sure to only call thread-safe functions from here! /// @note returned colors need to be in render-system specific format! Use RenderSystem::convertColourValue. + /// @note Vertices should be written in row-major order (a row is defined as parallel to the x-axis). + /// The specified positions should be in local space, i.e. relative to the center of the terrain chunk. /// @param lodLevel LOD level, 0 = most detailed /// @param size size of the terrain chunk in cell units /// @param center center of the chunk in cell units From 3ce22d31d807447860234ee5580db398321884ba Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 13 Jan 2015 04:53:49 +0100 Subject: [PATCH 201/740] Fix cursor issue when loading savegame from within mouselook-mode and a warning pops up --- apps/openmw/mwinput/inputmanagerimp.cpp | 38 +++++++++++++++---------- apps/openmw/mwinput/inputmanagerimp.hpp | 2 ++ 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 846cce6a2..fed864dfc 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -302,22 +302,8 @@ namespace MWInput } } - void InputManager::update(float dt, bool disableControls, bool disableEvents) + void InputManager::updateCursorMode() { - mControlsDisabled = disableControls; - - 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(mMouseX), int(mMouseY), mMouseWheel); - - if (mControlsDisabled) - return; - - // update values of channels (as a result of pressed keys) - mInputBinder->update(dt); - bool grab = !MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu) && MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Console; @@ -337,6 +323,28 @@ namespace MWInput { mInputManager->warpMouse(mMouseX, mMouseY); } + } + + void InputManager::update(float dt, bool disableControls, bool disableEvents) + { + mControlsDisabled = disableControls; + + 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(mMouseX), int(mMouseY), mMouseWheel); + + if (mControlsDisabled) + { + updateCursorMode(); + return; + } + + // update values of channels (as a result of pressed keys) + mInputBinder->update(dt); + + updateCursorMode(); // Disable movement in Gui mode if (!(MWBase::Environment::get().getWindowManager()->isGuiMode() diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 346e02ff9..851f24971 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -176,6 +176,8 @@ namespace MWInput void setPlayerControlsEnabled(bool enabled); + void updateCursorMode(); + private: void toggleMainMenu(); void toggleSpell(); From 883f7ec7ce0b62c2b04019898f4419f176433169 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 13 Jan 2015 17:14:54 +0100 Subject: [PATCH 202/740] Move workaround for hiding markers from NIF loader to Scene --- apps/openmw/mwworld/scene.cpp | 21 ++++++++++++++------- components/nifbullet/bulletnifloader.cpp | 18 +++++------------- components/nifbullet/bulletnifloader.hpp | 2 +- components/nifogre/ogrenifloader.cpp | 5 ----- 4 files changed, 20 insertions(+), 26 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index d7548018f..d054cd560 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -21,6 +21,18 @@ namespace { + + void addObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, + MWRender::RenderingManager& rendering) + { + std::string model = Misc::ResourceHelpers::correctActorModelPath(ptr.getClass().getModel(ptr)); + std::string id = ptr.getClass().getId(ptr); + if (id == "prisonmarker" || id == "divinemarker" || id == "templemarker" || id == "northmarker") + model = ""; + rendering.addObject(ptr, model); + ptr.getClass().insertObject (ptr, model, physics); + } + void updateObjectLocalRotation (const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWRender::RenderingManager& rendering) { @@ -80,10 +92,7 @@ namespace { try { - const std::string& model = Misc::ResourceHelpers::correctActorModelPath(ptr.getClass().getModel(ptr)); - mRendering.addObject(ptr, model); - ptr.getClass().insertObject (ptr, model, mPhysics); - + addObject(ptr, mPhysics, mRendering); updateObjectLocalRotation(ptr, mPhysics, mRendering); if (ptr.getRefData().getBaseNode()) { @@ -530,9 +539,7 @@ namespace MWWorld void Scene::addObjectToScene (const Ptr& ptr) { - const std::string& model = Misc::ResourceHelpers::correctActorModelPath(ptr.getClass().getModel(ptr)); - mRendering.addObject(ptr, model); - ptr.getClass().insertObject (ptr, model, *mPhysics); + addObject(ptr, *mPhysics, mRendering); MWBase::Environment::get().getWorld()->rotateObject(ptr, 0, 0, 0, true); MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale()); } diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 130787797..8cb531f55 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -158,7 +158,7 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) mShape->mAutogenerated = hasAutoGeneratedCollision(node); //do a first pass - handleNode(node,0,false,false,false); + handleNode(node,0,false,false); if(mBoundingBox != NULL) { @@ -232,7 +232,7 @@ bool ManualBulletShapeLoader::hasAutoGeneratedCollision(Nif::Node const * rootNo void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, bool isCollisionNode, - bool raycasting, bool isMarker, bool isAnimated) + bool raycasting, bool isAnimated) { // Accumulate the flags from all the child nodes. This works for all // the flags we currently use, at least. @@ -254,13 +254,6 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, if(node->recType == Nif::RC_AvoidNode) flags |= 0x800; - // Marker objects - /// \todo don't do this in the editor - std::string nodename = node->name; - Misc::StringUtils::toLower(nodename); - if (nodename.find("marker") != std::string::npos) - isMarker = true; - // Check for extra data Nif::Extra const *e = node; while (!e->extra.empty()) @@ -285,12 +278,11 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, // Marker objects. These are only visible in the // editor. Until and unless we add an editor component to // the engine, just skip this entire node. - isMarker = true; + return; } } - if ( (isCollisionNode || (mShape->mAutogenerated && !raycasting)) - && (!isMarker || (!mShape->mAutogenerated && !raycasting))) + if (isCollisionNode || (mShape->mAutogenerated && !raycasting)) { // NOTE: a trishape with hasBounds=true, but no BBoxCollision flag should NOT go through handleNiTriShape! // It must be ignored completely. @@ -319,7 +311,7 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, for(size_t i = 0;i < list.length();i++) { if(!list[i].empty()) - handleNode(list[i].getPtr(), flags, isCollisionNode, raycasting, isMarker, isAnimated); + handleNode(list[i].getPtr(), flags, isCollisionNode, raycasting, isAnimated); } } } diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index f95bdfccf..889599719 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -107,7 +107,7 @@ private: *Parse a node. */ void handleNode(Nif::Node const *node, int flags, bool isCollisionNode, - bool raycasting, bool isMarker, bool isAnimated=false); + bool raycasting, bool isAnimated=false); /** *Helper function diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 7ec2c2c24..51e5d10da 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1176,11 +1176,6 @@ class NIFObjectLoader if(node->recType == Nif::RC_RootCollisionNode) isRootCollisionNode = true; - // Marker objects: just skip the entire node branch - /// \todo don't do this in the editor - if (node->name.find("marker") != std::string::npos) - return; - if(node->recType == Nif::RC_NiBSAnimationNode) animflags |= node->flags; else if(node->recType == Nif::RC_NiBSParticleNode) From f11ec653d0f2ab00431f1af6abc9435d7a93ae9a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 13 Jan 2015 17:29:25 +0100 Subject: [PATCH 203/740] Add setting for showing MRK nodes to NIF loaders This makes marker objects show up in OpenCS. --- apps/opencs/editor.cpp | 4 +++- apps/opencs/view/world/physicssystem.cpp | 2 +- components/nifbullet/bulletnifloader.cpp | 5 ++--- components/nifbullet/bulletnifloader.hpp | 5 ++++- components/nifogre/ogrenifloader.cpp | 19 ++++++++++++++++++- components/nifogre/ogrenifloader.hpp | 8 ++++++++ 6 files changed, 36 insertions(+), 7 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 826619b5d..77644665f 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -15,7 +15,7 @@ #include #include - +#include #include #include "model/doc/document.hpp" @@ -35,6 +35,8 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit) ogreInit.init ((mCfgMgr.getUserConfigPath() / "opencsOgre.log").string()); + NifOgre::Loader::setShowMarkers(true); + mOverlaySystem.reset (new CSVRender::OverlaySystem); Bsa::registerResources (Files::Collections (config.first, !mFsStrict), config.second, true, diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 57909f4d3..2cbe17dcf 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -16,7 +16,7 @@ namespace CSVWorld PhysicsSystem::PhysicsSystem() { // Create physics. shapeLoader is deleted by the physic engine - NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); + NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(true); mEngine = new OEngine::Physic::PhysicEngine(shapeLoader); } diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 8cb531f55..372716b68 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -274,10 +274,9 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, // No collision. Use an internal flag setting to mark this. flags |= 0x800; } - else if (sd->string == "MRK") + else if (sd->string == "MRK" && !mShowMarkers) // Marker objects. These are only visible in the - // editor. Until and unless we add an editor component to - // the engine, just skip this entire node. + // editor. return; } } diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index 889599719..56d98834d 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -67,11 +67,12 @@ struct TriangleMeshShape : public btBvhTriangleMeshShape class ManualBulletShapeLoader : public OEngine::Physic::BulletShapeLoader { public: - ManualBulletShapeLoader() + ManualBulletShapeLoader(bool showMarkers=false) : mShape(NULL) , mStaticMesh(NULL) , mCompoundShape(NULL) , mBoundingBox(NULL) + , mShowMarkers(showMarkers) { } @@ -130,6 +131,8 @@ private: btBoxShape *mBoundingBox; std::set mControlledNodes; + + bool mShowMarkers; }; diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 51e5d10da..17df7a3cd 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -689,6 +689,14 @@ public: */ class NIFObjectLoader { + static bool sShowMarkers; +public: + static void setShowMarkers(bool show) + { + sShowMarkers = show; + } +private: + static void warn(const std::string &msg) { std::cerr << "NIFObjectLoader: Warn: " << msg << std::endl; @@ -1208,7 +1216,7 @@ class NIFObjectLoader const Nif::NiStringExtraData *sd = static_cast(e.getPtr()); // String markers may contain important information // affecting the entire subtree of this obj - if(sd->string == "MRK") + if(sd->string == "MRK" && !sShowMarkers) { // Marker objects. These meshes are only visible in the // editor. @@ -1471,5 +1479,14 @@ void Loader::createKfControllers(Ogre::Entity *skelBase, NIFObjectLoader::loadKf(skelBase->getSkeleton(), name, textKeys, ctrls); } +bool Loader::sShowMarkers = false; +bool NIFObjectLoader::sShowMarkers = false; + +void Loader::setShowMarkers(bool show) +{ + sShowMarkers = show; + NIFObjectLoader::setShowMarkers(show); +} + } // namespace NifOgre diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index fd5ddca7d..c13532644 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -110,10 +110,18 @@ public: std::string name, const std::string &group="General"); + /// Set whether or not nodes marked as "MRK" should be shown. + /// These should be hidden ingame, but visible in the editior. + /// Default: false. + static void setShowMarkers(bool show); + static void createKfControllers(Ogre::Entity *skelBase, const std::string &name, TextKeyMap &textKeys, std::vector > &ctrls); + +private: + static bool sShowMarkers; }; // FIXME: Should be with other general Ogre extensions. From 2ac4a74a34d150cb135d8c9545fe117734f21b9c Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 13 Jan 2015 18:09:10 +0100 Subject: [PATCH 204/740] Fix running AI for dead actors --- apps/openmw/mwmechanics/actors.cpp | 20 ++++++++++++++------ apps/openmw/mwmechanics/aisequence.cpp | 3 +-- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index a454d816a..64434a304 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -42,6 +42,12 @@ namespace { +bool isConscious(const MWWorld::Ptr& ptr) +{ + const MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr); + return !stats.isDead() && !stats.getKnockedDown(); +} + void adjustBoundItem (const std::string& item, bool bound, const MWWorld::Ptr& actor) { if (bound) @@ -1101,12 +1107,12 @@ namespace MWMechanics updateCrimePersuit(iter->first, duration); if (iter->first != player) - iter->first.getClass().getCreatureStats(iter->first).getAiSequence().execute(iter->first,iter->second->getAiState(), duration); - - CreatureStats &stats = iter->first.getClass().getCreatureStats(iter->first); - if(!stats.isDead()) { - if (stats.getAiSequence().isInCombat()) hostilesCount++; + CreatureStats &stats = iter->first.getClass().getCreatureStats(iter->first); + if (isConscious(iter->first)) + stats.getAiSequence().execute(iter->first,iter->second->getAiState(), duration); + + if (stats.getAiSequence().isInCombat() && !stats.isDead()) hostilesCount++; } } @@ -1515,7 +1521,9 @@ namespace MWMechanics for (PtrActorMap::iterator it = map.begin(); it != map.end(); ++it) { MWWorld::Ptr ptr = it->first; - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr() + || !isConscious(ptr) + || ptr.getClass().getCreatureStats(ptr).getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0) continue; MWMechanics::AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence(); seq.fastForward(ptr, it->second->getAiState()); diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 364e6effe..533bcd17c 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -152,8 +152,7 @@ bool AiSequence::isPackageDone() const void AiSequence::execute (const MWWorld::Ptr& actor, AiState& state,float duration) { - if(actor != MWBase::Environment::get().getWorld()->getPlayerPtr() - && !actor.getClass().getCreatureStats(actor).getKnockedDown()) + if(actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) { if (!mPackages.empty()) { From a3c861b7fa1c68b20a20ff9edc927dc406956e80 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 14 Jan 2015 00:07:14 +0100 Subject: [PATCH 205/740] Idle voice fix --- apps/openmw/mwmechanics/aiwander.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index c3278a5ad..73f066140 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -311,14 +311,18 @@ namespace MWMechanics && actor.getRefData().getPosition().pos[2] < 3000 && MWBase::Environment::get().getSoundManager()->sayDone(actor)) { - float roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 10000; // [0, 9999] MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - // Don't bother if the player is out of hearing range static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore() .get().find("fVoiceIdleOdds")->getFloat(); - float x = fVoiceIdleOdds * MWBase::Environment::get().getFrameDuration(); + float roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 10000; + + // In vanilla MW the chance was FPS dependent, and did not allow proper changing of fVoiceIdleOdds + // due to the roll being an integer. + // Our implementation does not have these issues, so needs to be recalibrated. We chose to + // use the chance MW would have when run at 60 FPS with the default value of the GMST for calibration. + float x = fVoiceIdleOdds * 0.6 * (MWBase::Environment::get().getFrameDuration() / 0.1); // Only say Idle voices when player is in LOS // A bit counterintuitive, likely vanilla did this to reduce the appearance of From 52ed3d92a8c86224bc4ab0dc24aeb7ad797a8c96 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 14 Jan 2015 17:59:04 +0100 Subject: [PATCH 206/740] Fix btCompoundShape scaling (Fixes #1683) --- apps/openmw/mwworld/physicssystem.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 77c5b4460..993e1aa25 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -73,10 +73,12 @@ void animateCollisionShapes (std::map(instance.mCompound); btTransform trans; - trans.setOrigin(BtOgre::Convert::toBullet(bone->_getDerivedPosition())); + trans.setOrigin(BtOgre::Convert::toBullet(bone->_getDerivedPosition()) * compound->getLocalScaling()); trans.setRotation(BtOgre::Convert::toBullet(bone->_getDerivedOrientation())); - compound->getChildShape(shapeIt->second)->setLocalScaling(BtOgre::Convert::toBullet(bone->_getDerivedScale())); + compound->getChildShape(shapeIt->second)->setLocalScaling( + compound->getLocalScaling() * + BtOgre::Convert::toBullet(bone->_getDerivedScale())); compound->updateChildTransform(shapeIt->second, trans); } From d387c207d19aa4b0685207e9b0a48d841ac68899 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 14 Jan 2015 18:43:42 +0100 Subject: [PATCH 207/740] Fix initial scaling for btCompoundShape children (Fixes #2234) --- components/nifbullet/bulletnifloader.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 372716b68..35d552726 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -365,10 +365,17 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int TriangleMeshShape* childShape = new TriangleMeshShape(childMesh,true); - childShape->setLocalScaling(btVector3(transform[0][0], transform[1][1], transform[2][2])); - + float scale = shape->trafo.scale; + const Nif::Node* parent = shape; + while (parent->parent) + { + parent = parent->parent; + scale *= parent->trafo.scale; + } Ogre::Quaternion q = transform.extractQuaternion(); Ogre::Vector3 v = transform.getTrans(); + childShape->setLocalScaling(btVector3(scale, scale, scale)); + btTransform trans(btQuaternion(q.x, q.y, q.z, q.w), btVector3(v.x, v.y, v.z)); if (raycasting) From fb6dd736cfae19269ac2a98e82c2c7d2339697d2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 14 Jan 2015 20:43:15 +0100 Subject: [PATCH 208/740] Reducing number of jobs in .travis.yml to see if this fixes out of memory issues with coverity build --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 079e84a8e..9e302b144 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,7 @@ addons: description: "" notification_email: scrawl@baseoftrash.de build_command_prepend: "cmake ." - build_command: "make -j4" + build_command: "make -j2" branch_pattern: coverity_scan before_install: From 03c3e3e1fffcea07b970d448c91e83fcb968fa47 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 15 Jan 2015 00:33:20 +0100 Subject: [PATCH 209/740] 3 jobs --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9e302b144..f9c917bbb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,7 @@ addons: description: "" notification_email: scrawl@baseoftrash.de build_command_prepend: "cmake ." - build_command: "make -j2" + build_command: "make -j3" branch_pattern: coverity_scan before_install: From cef72385d4f8bfeea46bdc986abf9a37ed7799d2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 15 Jan 2015 00:58:12 +0100 Subject: [PATCH 210/740] Fix extreme frame drop when running into certain corners (Fixes #2023) --- apps/openmw/mwworld/physicssystem.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 993e1aa25..d17d5e089 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -350,6 +350,8 @@ namespace MWWorld velocity *= 1.f-(fStromWalkMult * (angle.valueDegrees()/180.f)); } + Ogre::Vector3 origVelocity = velocity; + Ogre::Vector3 newPosition = position; /* * A loop to find newPosition using tracer, if successful different from the starting position. @@ -427,10 +429,18 @@ namespace MWWorld else { // Can't move this way, try to find another spot along the plane - Ogre::Real movelen = velocity.normalise(); + Ogre::Vector3 direction = velocity; + Ogre::Real movelen = direction.normalise(); Ogre::Vector3 reflectdir = velocity.reflect(tracer.mPlaneNormal); reflectdir.normalise(); - velocity = slide(reflectdir, tracer.mPlaneNormal)*movelen; + + Ogre::Vector3 newVelocity = slide(reflectdir, tracer.mPlaneNormal)*movelen; + if ((newVelocity-velocity).squaredLength() < 0.01) + break; + if (velocity.dotProduct(origVelocity) <= 0.f) + break; + + velocity = newVelocity; // Do not allow sliding upward if there is gravity. Stepping will have taken // care of that. From edbac30a57e20d5d742640f38ee7226aa1af4554 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 15 Jan 2015 01:23:58 +0100 Subject: [PATCH 211/740] Change another dynamic_cast to static_cast (coverity) --- apps/openmw/mwworld/physicssystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index d17d5e089..0090ca010 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -70,7 +70,7 @@ void animateCollisionShapes (std::map(instance.mCompound); + btCompoundShape* compound = static_cast(instance.mCompound); btTransform trans; trans.setOrigin(BtOgre::Convert::toBullet(bone->_getDerivedPosition()) * compound->getLocalScaling()); From 6b2df951677802b138e662b606c83a01105de051 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 15 Jan 2015 02:03:27 +0100 Subject: [PATCH 212/740] Fix for some coverity defects --- apps/openmw/mwworld/worldimp.cpp | 13 +++++++++++-- extern/oics/ICSInputControlSystem.cpp | 3 +++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 011f6c330..fbb0b5869 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2107,6 +2107,9 @@ namespace MWWorld Ogre::Vector3 playerPos(refdata.getPosition().pos); const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); + if (!physactor) + return 0; // shouldn't happen + if((!physactor->getOnGround()&&physactor->getCollisionMode()) || isUnderwater(currentCell, playerPos) || isWalkingOnWater(player)) return 2; if((currentCell->getCell()->mData.mFlags&ESM::Cell::NoSleep) || @@ -2326,9 +2329,15 @@ namespace MWWorld if (!targetActor.getRefData().getBaseNode() || !targetActor.getRefData().getBaseNode()) return false; // not in active cell - Ogre::Vector3 halfExt1 = mPhysEngine->getCharacter(actor.getRefData().getHandle())->getHalfExtents(); + OEngine::Physic::PhysicActor* actor1 = mPhysEngine->getCharacter(actor.getRefData().getHandle()); + OEngine::Physic::PhysicActor* actor2 = mPhysEngine->getCharacter(targetActor.getRefData().getHandle()); + + if (!actor1 || !actor2) + return false; + + Ogre::Vector3 halfExt1 = actor1->getHalfExtents(); const float* pos1 = actor.getRefData().getPosition().pos; - Ogre::Vector3 halfExt2 = mPhysEngine->getCharacter(targetActor.getRefData().getHandle())->getHalfExtents(); + Ogre::Vector3 halfExt2 = actor2->getHalfExtents(); const float* pos2 = targetActor.getRefData().getPosition().pos; btVector3 from(pos1[0],pos1[1],pos1[2]+halfExt1.z*2*0.9); // eye level diff --git a/extern/oics/ICSInputControlSystem.cpp b/extern/oics/ICSInputControlSystem.cpp index 7dc026c7e..e1bd58728 100644 --- a/extern/oics/ICSInputControlSystem.cpp +++ b/extern/oics/ICSInputControlSystem.cpp @@ -36,6 +36,9 @@ namespace ICS , mDetectingBindingControl(NULL) , mLog(log) , mXmouseAxisBinded(false), mYmouseAxisBinded(false) + , mClientHeight(1) + , mClientWidth(1) + , mDetectingBindingDirection(Control::STOP) { ICS_LOG(" - Creating InputControlSystem - "); From b39cc0c8c837f4c01e2d98dc13721f72f52d0de7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 15 Jan 2015 02:49:54 +0100 Subject: [PATCH 213/740] Fix OpenCS window opening issue when config file doesn't exist It would attempt to create a zero-sized window (or even negative-sized, after subtracting the frame dimensions). --- apps/opencs/view/doc/view.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 0d2b6060e..9117a6d03 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -375,17 +375,20 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to : mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews) { - QString width = CSMSettings::UserSettings::instance().settingValue - ("window/default-width"); + int width = CSMSettings::UserSettings::instance().settingValue + ("window/default-width").toInt(); - QString height = CSMSettings::UserSettings::instance().settingValue - ("window/default-height"); + int height = CSMSettings::UserSettings::instance().settingValue + ("window/default-height").toInt(); + + width = std::max(width, 300); + height = std::max(height, 300); // trick to get the window decorations and their sizes show(); hide(); - resize (width.toInt() - (frameGeometry().width() - geometry().width()), - height.toInt() - (frameGeometry().height() - geometry().height())); + resize (width - (frameGeometry().width() - geometry().width()), + height - (frameGeometry().height() - geometry().height())); mSubViewWindow.setDockOptions (QMainWindow::AllowNestedDocks); From bf915d929a3fcc8a5cb06c88c1e8986b4c4ef7b8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 15 Jan 2015 03:35:46 +0100 Subject: [PATCH 214/740] Update idle voices according to research --- apps/openmw/mwmechanics/aiwander.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 73f066140..fbb147b34 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -308,8 +308,7 @@ namespace MWMechanics // Play idle voiced dialogue entries randomly int hello = cStats.getAiSetting(CreatureStats::AI_Hello).getModified(); if (hello > 0 && !MWBase::Environment::get().getWorld()->isSwimming(actor) - && actor.getRefData().getPosition().pos[2] < 3000 && - MWBase::Environment::get().getSoundManager()->sayDone(actor)) + && MWBase::Environment::get().getSoundManager()->sayDone(actor)) { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); @@ -327,7 +326,8 @@ namespace MWMechanics // Only say Idle voices when player is in LOS // A bit counterintuitive, likely vanilla did this to reduce the appearance of // voices going through walls? - if (roll < x && Ogre::Vector3(player.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(pos.pos)) < 1500*1500 + if (roll < x && Ogre::Vector3(player.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(pos.pos)) + < 3000*3000 // maybe should be fAudioVoiceDefaultMaxDistance*fAudioMaxDistanceMult instead && MWBase::Environment::get().getWorld()->getLOS(player, actor)) MWBase::Environment::get().getDialogueManager()->say(actor, "idle"); } From 375d426dd0e87173c668b9abea0f5f958ebc3989 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 15 Jan 2015 11:35:17 +0100 Subject: [PATCH 215/740] check for premature end of scripts more consistently --- components/compiler/scanner.cpp | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index 14ab99c21..83d435962 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -387,10 +387,9 @@ namespace Compiler if (get (c)) { /// \todo hack to allow a space in comparison operators (add option to disable) - if (c==' ') - get (c); - - if (c=='=') + if (c==' ' && !get (c)) + special = S_cmpEQ; + else if (c=='=') special = S_cmpEQ; else { @@ -471,10 +470,9 @@ namespace Compiler if (get (c)) { /// \todo hack to allow a space in comparison operators (add option to disable) - if (c==' ') - get (c); - - if (c=='=') + if (c==' ' && !get (c)) + special = S_cmpLT; + else if (c=='=') { special = S_cmpLE; @@ -495,10 +493,9 @@ namespace Compiler if (get (c)) { /// \todo hack to allow a space in comparison operators (add option to disable) - if (c==' ') - get (c); - - if (c=='=') + if (c==' ' && !get (c)) + special = S_cmpGT; + else if (c=='=') { special = S_cmpGE; From f3c7532660c0d7f5bd806366802be4a61c0b730c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 15 Jan 2015 12:01:59 +0100 Subject: [PATCH 216/740] cleaned up some enum confusion --- apps/opencs/model/filter/valuenode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/filter/valuenode.cpp b/apps/opencs/model/filter/valuenode.cpp index 66b6282d7..26b982441 100644 --- a/apps/opencs/model/filter/valuenode.cpp +++ b/apps/opencs/model/filter/valuenode.cpp @@ -27,7 +27,7 @@ bool CSMFilter::ValueNode::test (const CSMWorld::IdTableBase& table, int row, QVariant data = table.data (index); if (data.type()!=QVariant::Double && data.type()!=QVariant::Bool && data.type()!=QVariant::Int && - data.type()!=QVariant::UInt && data.type()!=static_cast (QMetaType::Float)) + data.type()!=QVariant::UInt) return false; double value = data.toDouble(); From 7b8e6f9dda0e278ec8961d02f42f0ad615a95ec5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 15 Jan 2015 12:04:23 +0100 Subject: [PATCH 217/740] addressed potential 0-pointer issue --- apps/opencs/view/render/object.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index d92b4aaa2..3cf256e11 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -156,11 +156,13 @@ CSVRender::Object::~Object() { clear(); - if(mPhysics) // preview may not have physics enabled - mPhysics->removeObject(mBase->getName()); - if (mBase) + { + if(mPhysics) // preview may not have physics enabled + mPhysics->removeObject(mBase->getName()); + mBase->getCreator()->destroySceneNode (mBase); + } } bool CSVRender::Object::referenceableDataChanged (const QModelIndex& topLeft, From 706df3f881ed974e3372e4e5644a39f1c8adcd58 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 15 Jan 2015 12:13:53 +0100 Subject: [PATCH 218/740] silenced a coverity warning --- apps/opencs/editor.cpp | 3 ++- apps/opencs/view/world/tablesubview.cpp | 20 +++++++++++--------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 826619b5d..21e1270f3 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -75,7 +75,8 @@ CS::Editor::~Editor () mPidFile.close(); if(mServer && boost::filesystem::exists(mPid)) - remove(mPid.string().c_str()); // ignore any error + static_cast ( // silence coverity warning + remove(mPid.string().c_str())); // ignore any error // cleanup global resources used by OEngine delete OEngine::Physic::BulletShapeManager::getSingletonPtr(); diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index 54518023b..729b6b8d7 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -138,17 +138,19 @@ bool CSVWorld::TableSubView::eventFilter (QObject* object, QEvent* event) { if (event->type() == QEvent::Drop) { - QDropEvent* drop = dynamic_cast(event); - const CSMWorld::TableMimeData* data = dynamic_cast(drop->mimeData()); - if (!data) // May happen when non-records (e.g. plain text) are dragged and dropped - return false; - - bool handled = data->holdsType(CSMWorld::UniversalId::Type_Filter); - if (handled) + if (QDropEvent* drop = dynamic_cast(event)) { - mFilterBox->setRecordFilter(data->returnMatching(CSMWorld::UniversalId::Type_Filter).getId()); + const CSMWorld::TableMimeData* data = dynamic_cast(drop->mimeData()); + if (!data) // May happen when non-records (e.g. plain text) are dragged and dropped + return false; + + bool handled = data->holdsType(CSMWorld::UniversalId::Type_Filter); + if (handled) + { + mFilterBox->setRecordFilter(data->returnMatching(CSMWorld::UniversalId::Type_Filter).getId()); + } + return handled; } - return handled; } return false; } From c55e9b9c586b4687c16fab04cc91a4f9061f3ae4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 15 Jan 2015 15:00:16 +0100 Subject: [PATCH 219/740] one more potential 0-pointer fix --- apps/opencs/view/render/object.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 3cf256e11..3607fb415 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -35,7 +35,8 @@ void CSVRender::Object::clear() { mObject.setNull(); - clearSceneNode (mBase); + if (mBase) + clearSceneNode (mBase); } void CSVRender::Object::update() From fc6aa256bfd1118496db8f6f09dc6397824ecea1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 15 Jan 2015 16:05:25 +0100 Subject: [PATCH 220/740] Add comment --- apps/openmw/mwworld/scene.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index d054cd560..286721df4 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -28,7 +28,7 @@ namespace std::string model = Misc::ResourceHelpers::correctActorModelPath(ptr.getClass().getModel(ptr)); std::string id = ptr.getClass().getId(ptr); if (id == "prisonmarker" || id == "divinemarker" || id == "templemarker" || id == "northmarker") - model = ""; + model = ""; // marker objects that have a hardcoded function in the game logic, should be hidden from the player rendering.addObject(ptr, model); ptr.getClass().insertObject (ptr, model, physics); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index fbb0b5869..104605e65 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2108,7 +2108,7 @@ namespace MWWorld const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); if (!physactor) - return 0; // shouldn't happen + throw std::runtime_error("can't find player"); if((!physactor->getOnGround()&&physactor->getCollisionMode()) || isUnderwater(currentCell, playerPos) || isWalkingOnWater(player)) return 2; From 714b19015cb43e5a5829020730de145b15d3c7f7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 15 Jan 2015 20:31:08 +0100 Subject: [PATCH 221/740] Fix unknown record error message --- apps/openmw/mwstate/statemanagerimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 54c3726bd..87b303b6f 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -426,7 +426,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::str default: // ignore invalid records - std::cerr << "Ignoring unknown record: " << n.name << std::endl; + std::cerr << "Ignoring unknown record: " << n.toString() << std::endl; reader.skipRecord(); } int progressPercent = static_cast(float(reader.getFileOffset())/total*100); From 1869d37cfc3b1dfb786f51a7995818d3225a4f15 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 16 Jan 2015 04:55:42 +0100 Subject: [PATCH 222/740] Remove unused mLastDrowningHit --- apps/openmw/mwmechanics/npcstats.cpp | 3 --- apps/openmw/mwmechanics/npcstats.hpp | 2 -- components/esm/npcstats.cpp | 8 +++----- components/esm/npcstats.hpp | 1 - 4 files changed, 3 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index ba01caf95..6d9388408 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -33,7 +33,6 @@ MWMechanics::NpcStats::NpcStats() , mWerewolfKills (0) , mProfit(0) , mTimeToStartDrowning(20.0) -, mLastDrowningHit(0) { mSkillIncreases.resize (ESM::Attribute::Length, 0); } @@ -522,7 +521,6 @@ void MWMechanics::NpcStats::writeState (ESM::NpcStats& state) const std::copy (mUsedIds.begin(), mUsedIds.end(), std::back_inserter (state.mUsedIds)); state.mTimeToStartDrowning = mTimeToStartDrowning; - state.mLastDrowningHit = mLastDrowningHit; } void MWMechanics::NpcStats::readState (const ESM::NpcStats& state) @@ -573,5 +571,4 @@ void MWMechanics::NpcStats::readState (const ESM::NpcStats& state) mUsedIds.insert (*iter); mTimeToStartDrowning = state.mTimeToStartDrowning; - mLastDrowningHit = state.mLastDrowningHit; } diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index ee897033b..579455a75 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -46,8 +46,6 @@ namespace MWMechanics /// Countdown to getting damage while underwater float mTimeToStartDrowning; - /// time since last hit from drowning - float mLastDrowningHit; public: diff --git a/components/esm/npcstats.cpp b/components/esm/npcstats.cpp index 3e6aed99d..4ba0ce7e3 100644 --- a/components/esm/npcstats.cpp +++ b/components/esm/npcstats.cpp @@ -75,8 +75,9 @@ void ESM::NpcStats::load (ESMReader &esm) mTimeToStartDrowning = 0; esm.getHNOT (mTimeToStartDrowning, "DRTI"); - mLastDrowningHit = 0; - esm.getHNOT (mLastDrowningHit, "DRLH"); + // No longer used + float lastDrowningHit = 0; + esm.getHNOT (lastDrowningHit, "DRLH"); // No longer used float levelHealthBonus = 0; @@ -146,9 +147,6 @@ void ESM::NpcStats::save (ESMWriter &esm) const if (mTimeToStartDrowning) esm.writeHNT ("DRTI", mTimeToStartDrowning); - if (mLastDrowningHit) - esm.writeHNT ("DRLH", mLastDrowningHit); - if (mCrimeId != -1) esm.writeHNT ("CRID", mCrimeId); } diff --git a/components/esm/npcstats.hpp b/components/esm/npcstats.hpp index 0061fc05f..f6e9c1e58 100644 --- a/components/esm/npcstats.hpp +++ b/components/esm/npcstats.hpp @@ -45,7 +45,6 @@ namespace ESM int mSkillIncrease[8]; std::vector mUsedIds; float mTimeToStartDrowning; - float mLastDrowningHit; int mCrimeId; void load (ESMReader &esm); From b77558726a99427b62d59256db75ace243d4bef7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 16 Jan 2015 14:59:42 +0100 Subject: [PATCH 223/740] Disable collision for placeable objects (Fixes #1634) --- libs/openengine/bullet/physic.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index a3ec25e22..1ef00a0e1 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -461,7 +461,9 @@ namespace Physic BulletShapeManager::getSingletonPtr()->load(outputstring,"General"); BulletShapePtr shape = BulletShapeManager::getSingleton().getByName(outputstring,"General"); - if (placeable && !raycasting && shape->mCollisionShape && shape->mAutogenerated) + // TODO: add option somewhere to enable collision for placeable meshes + + if (placeable && !raycasting && shape->mCollisionShape) return NULL; if (!shape->mCollisionShape && !raycasting) From 14aacf9a726e2b1d94b3339d1403af1ecabab13c Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 16 Jan 2015 17:56:19 +0100 Subject: [PATCH 224/740] Add comment --- apps/openmw/mwmechanics/npcstats.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index 579455a75..4594492e1 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -108,8 +108,10 @@ namespace MWMechanics /// Called at character creation. void flagAsUsed (const std::string& id); + ///< @note Id must be lower-case bool hasBeenUsed (const std::string& id) const; + ///< @note Id must be lower-case int getBounty() const; From fc663addfa336032dab9f02a026474f91e3c80c7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 16 Jan 2015 23:10:57 +0100 Subject: [PATCH 225/740] Fix null character issue in ESMReader::getString --- components/esm/esmreader.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 6facee381..7cf0de1a9 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -299,8 +299,7 @@ std::string ESMReader::getString(int size) char *ptr = &mBuffer[0]; getExact(ptr, size); - if (size>0 && ptr[size-1]==0) - --size; + size = strnlen(ptr, size); // Convert to UTF8 and return if (mEncoder) From 031eec45509c3b157dd4fce9e366ac4fcfffe571 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 17 Jan 2015 00:11:36 +0100 Subject: [PATCH 226/740] Starting ESS importer for Morrowind save files --- CMakeLists.txt | 11 + apps/essimporter/CMakeLists.txt | 25 +++ apps/essimporter/converter.cpp | 40 ++++ apps/essimporter/converter.hpp | 262 +++++++++++++++++++++++ apps/essimporter/importacdt.hpp | 25 +++ apps/essimporter/importcellref.cpp | 28 +++ apps/essimporter/importcellref.hpp | 33 +++ apps/essimporter/importcrec.cpp | 13 ++ apps/essimporter/importcrec.hpp | 22 ++ apps/essimporter/importer.cpp | 306 +++++++++++++++++++++++++++ apps/essimporter/importer.hpp | 25 +++ apps/essimporter/importercontext.cpp | 0 apps/essimporter/importercontext.hpp | 65 ++++++ apps/essimporter/importnpcc.cpp | 18 ++ apps/essimporter/importnpcc.hpp | 29 +++ apps/essimporter/importplayer.cpp | 59 ++++++ apps/essimporter/importplayer.hpp | 58 +++++ apps/essimporter/main.cpp | 60 ++++++ components/esm/esmreader.hpp | 1 + components/esm/loadcell.cpp | 5 + components/esm/loadnpcc.hpp | 29 +-- components/esm/loadscpt.cpp | 26 +++ components/esm/loadtes3.cpp | 19 ++ components/esm/loadtes3.hpp | 14 ++ 24 files changed, 1161 insertions(+), 12 deletions(-) create mode 100644 apps/essimporter/CMakeLists.txt create mode 100644 apps/essimporter/converter.cpp create mode 100644 apps/essimporter/converter.hpp create mode 100644 apps/essimporter/importacdt.hpp create mode 100644 apps/essimporter/importcellref.cpp create mode 100644 apps/essimporter/importcellref.hpp create mode 100644 apps/essimporter/importcrec.cpp create mode 100644 apps/essimporter/importcrec.hpp create mode 100644 apps/essimporter/importer.cpp create mode 100644 apps/essimporter/importer.hpp create mode 100644 apps/essimporter/importercontext.cpp create mode 100644 apps/essimporter/importercontext.hpp create mode 100644 apps/essimporter/importnpcc.cpp create mode 100644 apps/essimporter/importnpcc.hpp create mode 100644 apps/essimporter/importplayer.cpp create mode 100644 apps/essimporter/importplayer.hpp create mode 100644 apps/essimporter/main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 0bbce7ad4..6e971b8fb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,6 +58,7 @@ 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) @@ -414,6 +415,9 @@ IF(NOT WIN32 AND NOT APPLE) IF(BUILD_MWINIIMPORTER) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/mwiniimport" DESTINATION "${BINDIR}" ) ENDIF(BUILD_MWINIIMPORTER) + IF(BUILD_ESSIMPORTER) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-essimporter" DESTINATION "${BINDIR}" ) + ENDIF(BUILD_ESSIMPORTER) IF(BUILD_OPENCS) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/opencs" DESTINATION "${BINDIR}" ) ENDIF(BUILD_OPENCS) @@ -472,6 +476,9 @@ if(WIN32) IF(BUILD_MWINIIMPORTER) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/mwiniimport.exe" DESTINATION ".") ENDIF(BUILD_MWINIIMPORTER) + IF(BUILD_ESSIMPORTER) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-essimporter.exe" DESTINATION ".") + ENDIF(BUILD_ESSIMPORTER) IF(BUILD_OPENCS) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/opencs.exe" DESTINATION ".") INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION ".") @@ -582,6 +589,10 @@ if (BUILD_MWINIIMPORTER) add_subdirectory( apps/mwiniimporter ) endif() +if (BUILD_ESSIMPORTER) + add_subdirectory (apps/essimporter ) +endif() + if (BUILD_OPENCS) add_subdirectory (apps/opencs) endif() diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt new file mode 100644 index 000000000..231e31fd8 --- /dev/null +++ b/apps/essimporter/CMakeLists.txt @@ -0,0 +1,25 @@ +set(ESSIMPORTER_FILES + main.cpp + importer.cpp + importplayer.cpp + importnpcc.cpp + importcrec.cpp + importcellref.cpp + importacdt.hpp + importercontext.cpp + converter.cpp +) + +add_executable(openmw-essimporter + ${ESSIMPORTER_FILES} +) + +target_link_libraries(openmw-essimporter + ${Boost_LIBRARIES} + components +) + +if (BUILD_WITH_CODE_COVERAGE) + add_definitions (--coverage) + target_link_libraries(openmw-essimporter gcov) +endif() diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp new file mode 100644 index 000000000..4f36f13ee --- /dev/null +++ b/apps/essimporter/converter.cpp @@ -0,0 +1,40 @@ +#include "converter.hpp" + +#include + +namespace +{ + + void convertImage(char* data, int size, int width, int height, Ogre::PixelFormat pf, const std::string& out) + { + Ogre::Image screenshot; + Ogre::DataStreamPtr stream (new Ogre::MemoryDataStream(data, size)); + screenshot.loadRawData(stream, width, height, 1, pf); + screenshot.save(out); + } + +} + +namespace ESSImport +{ + + + struct MAPH + { + unsigned int size; + unsigned int value; + }; + + void ConvertFMAP::read(ESM::ESMReader &esm) + { + MAPH maph; + esm.getHNT(maph, "MAPH"); + std::vector data; + esm.getSubNameIs("MAPD"); + esm.getSubHeader(); + data.resize(esm.getSubSize()); + esm.getExact(&data[0], data.size()); + convertImage(&data[0], data.size(), maph.size, maph.size, Ogre::PF_BYTE_RGB, "map.tga"); + } + +} diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp new file mode 100644 index 000000000..2662f8c75 --- /dev/null +++ b/apps/essimporter/converter.hpp @@ -0,0 +1,262 @@ +#ifndef OPENMW_ESSIMPORT_CONVERTER_H +#define OPENMW_ESSIMPORT_CONVERTER_H + +#include +#include + +#include +#include +#include +#include +#include "importcrec.hpp" + +#include "importercontext.hpp" +#include "importcellref.hpp" + +namespace ESSImport +{ + +class Converter +{ +public: + /// @return the order for writing this converter's records to the output file, in relation to other converters + virtual int getStage() { return 1; } + + virtual ~Converter() {} + + void setContext(Context& context) { mContext = &context; } + + virtual void read(ESM::ESMReader& esm) + { + } + + /// Called after the input file has been read in completely, which may be necessary + /// if the conversion process relies on information in other records + virtual void write(ESM::ESMWriter& esm) + { + + } + +protected: + Context* mContext; +}; + +/// Default converter: simply reads the record and writes it unmodified to the output +template +class DefaultConverter : public Converter +{ +public: + virtual int getStage() { return 0; } + + virtual void read(ESM::ESMReader& esm) + { + std::string id = esm.getHNString("NAME"); + T record; + record.load(esm); + mRecords[id] = record; + } + + virtual void write(ESM::ESMWriter& esm) + { + for (typename std::map::const_iterator it = mRecords.begin(); it != mRecords.end(); ++it) + { + esm.startRecord(T::sRecordId); + esm.writeHNString("NAME", it->first); + it->second.save(esm); + esm.endRecord(T::sRecordId); + } + } + +protected: + std::map mRecords; +}; + +class ConvertNPC : public Converter +{ +public: + virtual void read(ESM::ESMReader &esm) + { + // this is always the player + ESM::NPC npc; + std::string id = esm.getHNString("NAME"); + assert (id == "player"); + npc.load(esm); + mContext->mPlayer.mObject.mCreatureStats.mLevel = npc.mNpdt52.mLevel; + mContext->mPlayerBase = npc; + std::map empty; + for (std::vector::const_iterator it = npc.mSpells.mList.begin(); it != npc.mSpells.mList.end(); ++it) + mContext->mPlayer.mObject.mCreatureStats.mSpells.mSpells[*it] = empty; + } +}; + +class ConvertGlobal : public DefaultConverter +{ +public: + virtual void read(ESM::ESMReader &esm) + { + std::string id = esm.getHNString("NAME"); + ESM::Global global; + global.load(esm); + if (Misc::StringUtils::ciEqual(id, "gamehour")) + mContext->mHour = global.mValue.getFloat(); + if (Misc::StringUtils::ciEqual(id, "day")) + mContext->mDay = global.mValue.getInteger(); + if (Misc::StringUtils::ciEqual(id, "month")) + mContext->mMonth = global.mValue.getInteger(); + if (Misc::StringUtils::ciEqual(id, "year")) + mContext->mYear = global.mValue.getInteger(); + mRecords[id] = global; + } +}; + +class ConvertClass : public DefaultConverter +{ +public: + virtual void read(ESM::ESMReader &esm) + { + std::string id = esm.getHNString("NAME"); + ESM::Class class_; + class_.load(esm); + + if (id == "NEWCLASSID_CHARGEN") + mContext->mCustomPlayerClassName = class_.mName; + + mRecords[id] = class_; + } +}; + +class ConvertBook : public DefaultConverter +{ +public: + virtual void read(ESM::ESMReader &esm) + { + std::string id = esm.getHNString("NAME"); + ESM::Book book; + book.load(esm); + if (book.mData.mSkillID == -1) + mContext->mPlayer.mObject.mNpcStats.mUsedIds.push_back(Misc::StringUtils::lowerCase(id)); + + mRecords[id] = book; + } +}; + +class ConvertNPCC : public Converter +{ +public: + virtual void read(ESM::ESMReader &esm) + { + std::string id = esm.getHNString("NAME"); + NPCC npcc; + npcc.load(esm); + if (id == "PlayerSaveGame") + { + mContext->mPlayer.mObject.mNpcStats.mReputation = npcc.mNPDT.mReputation; + } + } +}; + +class ConvertREFR : public Converter +{ +public: + virtual void read(ESM::ESMReader &esm) + { + REFR refr; + refr.load(esm); + assert(refr.mRefID == "PlayerSaveGame"); + mContext->mPlayer.mObject.mPosition = refr.mPos; + + ESM::CreatureStats& cStats = mContext->mPlayer.mObject.mCreatureStats; + for (int i=0; i<3; ++i) + { + int writeIndex = translateDynamicIndex(i); + cStats.mDynamic[writeIndex].mBase = refr.mACDT.mDynamic[i][1]; + cStats.mDynamic[writeIndex].mMod = refr.mACDT.mDynamic[i][1]; + cStats.mDynamic[writeIndex].mCurrent = refr.mACDT.mDynamic[i][0]; + } + for (int i=0; i<8; ++i) + { + cStats.mAttributes[i].mBase = refr.mACDT.mAttributes[i][1]; + cStats.mAttributes[i].mMod = refr.mACDT.mAttributes[i][0]; + cStats.mAttributes[i].mCurrent = refr.mACDT.mAttributes[i][0]; + } + ESM::NpcStats& npcStats = mContext->mPlayer.mObject.mNpcStats; + for (int i=0; imPlayer.mBirthsign = pcdt.mBirthsign; + mContext->mPlayer.mObject.mNpcStats.mBounty = pcdt.mBounty; + for (std::vector::const_iterator it = pcdt.mFactions.begin(); it != pcdt.mFactions.end(); ++it) + { + ESM::NpcStats::Faction faction; + faction.mExpelled = it->mFlags & 0x2; + faction.mRank = it->mRank; + faction.mReputation = it->mReputation; + mContext->mPlayer.mObject.mNpcStats.mFactions[it->mFactionName.toString()] = faction; + } + + } +}; + +class ConvertCREC : public Converter +{ +public: + virtual void read(ESM::ESMReader &esm) + { + std::string id = esm.getHNString("NAME"); + CREC crec; + crec.load(esm); + } +}; + +class ConvertFMAP : public Converter +{ +public: + virtual void read(ESM::ESMReader &esm); +}; + +class ConvertCell : public Converter +{ +public: + virtual void read(ESM::ESMReader& esm) + { + ESM::Cell cell; + std::string id = esm.getHNString("NAME"); + cell.load(esm, false); + CellRef ref; + while (esm.hasMoreSubs()) + { + ref.load (esm); + if (esm.isNextSub("DELE")) + std::cout << "deleted ref " << ref.mIndexedRefId << std::endl; + } + } + +}; + +} + +#endif diff --git a/apps/essimporter/importacdt.hpp b/apps/essimporter/importacdt.hpp new file mode 100644 index 000000000..1d79f899e --- /dev/null +++ b/apps/essimporter/importacdt.hpp @@ -0,0 +1,25 @@ +#ifndef OPENMW_ESSIMPORT_ACDT_H +#define OPENMW_ESSIMPORT_ACDT_H + +namespace ESSImport +{ + + /// Actor data, shared by (at least) REFR and CellRef + struct ACDT + { + unsigned char mUnknown1[40]; + float mDynamic[3][2]; + unsigned char mUnknown2[16]; + float mAttributes[8][2]; + unsigned char mUnknown3[120]; + }; + + /// Unknown, shared by (at least) REFR and CellRef + struct ACSC + { + unsigned char unknown[112]; + }; + +} + +#endif diff --git a/apps/essimporter/importcellref.cpp b/apps/essimporter/importcellref.cpp new file mode 100644 index 000000000..f59358d8b --- /dev/null +++ b/apps/essimporter/importcellref.cpp @@ -0,0 +1,28 @@ +#include "importcellref.hpp" + +#include + +namespace ESSImport +{ + + void CellRef::load(ESM::ESMReader &esm) + { + esm.getHNT(mRefNum.mIndex, "FRMR"); // TODO: adjust RefNum + + mIndexedRefId = esm.getHNString("NAME"); + + esm.getHNT(mACDT, "ACDT"); + + ACSC acsc; + esm.getHNOT(acsc, "ACSC"); + esm.getHNOT(acsc, "ACSL"); + + if (esm.isNextSub("CRED")) + esm.skipHSub(); + + if (esm.isNextSub("ND3D")) + esm.skipHSub(); + esm.getHNOT(mPos, "DATA", 24); + } + +} diff --git a/apps/essimporter/importcellref.hpp b/apps/essimporter/importcellref.hpp new file mode 100644 index 000000000..f06278ba5 --- /dev/null +++ b/apps/essimporter/importcellref.hpp @@ -0,0 +1,33 @@ +#ifndef OPENMW_ESSIMPORT_CELLREF_H +#define OPENMW_ESSIMPORT_CELLREF_H + +#include + +#include + +#include "importacdt.hpp" + +namespace ESM +{ + class ESMReader; +} + +namespace ESSImport +{ + + // Not sure if we can share any code with ESM::CellRef here + struct CellRef + { + std::string mIndexedRefId; + ESM::RefNum mRefNum; + + ACDT mACDT; + + ESM::Position mPos; + + void load(ESM::ESMReader& esm); + }; + +} + +#endif diff --git a/apps/essimporter/importcrec.cpp b/apps/essimporter/importcrec.cpp new file mode 100644 index 000000000..c770b2386 --- /dev/null +++ b/apps/essimporter/importcrec.cpp @@ -0,0 +1,13 @@ +#include "importcrec.hpp" + +#include + +namespace ESSImport +{ + + void CREC::load(ESM::ESMReader &esm) + { + esm.getHNT(mIndex, "INDX"); + } + +} diff --git a/apps/essimporter/importcrec.hpp b/apps/essimporter/importcrec.hpp new file mode 100644 index 000000000..62881c582 --- /dev/null +++ b/apps/essimporter/importcrec.hpp @@ -0,0 +1,22 @@ +#ifndef OPENMW_ESSIMPORT_CREC_H +#define OPENMW_ESSIMPORT_CREC_H + +namespace ESM +{ + class ESMReader; +} + +namespace ESSImport +{ + + /// Creature changes + struct CREC + { + int mIndex; + + void load(ESM::ESMReader& esm); + }; + +} + +#endif diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp new file mode 100644 index 000000000..96b79e029 --- /dev/null +++ b/apps/essimporter/importer.cpp @@ -0,0 +1,306 @@ +#include "importer.hpp" + +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "importercontext.hpp" + +#include "converter.hpp" + +namespace +{ + + void writeScreenshot(const ESM::Header& fileHeader, ESM::SavedGame& out) + { + Ogre::Image screenshot; + std::vector screenshotData = fileHeader.mSCRS; // MemoryDataStream doesn't work with const data :( + Ogre::DataStreamPtr screenshotStream (new Ogre::MemoryDataStream(&screenshotData[0], screenshotData.size())); + screenshot.loadRawData(screenshotStream, 128, 128, 1, Ogre::PF_BYTE_BGRA); + Ogre::DataStreamPtr encoded = screenshot.encode("jpg"); + out.mScreenshot.resize(encoded->size()); + encoded->read(&out.mScreenshot[0], encoded->size()); + } + +} + +namespace ESSImport +{ + + Importer::Importer(const std::string &essfile, const std::string &outfile) + : mEssFile(essfile) + , mOutFile(outfile) + { + + } + + struct File + { + struct Subrecord + { + std::string mName; + size_t mFileOffset; + std::vector mData; + }; + + struct Record + { + std::string mName; + size_t mFileOffset; + std::vector mSubrecords; + }; + + std::vector mRecords; + }; + + void read(const std::string& filename, File& file) + { + ESM::ESMReader esm; + esm.open(filename); + + while (esm.hasMoreRecs()) + { + ESM::NAME n = esm.getRecName(); + esm.getRecHeader(); + + File::Record rec; + rec.mName = n.toString(); + rec.mFileOffset = esm.getFileOffset(); + while (esm.hasMoreSubs()) + { + File::Subrecord sub; + esm.getSubName(); + esm.getSubHeader(); + sub.mFileOffset = esm.getFileOffset(); + sub.mName = esm.retSubName().toString(); + sub.mData.resize(esm.getSubSize()); + esm.getExact(&sub.mData[0], sub.mData.size()); + rec.mSubrecords.push_back(sub); + } + file.mRecords.push_back(rec); + } + } + + void Importer::compare() + { + // data that always changes should be blacklisted + std::set > blacklist; + blacklist.insert(std::make_pair("GLOB", "FLTV")); // gamehour + blacklist.insert(std::make_pair("REFR", "DATA")); // player position + + File file1; + read(mEssFile, file1); + File file2; + read(mOutFile, file2); // todo rename variable + + for (unsigned int i=0; i= file2.mRecords.size()) + { + std::cout << "Record in file1 not present in file2: (1) 0x" << std::hex << rec.mFileOffset; + return; + } + + File::Record rec2 = file2.mRecords[i]; + + if (rec.mName != rec2.mName) + { + std::cout << "Different record name at (2) 0x" << std::hex << rec2.mFileOffset << std::endl; + return; // TODO: try to recover + } + + // FIXME: use max(size1, size2) + for (unsigned int j=0; j= rec2.mSubrecords.size()) + { + std::cout << "Subrecord in file1 not present in file2: (1) 0x" << std::hex << sub.mFileOffset; + return; + } + + File::Subrecord sub2 = rec2.mSubrecords[j]; + + if (sub.mName != sub2.mName) + { + std::cout << "Different subrecord name (" << rec.mName << "." << sub.mName << " vs. " << sub2.mName << ") at (1) 0x" << std::hex << sub.mFileOffset + << " (2) 0x" << sub2.mFileOffset << std::endl; + return; // TODO: try to recover + } + + if (sub.mData != sub2.mData) + { + if (blacklist.find(std::make_pair(rec.mName, sub.mName)) != blacklist.end()) + continue; + + std::cout << "Different subrecord data for " << rec.mName << "." << sub.mName << " at (1) 0x" << std::hex << sub.mFileOffset + << " (2) 0x" << sub2.mFileOffset << std::endl; + + std::cout << "Data 1:" << std::endl; + for (unsigned int k=0; k globals; + + const unsigned int recREFR = ESM::FourCC<'R','E','F','R'>::value; + const unsigned int recPCDT = ESM::FourCC<'P','C','D','T'>::value; + const unsigned int recFMAP = ESM::FourCC<'F','M','A','P'>::value; + + std::map > converters; + converters[ESM::REC_GLOB] = boost::shared_ptr(new ConvertGlobal()); + converters[ESM::REC_BOOK] = boost::shared_ptr(new ConvertBook()); + converters[ESM::REC_NPC_] = boost::shared_ptr(new ConvertNPC()); + converters[ESM::REC_NPCC] = boost::shared_ptr(new ConvertNPCC()); + converters[ESM::REC_CREC] = boost::shared_ptr(new ConvertCREC()); + converters[recREFR] = boost::shared_ptr(new ConvertREFR()); + converters[recPCDT] = boost::shared_ptr(new ConvertPCDT()); + converters[recFMAP] = boost::shared_ptr(new ConvertFMAP()); + converters[ESM::REC_CELL] = boost::shared_ptr(new ConvertCell()); + converters[ESM::REC_ALCH] = boost::shared_ptr(new DefaultConverter()); + converters[ESM::REC_CLAS] = boost::shared_ptr(new ConvertClass()); + converters[ESM::REC_SPEL] = boost::shared_ptr(new DefaultConverter()); + converters[ESM::REC_ARMO] = boost::shared_ptr(new DefaultConverter()); + converters[ESM::REC_WEAP] = boost::shared_ptr(new DefaultConverter()); + converters[ESM::REC_CLOT] = boost::shared_ptr(new DefaultConverter()); + converters[ESM::REC_ENCH] = boost::shared_ptr(new DefaultConverter()); + converters[ESM::REC_WEAP] = boost::shared_ptr(new DefaultConverter()); + converters[ESM::REC_LEVC] = boost::shared_ptr(new DefaultConverter()); + converters[ESM::REC_LEVI] = boost::shared_ptr(new DefaultConverter()); + + + for (std::map >::const_iterator it = converters.begin(); + it != converters.end(); ++it) + { + it->second->setContext(context); + } + + while (esm.hasMoreRecs()) + { + ESM::NAME n = esm.getRecName(); + esm.getRecHeader(); + + std::map >::iterator it = converters.find(n.val); + if (it != converters.end()) + { + it->second->read(esm); + } + else + { + std::cerr << "unknown record " << n.toString() << std::endl; + esm.skipRecord(); + } + } + + const ESM::Header& header = esm.getHeader(); + + ESM::ESMWriter writer; + + writer.setFormat (ESM::Header::CurrentFormat); + + std::ofstream stream(mOutFile.c_str(), std::ios::binary); + // all unused + writer.setVersion(0); + writer.setType(0); + writer.setAuthor(""); + writer.setDescription(""); + writer.setRecordCount (0); + writer.save (stream); + + ESM::SavedGame profile; + for (std::vector::const_iterator it = header.mMaster.begin(); + it != header.mMaster.end(); ++it) + { + profile.mContentFiles.push_back(it->name); + } + profile.mDescription = esm.getDesc(); + profile.mInGameTime.mDay = context.mDay; + profile.mInGameTime.mGameHour = context.mHour; + profile.mInGameTime.mMonth = context.mMonth; + profile.mInGameTime.mYear = context.mYear; + profile.mPlayerCell = header.mGameData.mCurrentCell.toString(); + if (context.mPlayerBase.mClass == "NEWCLASSID_CHARGEN") + profile.mPlayerClassName = context.mCustomPlayerClassName; + else + profile.mPlayerClassId = context.mPlayerBase.mClass; + profile.mPlayerLevel = context.mPlayerBase.mNpdt52.mLevel; + profile.mPlayerName = header.mGameData.mPlayerName.toString(); + + writeScreenshot(header, profile); + + writer.startRecord (ESM::REC_SAVE); + profile.save (writer); + writer.endRecord (ESM::REC_SAVE); + + // Writing order should be Dynamic Store -> Cells -> Player, + // so that references to dynamic records can be recognized when loading + for (std::map >::const_iterator it = converters.begin(); + it != converters.end(); ++it) + { + if (it->second->getStage() != 0) + continue; + it->second->write(writer); + } + + writer.startRecord(ESM::REC_NPC_); + writer.writeHNString("NAME", "player"); + context.mPlayerBase.save(writer); + writer.endRecord(ESM::REC_NPC_); + + for (std::map >::const_iterator it = converters.begin(); + it != converters.end(); ++it) + { + if (it->second->getStage() != 1) + continue; + it->second->write(writer); + } + + writer.startRecord(ESM::REC_PLAY); + context.mPlayer.save(writer); + writer.endRecord(ESM::REC_PLAY); + } + + +} diff --git a/apps/essimporter/importer.hpp b/apps/essimporter/importer.hpp new file mode 100644 index 000000000..eb199b6df --- /dev/null +++ b/apps/essimporter/importer.hpp @@ -0,0 +1,25 @@ +#ifndef OPENMW_ESSIMPORTER_IMPORTER_H +#define OPENMW_ESSIMPORTER_IMPORTER_H + +#include + +namespace ESSImport +{ + + class Importer + { + public: + Importer(const std::string& essfile, const std::string& outfile); + + void run(); + + void compare(); + + private: + std::string mEssFile; + std::string mOutFile; + }; + +} + +#endif diff --git a/apps/essimporter/importercontext.cpp b/apps/essimporter/importercontext.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/apps/essimporter/importercontext.hpp b/apps/essimporter/importercontext.hpp new file mode 100644 index 000000000..e9af77678 --- /dev/null +++ b/apps/essimporter/importercontext.hpp @@ -0,0 +1,65 @@ +#ifndef OPENMW_ESSIMPORT_CONTEXT_H +#define OPENMW_ESSIMPORT_CONTEXT_H + +#include + +#include "importnpcc.hpp" +#include "importplayer.hpp" + +#include + +namespace ESSImport +{ + + struct Context + { + ESM::Player mPlayer; + ESM::NPC mPlayerBase; + std::string mCustomPlayerClassName; + + int mDay, mMonth, mYear; + float mHour; + + Context() + { + mPlayer.mAutoMove = 0; + ESM::CellId playerCellId; + playerCellId.mPaged = true; + playerCellId.mIndex.mX = playerCellId.mIndex.mY = 0; + mPlayer.mCellId = playerCellId; + //mPlayer.mLastKnownExteriorPosition + mPlayer.mHasMark = 0; // TODO + mPlayer.mCurrentCrimeId = 0; // TODO + mPlayer.mObject.mCount = 1; + mPlayer.mObject.mEnabled = 1; + mPlayer.mObject.mHasLocals = false; + mPlayer.mObject.mRef.mRefID = "player"; // REFR.mRefID would be PlayerSaveGame + mPlayer.mObject.mCreatureStats.mHasAiSettings = true; + mPlayer.mObject.mCreatureStats.mDead = false; + mPlayer.mObject.mCreatureStats.mDied = false; + mPlayer.mObject.mCreatureStats.mKnockdown = false; + mPlayer.mObject.mCreatureStats.mKnockdownOneFrame = false; + mPlayer.mObject.mCreatureStats.mKnockdownOverOneFrame = false; + mPlayer.mObject.mCreatureStats.mHitRecovery = false; + mPlayer.mObject.mCreatureStats.mBlock = false; + mPlayer.mObject.mCreatureStats.mMovementFlags = 0; + mPlayer.mObject.mCreatureStats.mAttackStrength = 0.f; + mPlayer.mObject.mCreatureStats.mFallHeight = 0.f; + mPlayer.mObject.mCreatureStats.mRecalcDynamicStats = false; + mPlayer.mObject.mCreatureStats.mDrawState = 0; + mPlayer.mObject.mCreatureStats.mDeathAnimation = 0; + mPlayer.mObject.mNpcStats.mIsWerewolf = false; + mPlayer.mObject.mNpcStats.mTimeToStartDrowning = 20; + mPlayer.mObject.mNpcStats.mLevelProgress = 0; + mPlayer.mObject.mNpcStats.mDisposition = 0; + mPlayer.mObject.mNpcStats.mTimeToStartDrowning = 20; + mPlayer.mObject.mNpcStats.mReputation = 0; + mPlayer.mObject.mNpcStats.mCrimeId = -1; + mPlayer.mObject.mNpcStats.mWerewolfKills = 0; + mPlayer.mObject.mNpcStats.mProfit = 0; + } + }; + +} + +#endif diff --git a/apps/essimporter/importnpcc.cpp b/apps/essimporter/importnpcc.cpp new file mode 100644 index 000000000..192fe5da4 --- /dev/null +++ b/apps/essimporter/importnpcc.cpp @@ -0,0 +1,18 @@ +#include "importnpcc.hpp" + +#include + +namespace ESSImport +{ + + void NPCC::load(ESM::ESMReader &esm) + { + esm.getHNT(mNPDT, "NPDT"); + + // container: + // XIDX + // XHLT - condition + // WIDX - equipping? + } + +} diff --git a/apps/essimporter/importnpcc.hpp b/apps/essimporter/importnpcc.hpp new file mode 100644 index 000000000..12135850f --- /dev/null +++ b/apps/essimporter/importnpcc.hpp @@ -0,0 +1,29 @@ +#ifndef OPENMW_ESSIMPORT_NPCC_H +#define OPENMW_ESSIMPORT_NPCC_H + +#include +#include + +namespace ESM +{ + class ESMReader; +} + +namespace ESSImport +{ + + struct NPCC : public ESM::NPC + { + struct NPDT + { + unsigned char unknown[2]; + unsigned char mReputation; + unsigned char unknown2[5]; + } mNPDT; + + void load(ESM::ESMReader &esm); + }; + +} + +#endif diff --git a/apps/essimporter/importplayer.cpp b/apps/essimporter/importplayer.cpp new file mode 100644 index 000000000..81f81e764 --- /dev/null +++ b/apps/essimporter/importplayer.cpp @@ -0,0 +1,59 @@ +#include "importplayer.hpp" + +#include + +namespace ESSImport +{ + + void REFR::load(ESM::ESMReader &esm) + { + esm.getHNT(mRefNum.mIndex, "FRMR"); + + mRefID = esm.getHNString("NAME"); + + if (esm.isNextSub("STPR")) + esm.skipHSub(); // ESS TODO + + esm.getHNT(mACDT, "ACDT"); + + ACSC acsc; + esm.getHNOT(acsc, "ACSC"); + esm.getHNOT(acsc, "ACSL"); + + esm.getHNExact(mSkills, 27*2*sizeof(int), "CHRD"); + + if (esm.isNextSub("ND3D")) + esm.skipHSub(); // ESS TODO (1 byte) + + esm.getHNOT(mPos, "DATA", 24); + } + + void PCDT::load(ESM::ESMReader &esm) + { + if (esm.isNextSub("PNAM")) + esm.skipHSub(); + if (esm.isNextSub("SNAM")) + esm.skipHSub(); + if (esm.isNextSub("NAM9")) + esm.skipHSub(); + + mBounty = 0; + esm.getHNOT(mBounty, "CNAM"); + + mBirthsign = esm.getHNOString("BNAM"); + + if (esm.isNextSub("ENAM")) + esm.skipHSub(); + + while (esm.isNextSub("FNAM")) + { + FNAM fnam; + esm.getHT(fnam); + mFactions.push_back(fnam); + } + + if (esm.isNextSub("KNAM")) + esm.skipHSub(); + } + +} diff --git a/apps/essimporter/importplayer.hpp b/apps/essimporter/importplayer.hpp new file mode 100644 index 000000000..8a0a087a5 --- /dev/null +++ b/apps/essimporter/importplayer.hpp @@ -0,0 +1,58 @@ +#ifndef OPENMW_ESSIMPORT_PLAYER_H +#define OPENMW_ESSIMPORT_PLAYER_H + +#include +#include + +#include +#include +#include + +#include "importacdt.hpp" + +namespace ESM +{ + class ESMReader; +} + +namespace ESSImport +{ + +/// Player-agnostic player data +struct REFR +{ + ACDT mACDT; + + std::string mRefID; + ESM::Position mPos; + ESM::RefNum mRefNum; + + int mSkills[27][2]; + float mAttributes[8][2]; + + void load(ESM::ESMReader& esm); +}; + +/// Other player data +struct PCDT +{ + int mBounty; + std::string mBirthsign; + + struct FNAM + { + unsigned char mRank; + unsigned char mUnknown1[3]; + int mReputation; + unsigned char mFlags; // 0x1: unknown, 0x2: expelled + unsigned char mUnknown2[3]; + ESM::NAME32 mFactionName; + }; + std::vector mFactions; + + void load(ESM::ESMReader& esm); +}; + +} + +#endif diff --git a/apps/essimporter/main.cpp b/apps/essimporter/main.cpp new file mode 100644 index 000000000..0e5c65e95 --- /dev/null +++ b/apps/essimporter/main.cpp @@ -0,0 +1,60 @@ +#include +#include +#include +#include + +#include "importer.hpp" + +namespace bpo = boost::program_options; +namespace bfs = boost::filesystem; + + + +int main(int argc, const char** argv) +{ + try + { + bpo::options_description desc("Syntax: openmw-essimporter infile.ess outfile.omwsave\nAllowed options"); + bpo::positional_options_description p_desc; + desc.add_options() + ("help,h", "produce help message") + ("mwsave,m", bpo::value(), "morrowind .ess save file") + ("output,o", bpo::value(), "output file (.omwsave)") + ("compare,c", "compare two .ess files") + ; + p_desc.add("mwsave", 1).add("output", 1); + + bpo::variables_map vm; + + bpo::parsed_options parsed = bpo::command_line_parser(argc, argv) + .options(desc) + .positional(p_desc) + .run(); + + bpo::store(parsed, vm); + + if(vm.count("help") || !vm.count("mwsave") || !vm.count("output")) { + std::cout << desc; + return 0; + } + + bpo::notify(vm); + + std::string essFile = vm["mwsave"].as(); + std::string outputFile = vm["output"].as(); + + ESSImport::Importer importer(essFile, outputFile); + + if (vm.count("compare")) + importer.compare(); + else + importer.run(); + } + catch (std::exception& e) + { + std::cerr << "Error: " << e.what() << std::endl; + return 1; + } + + return 0; +} diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index 1549e15f5..642ec4168 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -36,6 +36,7 @@ public: const std::string getAuthor() const { return mHeader.mData.author.toString(); } const std::string getDesc() const { return mHeader.mData.desc.toString(); } const std::vector &getGameFiles() const { return mHeader.mMaster; } + const Header& getHeader() const { return mHeader; } int getFormat() const; const NAME &retSubName() const { return mCtx.subName; } uint32_t getSubSize() const { return mCtx.leftSub; } diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index e4f847dec..f6649d94a 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -111,6 +111,11 @@ void Cell::loadData(ESMReader &esm) } esm.getHNT(mData, "DATA", 12); + + // ess only, unknown + char nam8[32]; + if (esm.isNextSub("NAM8")) + esm.getHExact(nam8, 32); } void Cell::postLoad(ESMReader &esm) diff --git a/components/esm/loadnpcc.hpp b/components/esm/loadnpcc.hpp index c87c2545f..6c087fd01 100644 --- a/components/esm/loadnpcc.hpp +++ b/components/esm/loadnpcc.hpp @@ -17,26 +17,29 @@ class ESMWriter; * * Some general observations about savegames: * - * Magical items/potions/spells/etc are added normally as new ALCH, - * SPEL, etc. records, with unique numeric identifiers. - * - * Books with ability enhancements are listed in the save if they have - * been read. - * - * GLOB records set global variables. - * * SCPT records do not define new scripts, but assign values to the * variables of existing ones. * * STLN - stolen items, ONAM is the owner * - * GAME - contains a GMDT (game data) of unknown format - * - * VFXM, SPLM, KLST - no clue + * GAME - weather data + * struct GMDT + { + char mCellName[64]; + int mFogColour; + float mFogDensity; + int mCurrentWeather, mNextWeather; + int mWeatherTransition; // 0-100 transition between weathers, top 3 bytes may be garbage + float mTimeOfNextTransition; // weather changes when gamehour == timeOfNextTransition + int masserPhase, secundaPhase; // top 3 bytes may be garbage + }; + * + * VFXM, SPLM - no clue + * KLST - kill counter * * PCDT - seems to contain a lot of DNAMs, strings? * - * FMAP - MAPH and MAPD, probably map data. + * FMAP - MAPH and MAPD, global map image. * * JOUR - the entire journal in html * @@ -44,6 +47,8 @@ class ESMWriter; * ones you have done or begun. * * REGN - lists all regions in the game, even unvisited ones. + * notable differences to Regions in ESM files: mMapColor may be missing, and includes an unknown WNAM subrecord. + * * * The DIAL/INFO blocks contain changes to characters' dialog status. * diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index 07561c2ea..f2f13d086 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -92,6 +92,32 @@ void Script::load(ESMReader &esm) if (esm.isNextSub("SCVR")) { esm.skipHSub(); } + + // ESS only, TODO: move + if (esm.isNextSub("SLCS")) + { + esm.getSubHeader(); + char unknown[12]; + esm.getExact(unknown, 12); + } + if (esm.isNextSub("SLSD")) + { + float read; + esm.getSubHeader(); + // values of variables? + for (int i=0; i mSCRD; // Used in .ess savegames only, screenshot? + std::vector mSCRS; // Used in .ess savegames only, screenshot? + Data mData; int mFormat; std::vector mMaster; From cbf56dbb4750822650dfc5335e78cc577a596c31 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 17 Jan 2015 03:07:24 +0100 Subject: [PATCH 227/740] ESSImport: work on cell fog of war --- apps/essimporter/converter.cpp | 50 ++++++++++++++++++++++++++++++++++ apps/essimporter/converter.hpp | 35 ++++++++++++++++++------ apps/essimporter/importer.cpp | 6 ++-- components/esm/loadcell.cpp | 5 ---- 4 files changed, 79 insertions(+), 17 deletions(-) diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 4f36f13ee..5f7366625 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -37,4 +37,54 @@ namespace ESSImport convertImage(&data[0], data.size(), maph.size, maph.size, Ogre::PF_BYTE_RGB, "map.tga"); } + void ConvertCell::read(ESM::ESMReader &esm) + { + ESM::Cell cell; + std::string id = esm.getHNString("NAME"); + cell.load(esm, false); + + Cell newcell; + newcell.mCell = cell; + + // fog of war + // seems to be a 1-bit pixel format, 16*16 pixels + // TODO: add bleeding of FOW into neighbouring cells (openmw handles this by writing to the textures, + // MW handles it when rendering only) + unsigned char nam8[32]; + if (esm.isNextSub("NAM8")) + { + esm.getHExact(nam8, 32); + + newcell.mFogOfWar.reserve(16*16); + for (int x=0; x<16; ++x) + { + for (int y=0; y<16; ++y) + { + size_t pos = x*16+y; + size_t bytepos = pos/8; + assert(bytepos<32); + int bit = pos%8; + newcell.mFogOfWar.push_back(((nam8[bytepos] >> bit) & (0x1)) ? 0xffffffff : 0x000000ff); + } + } + + std::ostringstream filename; + filename << "fog_" << cell.mData.mX << "_" << cell.mData.mY << ".tga"; + + convertImage((char*)&newcell.mFogOfWar[0], newcell.mFogOfWar.size()*4, 16, 16, Ogre::PF_BYTE_RGBA, filename.str()); + } + + std::vector cellrefs; + while (esm.hasMoreSubs()) + { + CellRef ref; + ref.load (esm); + if (esm.isNextSub("DELE")) + std::cout << "deleted ref " << ref.mIndexedRefId << std::endl; + } + + newcell.mRefs = cellrefs; + mCells[id] = newcell; + } + } diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 2662f8c75..011508f36 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "importcrec.hpp" #include "importercontext.hpp" @@ -241,20 +242,36 @@ public: class ConvertCell : public Converter { public: - virtual void read(ESM::ESMReader& esm) + virtual void read(ESM::ESMReader& esm); + + virtual void write(ESM::ESMWriter& esm) { - ESM::Cell cell; - std::string id = esm.getHNString("NAME"); - cell.load(esm, false); - CellRef ref; - while (esm.hasMoreSubs()) + for (std::map::const_iterator it = mCells.begin(); it != mCells.end(); ++it) { - ref.load (esm); - if (esm.isNextSub("DELE")) - std::cout << "deleted ref " << ref.mIndexedRefId << std::endl; + const ESM::Cell& cell = it->second.mCell; + esm.startRecord(ESM::REC_CSTA); + ESM::CellState csta; + csta.mHasFogOfWar = 0; + csta.mId = cell.getCellId(); + csta.mId.save(esm); + // TODO csta.mLastRespawn; + // shouldn't be needed if we respawn on global schedule like in original MW + csta.mWaterLevel = cell.mWater; + csta.save(esm); + esm.endRecord(ESM::REC_CSTA); } } +private: + struct Cell + { + ESM::Cell mCell; + std::vector mRefs; + std::vector mFogOfWar; + }; + + std::map mCells; + }; } diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 96b79e029..b511dfe5e 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -99,16 +99,18 @@ namespace ESSImport void Importer::compare() { - // data that always changes should be blacklisted + // data that always changes (and/or is already fully decoded) should be blacklisted std::set > blacklist; blacklist.insert(std::make_pair("GLOB", "FLTV")); // gamehour blacklist.insert(std::make_pair("REFR", "DATA")); // player position + blacklist.insert(std::make_pair("CELL", "NAM8")); // fog of war File file1; read(mEssFile, file1); File file2; read(mOutFile, file2); // todo rename variable + // FIXME: use max(size1, size2) for (unsigned int i=0; i globals; - const unsigned int recREFR = ESM::FourCC<'R','E','F','R'>::value; const unsigned int recPCDT = ESM::FourCC<'P','C','D','T'>::value; const unsigned int recFMAP = ESM::FourCC<'F','M','A','P'>::value; diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index f6649d94a..e4f847dec 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -111,11 +111,6 @@ void Cell::loadData(ESMReader &esm) } esm.getHNT(mData, "DATA", 12); - - // ess only, unknown - char nam8[32]; - if (esm.isNextSub("NAM8")) - esm.getHExact(nam8, 32); } void Cell::postLoad(ESMReader &esm) From b66937d6307d07823f890c5a78a6c5c567221be0 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 17 Jan 2015 15:35:58 +1300 Subject: [PATCH 228/740] add #include Required to get build to work on my configuration. --- libs/openengine/ogre/renderer.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/openengine/ogre/renderer.hpp b/libs/openengine/ogre/renderer.hpp index 1b18a7b0b..33a42f8cd 100644 --- a/libs/openengine/ogre/renderer.hpp +++ b/libs/openengine/ogre/renderer.hpp @@ -6,6 +6,7 @@ */ #include +#include #include From 017e4cd4effb26b0b1a4a9c64b47c17f4d4e0633 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 17 Jan 2015 18:11:03 +1300 Subject: [PATCH 229/740] OpenCS shows plug-ins with load order issues. 1. FileDiaog in OpenCS now shows warning icon beside .esm./.esp files with load order problems. 2. omwlaucher -> replaced "stop" icon with "warning" icon for files with load order problems. --- components/contentselector/model/contentmodel.cpp | 7 +++---- components/contentselector/model/contentmodel.hpp | 11 ++++++----- components/contentselector/view/contentselector.cpp | 4 +++- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 5760a327e..4a1a69169 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -6,13 +6,12 @@ #include #include #include -#include -#include #include "components/esm/esmreader.hpp" -ContentSelectorModel::ContentModel::ContentModel(QObject *parent) : +ContentSelectorModel::ContentModel::ContentModel(QObject *parent, QIcon warningIcon) : QAbstractTableModel(parent), + mWarningIcon(warningIcon), mMimeType ("application/omwcontent"), mMimeTypes (QStringList() << mMimeType), mColumnCount (1), @@ -180,7 +179,7 @@ QVariant ContentSelectorModel::ContentModel::data(const QModelIndex &index, int { case Qt::DecorationRole: { - return isLoadOrderError(file) ? QIcon::fromTheme("edit-delete") : QVariant(); + return isLoadOrderError(file) ? mWarningIcon : QVariant(); } case Qt::EditRole: diff --git a/components/contentselector/model/contentmodel.hpp b/components/contentselector/model/contentmodel.hpp index 153800dca..2ced40f04 100644 --- a/components/contentselector/model/contentmodel.hpp +++ b/components/contentselector/model/contentmodel.hpp @@ -4,7 +4,7 @@ #include #include #include - +#include #include "loadordererror.hpp" namespace ContentSelectorModel @@ -23,7 +23,7 @@ namespace ContentSelectorModel { Q_OBJECT public: - explicit ContentModel(QObject *parent = 0); + explicit ContentModel(QObject *parent, QIcon warningIcon); ~ContentModel(); void setEncoding(const QString &encoding); @@ -57,6 +57,9 @@ namespace ContentSelectorModel void refreshModel(); + /// Checks all plug-ins for load order errors and updates mPluginsWithLoadOrderError with plug-ins with issues + void checkForLoadOrderErrors(); + private: void addFile(EsmFile *file); @@ -65,9 +68,6 @@ namespace ContentSelectorModel void sortFiles(); - /// Checks all plug-ins for load order errors and updates mPluginsWithLoadOrderError with plug-ins with issues - void checkForLoadOrderErrors(); - /// Checks a specific plug-in for load order errors /// \return all errors found for specific plug-in QList checkForLoadOrderErrors(const EsmFile *file, int row) const; @@ -82,6 +82,7 @@ namespace ContentSelectorModel QSet mPluginsWithLoadOrderError; QTextCodec *mCodec; QString mEncoding; + QIcon mWarningIcon; public: diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index 770d45c86..521462d92 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -24,7 +24,8 @@ ContentSelectorView::ContentSelector::ContentSelector(QWidget *parent) : void ContentSelectorView::ContentSelector::buildContentModel() { - mContentModel = new ContentSelectorModel::ContentModel(this); + QIcon warningIcon(ui.addonView->style()->standardIcon(QStyle::SP_MessageBoxWarning).pixmap(QSize(16, 15))); + mContentModel = new ContentSelectorModel::ContentModel(this, warningIcon); } void ContentSelectorView::ContentSelector::buildGameFileView() @@ -161,6 +162,7 @@ void ContentSelectorView::ContentSelector::slotCurrentGameFileIndexChanged(int i oldIndex = index; model->setData(model->index(index, 0), true, Qt::UserRole + 1); + mContentModel->checkForLoadOrderErrors(); } if (proxy) From 71700d2cb119934122dc7fc9f8ffae725cb2fce1 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 18 Jan 2015 11:55:58 +1300 Subject: [PATCH 230/740] Bugfix: OpenCS segfault when plug-in dependency not found. When a file that a plug-in depends on cannot be found, the OpenCS file dialog crashes. Similar problem exists in omwlauncher's "Data Files" dialog. --- components/contentselector/model/contentmodel.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 4a1a69169..3f1feac61 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -597,13 +597,16 @@ QList ContentSelectorModel::ContentModel:: { errors.append(LoadOrderError(LoadOrderError::ErrorCode_MissingDependency, dependentfileName)); } - if (!isChecked(dependentFile->filePath())) - { - errors.append(LoadOrderError(LoadOrderError::ErrorCode_InactiveDependency, dependentfileName)); - } - if (row < indexFromItem(dependentFile).row()) + else { - errors.append(LoadOrderError(LoadOrderError::ErrorCode_LoadOrder, dependentfileName)); + if (!isChecked(dependentFile->filePath())) + { + errors.append(LoadOrderError(LoadOrderError::ErrorCode_InactiveDependency, dependentfileName)); + } + if (row < indexFromItem(dependentFile).row()) + { + errors.append(LoadOrderError(LoadOrderError::ErrorCode_LoadOrder, dependentfileName)); + } } } return errors; From c8ed24cc84f5112d7784d957afd1f6e745225c87 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 18 Jan 2015 16:13:52 +0100 Subject: [PATCH 231/740] ESSImport: creature CellRefs work, need probing to find ref type --- apps/essimporter/converter.cpp | 60 ++++++++++++++++++++++++++++ apps/essimporter/converter.hpp | 22 ++-------- apps/essimporter/importcellref.cpp | 9 +++++ apps/essimporter/importcellref.hpp | 2 + apps/essimporter/importercontext.hpp | 10 ++++- 5 files changed, 84 insertions(+), 19 deletions(-) diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 5f7366625..1ad60d7ba 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -2,6 +2,8 @@ #include +#include + namespace { @@ -81,10 +83,68 @@ namespace ESSImport ref.load (esm); if (esm.isNextSub("DELE")) std::cout << "deleted ref " << ref.mIndexedRefId << std::endl; + cellrefs.push_back(ref); } newcell.mRefs = cellrefs; mCells[id] = newcell; } + void ConvertCell::write(ESM::ESMWriter &esm) + { + for (std::map::const_iterator it = mCells.begin(); it != mCells.end(); ++it) + { + const ESM::Cell& cell = it->second.mCell; + esm.startRecord(ESM::REC_CSTA); + ESM::CellState csta; + csta.mHasFogOfWar = 0; + csta.mId = cell.getCellId(); + csta.mId.save(esm); + // TODO csta.mLastRespawn; + // shouldn't be needed if we respawn on global schedule like in original MW + csta.mWaterLevel = cell.mWater; + csta.save(esm); + + for (std::vector::const_iterator refIt = it->second.mRefs.begin(); refIt != it->second.mRefs.end(); ++refIt) + { + const CellRef& cellref = *refIt; + ESM::CellRef out; + out.blank(); + + if (cellref.mIndexedRefId.size() < 8) + { + std::cerr << "CellRef with no index?" << std::endl; + continue; + } + std::stringstream stream; + stream << cellref.mIndexedRefId.substr(cellref.mIndexedRefId.size()-8,8); + int refIndex; + stream >> refIndex; + + out.mRefID = cellref.mIndexedRefId.substr(0,cellref.mIndexedRefId.size()-8); + + std::map, CREC>::const_iterator crecIt = mContext->mCreatureChanges.find( + std::make_pair(refIndex, out.mRefID)); + if (crecIt != mContext->mCreatureChanges.end()) + { + std::cerr << "Can't' find CREC for " << refIndex << " " << out.mRefID << std::endl; + continue; + } + + ESM::CreatureState objstate; + objstate.mCount = 1; + objstate.mEnabled = cellref.mEnabled; + objstate.mHasLocals = 0; + objstate.mLocalRotation[0] = objstate.mLocalRotation[1] = objstate.mLocalRotation[2] = 0; + objstate.mPosition = cellref.mPos; + objstate.mRef = out; + objstate.mRef.mRefNum = cellref.mRefNum; + esm.writeHNT ("OBJE", ESM::REC_CREA); + objstate.save(esm); + } + + esm.endRecord(ESM::REC_CSTA); + } + } + } diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 011508f36..71eb3ab9f 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -153,6 +153,7 @@ public: { mContext->mPlayer.mObject.mNpcStats.mReputation = npcc.mNPDT.mReputation; } + //mContext->mNpcChanges.insert(std::make_pair(std::make_pair(npcc.mIndex,id), crec)); } }; @@ -230,6 +231,8 @@ public: std::string id = esm.getHNString("NAME"); CREC crec; crec.load(esm); + + mContext->mCreatureChanges.insert(std::make_pair(std::make_pair(crec.mIndex,id), crec)); } }; @@ -243,24 +246,7 @@ class ConvertCell : public Converter { public: virtual void read(ESM::ESMReader& esm); - - virtual void write(ESM::ESMWriter& esm) - { - for (std::map::const_iterator it = mCells.begin(); it != mCells.end(); ++it) - { - const ESM::Cell& cell = it->second.mCell; - esm.startRecord(ESM::REC_CSTA); - ESM::CellState csta; - csta.mHasFogOfWar = 0; - csta.mId = cell.getCellId(); - csta.mId.save(esm); - // TODO csta.mLastRespawn; - // shouldn't be needed if we respawn on global schedule like in original MW - csta.mWaterLevel = cell.mWater; - csta.save(esm); - esm.endRecord(ESM::REC_CSTA); - } - } + virtual void write(ESM::ESMWriter& esm); private: struct Cell diff --git a/apps/essimporter/importcellref.cpp b/apps/essimporter/importcellref.cpp index f59358d8b..51e771081 100644 --- a/apps/essimporter/importcellref.cpp +++ b/apps/essimporter/importcellref.cpp @@ -9,6 +9,11 @@ namespace ESSImport { esm.getHNT(mRefNum.mIndex, "FRMR"); // TODO: adjust RefNum + // this is required since openmw supports more than 255 content files + int pluginIndex = (mRefNum.mIndex & 0xff000000) >> 24; + mRefNum.mContentFile = pluginIndex-1; + mRefNum.mIndex &= 0x00ffffff; + mIndexedRefId = esm.getHNString("NAME"); esm.getHNT(mACDT, "ACDT"); @@ -22,6 +27,10 @@ namespace ESSImport if (esm.isNextSub("ND3D")) esm.skipHSub(); + + mEnabled = true; + esm.getHNOT(mEnabled, "ZNAM"); + esm.getHNOT(mPos, "DATA", 24); } diff --git a/apps/essimporter/importcellref.hpp b/apps/essimporter/importcellref.hpp index f06278ba5..72c5af257 100644 --- a/apps/essimporter/importcellref.hpp +++ b/apps/essimporter/importcellref.hpp @@ -25,6 +25,8 @@ namespace ESSImport ESM::Position mPos; + bool mEnabled; + void load(ESM::ESMReader& esm); }; diff --git a/apps/essimporter/importercontext.hpp b/apps/essimporter/importercontext.hpp index e9af77678..6f26e8329 100644 --- a/apps/essimporter/importercontext.hpp +++ b/apps/essimporter/importercontext.hpp @@ -1,12 +1,16 @@ #ifndef OPENMW_ESSIMPORT_CONTEXT_H #define OPENMW_ESSIMPORT_CONTEXT_H +#include + #include +#include #include "importnpcc.hpp" +#include "importcrec.hpp" #include "importplayer.hpp" -#include + namespace ESSImport { @@ -20,6 +24,10 @@ namespace ESSImport int mDay, mMonth, mYear; float mHour; + // key + std::map, CREC> mCreatureChanges; + std::map, NPCC> mNpcChanges; + Context() { mPlayer.mAutoMove = 0; From 08ad4d73bbf9873887a8c6716c37b641e2603026 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 18 Jan 2015 19:59:29 +0100 Subject: [PATCH 232/740] ESSImport: player is placed in correct cell, npc cellrefs work --- apps/essimporter/CMakeLists.txt | 4 ++- apps/essimporter/convertacdt.cpp | 42 ++++++++++++++++++++++ apps/essimporter/convertacdt.hpp | 22 ++++++++++++ apps/essimporter/converter.cpp | 54 +++++++++++++++++++++------- apps/essimporter/converter.hpp | 40 +++++---------------- apps/essimporter/convertnpcc.cpp | 22 ++++++++++++ apps/essimporter/convertnpcc.hpp | 15 ++++++++ apps/essimporter/importacdt.cpp | 28 +++++++++++++++ apps/essimporter/importacdt.hpp | 24 +++++++++++++ apps/essimporter/importcellref.cpp | 19 +++++----- apps/essimporter/importcellref.hpp | 4 ++- apps/essimporter/importer.cpp | 19 ++++++++-- apps/essimporter/importercontext.hpp | 30 +++------------- apps/essimporter/importnpcc.cpp | 25 ++++++++++--- apps/essimporter/importnpcc.hpp | 12 +++++-- apps/essimporter/importplayer.cpp | 14 +++----- apps/essimporter/importplayer.hpp | 5 +-- components/esm/creaturestate.cpp | 8 ++++- components/esm/creaturestate.hpp | 3 ++ components/esm/creaturestats.cpp | 36 +++++++++++++++++-- components/esm/creaturestats.hpp | 3 ++ components/esm/npcstate.cpp | 9 ++++- components/esm/npcstate.hpp | 3 ++ components/esm/npcstats.cpp | 15 ++++++++ components/esm/npcstats.hpp | 3 ++ components/esm/objectstate.cpp | 16 ++++++++- components/esm/objectstate.hpp | 5 ++- 27 files changed, 370 insertions(+), 110 deletions(-) create mode 100644 apps/essimporter/convertacdt.cpp create mode 100644 apps/essimporter/convertacdt.hpp create mode 100644 apps/essimporter/convertnpcc.cpp create mode 100644 apps/essimporter/convertnpcc.hpp create mode 100644 apps/essimporter/importacdt.cpp diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index 231e31fd8..257a466ee 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -5,9 +5,11 @@ set(ESSIMPORTER_FILES importnpcc.cpp importcrec.cpp importcellref.cpp - importacdt.hpp + importacdt.cpp importercontext.cpp converter.cpp + convertacdt.cpp + convertnpcc.cpp ) add_executable(openmw-essimporter diff --git a/apps/essimporter/convertacdt.cpp b/apps/essimporter/convertacdt.cpp new file mode 100644 index 000000000..81ab61084 --- /dev/null +++ b/apps/essimporter/convertacdt.cpp @@ -0,0 +1,42 @@ +#include "convertacdt.hpp" + +namespace ESSImport +{ + + int translateDynamicIndex(int mwIndex) + { + if (mwIndex == 1) + return 2; + else if (mwIndex == 2) + return 1; + return mwIndex; + } + + void convertACDT (const ACDT& acdt, ESM::CreatureStats& cStats) + { + for (int i=0; i<3; ++i) + { + int writeIndex = translateDynamicIndex(i); + cStats.mDynamic[writeIndex].mBase = acdt.mDynamic[i][1]; + cStats.mDynamic[writeIndex].mMod = acdt.mDynamic[i][1]; + cStats.mDynamic[writeIndex].mCurrent = acdt.mDynamic[i][0]; + } + for (int i=0; i<8; ++i) + { + cStats.mAttributes[i].mBase = acdt.mAttributes[i][1]; + cStats.mAttributes[i].mMod = acdt.mAttributes[i][0]; + cStats.mAttributes[i].mCurrent = acdt.mAttributes[i][0]; + } + } + + void convertNpcData (const ActorData& actorData, ESM::NpcStats& npcStats) + { + for (int i=0; i +#include +#include + +#include "importacdt.hpp" + +namespace ESSImport +{ + + // OpenMW uses Health,Magicka,Fatigue, MW uses Health,Fatigue,Magicka + int translateDynamicIndex(int mwIndex); + + + void convertACDT (const ACDT& acdt, ESM::CreatureStats& cStats); + + void convertNpcData (const ActorData& actorData, ESM::NpcStats& npcStats); +} + +#endif diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 1ad60d7ba..2e7a954e0 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -43,8 +43,15 @@ namespace ESSImport { ESM::Cell cell; std::string id = esm.getHNString("NAME"); + cell.mName = id; cell.load(esm, false); + // note if the player is in a nameless exterior cell, we will assign the cellId later based on player position + if (id == mContext->mPlayerCellName) + { + mContext->mPlayer.mCellId = cell.getCellId(); + } + Cell newcell; newcell.mCell = cell; @@ -55,7 +62,12 @@ namespace ESSImport unsigned char nam8[32]; if (esm.isNextSub("NAM8")) { - esm.getHExact(nam8, 32); + esm.getSubHeader(); + // FIXME: different size in interior cells for some reason + if (esm.getSubSize() == 36) + esm.skip(4); + + esm.getExact(nam8, 32); newcell.mFogOfWar.reserve(16*16); for (int x=0; x<16; ++x) @@ -87,6 +99,8 @@ namespace ESSImport } newcell.mRefs = cellrefs; + + // FIXME: map by ID for exterior cells mCells[id] = newcell; } @@ -127,20 +141,36 @@ namespace ESSImport std::make_pair(refIndex, out.mRefID)); if (crecIt != mContext->mCreatureChanges.end()) { - std::cerr << "Can't' find CREC for " << refIndex << " " << out.mRefID << std::endl; + ESM::CreatureState objstate; + objstate.blank(); + convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats); + objstate.mEnabled = cellref.mEnabled; + objstate.mPosition = cellref.mPos; + objstate.mRef = out; + objstate.mRef.mRefNum = cellref.mRefNum; + esm.writeHNT ("OBJE", ESM::REC_CREA); + objstate.save(esm); + continue; + } + + std::map, NPCC>::const_iterator npccIt = mContext->mNpcChanges.find( + std::make_pair(refIndex, out.mRefID)); + if (npccIt != mContext->mNpcChanges.end()) + { + ESM::NpcState objstate; + objstate.blank(); + convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats); + convertNpcData(cellref.mActorData, objstate.mNpcStats); + objstate.mEnabled = cellref.mEnabled; + objstate.mPosition = cellref.mPos; + objstate.mRef = out; + objstate.mRef.mRefNum = cellref.mRefNum; + esm.writeHNT ("OBJE", ESM::REC_NPC_); + objstate.save(esm); continue; } - ESM::CreatureState objstate; - objstate.mCount = 1; - objstate.mEnabled = cellref.mEnabled; - objstate.mHasLocals = 0; - objstate.mLocalRotation[0] = objstate.mLocalRotation[1] = objstate.mLocalRotation[2] = 0; - objstate.mPosition = cellref.mPos; - objstate.mRef = out; - objstate.mRef.mRefNum = cellref.mRefNum; - esm.writeHNT ("OBJE", ESM::REC_CREA); - objstate.save(esm); + std::cerr << "Can't find type for " << refIndex << " " << out.mRefID << std::endl; } esm.endRecord(ESM::REC_CSTA); diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 71eb3ab9f..7e9166902 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -14,6 +14,9 @@ #include "importercontext.hpp" #include "importcellref.hpp" +#include "convertacdt.hpp" +#include "convertnpcc.hpp" + namespace ESSImport { @@ -151,9 +154,10 @@ public: npcc.load(esm); if (id == "PlayerSaveGame") { - mContext->mPlayer.mObject.mNpcStats.mReputation = npcc.mNPDT.mReputation; + convertNPCC(npcc, mContext->mPlayer.mObject); } - //mContext->mNpcChanges.insert(std::make_pair(std::make_pair(npcc.mIndex,id), crec)); + else + mContext->mNpcChanges.insert(std::make_pair(std::make_pair(npcc.mIndex,id), npcc)); } }; @@ -168,36 +172,10 @@ public: mContext->mPlayer.mObject.mPosition = refr.mPos; ESM::CreatureStats& cStats = mContext->mPlayer.mObject.mCreatureStats; - for (int i=0; i<3; ++i) - { - int writeIndex = translateDynamicIndex(i); - cStats.mDynamic[writeIndex].mBase = refr.mACDT.mDynamic[i][1]; - cStats.mDynamic[writeIndex].mMod = refr.mACDT.mDynamic[i][1]; - cStats.mDynamic[writeIndex].mCurrent = refr.mACDT.mDynamic[i][0]; - } - for (int i=0; i<8; ++i) - { - cStats.mAttributes[i].mBase = refr.mACDT.mAttributes[i][1]; - cStats.mAttributes[i].mMod = refr.mACDT.mAttributes[i][0]; - cStats.mAttributes[i].mCurrent = refr.mACDT.mAttributes[i][0]; - } - ESM::NpcStats& npcStats = mContext->mPlayer.mObject.mNpcStats; - for (int i=0; imPlayer.mObject.mNpcStats; + convertNpcData(refr.mActorData, npcStats); } }; diff --git a/apps/essimporter/convertnpcc.cpp b/apps/essimporter/convertnpcc.cpp new file mode 100644 index 000000000..11e665bfd --- /dev/null +++ b/apps/essimporter/convertnpcc.cpp @@ -0,0 +1,22 @@ +#include "convertnpcc.hpp" + +namespace ESSImport +{ + + void convertNPCC(const NPCC &npcc, ESM::NpcState &npcState) + { + npcState.mNpcStats.mReputation = npcc.mNPDT.mReputation; + + for (std::vector::const_iterator it = npcc.mInventory.begin(); + it != npcc.mInventory.end(); ++it) + { + ESM::ObjectState obj; + obj.blank(); + obj.mRef.mRefID = it->mId; + obj.mRef.mCharge = it->mCondition; + + // Don't know type of object :( change save format? + // npcState.mInventory.mItems.push_back(std::make_pair(obj, std::make_pair(0,0))); + } + } +} diff --git a/apps/essimporter/convertnpcc.hpp b/apps/essimporter/convertnpcc.hpp new file mode 100644 index 000000000..eb12d8f3b --- /dev/null +++ b/apps/essimporter/convertnpcc.hpp @@ -0,0 +1,15 @@ +#ifndef OPENMW_ESSIMPORT_CONVERTNPCC_H +#define OPENMW_ESSIMPORT_CONVERTNPCC_H + +#include "importnpcc.hpp" + +#include + +namespace ESSImport +{ + + void convertNPCC (const NPCC& npcc, ESM::NpcState& npcState); + +} + +#endif diff --git a/apps/essimporter/importacdt.cpp b/apps/essimporter/importacdt.cpp new file mode 100644 index 000000000..b3e399f9f --- /dev/null +++ b/apps/essimporter/importacdt.cpp @@ -0,0 +1,28 @@ +#include "importacdt.hpp" + +#include + +namespace ESSImport +{ + + void ActorData::load(ESM::ESMReader &esm) + { + esm.getHNT(mACDT, "ACDT"); + + ACSC acsc; + esm.getHNOT(acsc, "ACSC"); + esm.getHNOT(acsc, "ACSL"); + + if (esm.isNextSub("CHRD")) // npc only + esm.getHExact(mSkills, 27*2*sizeof(int)); + + if (esm.isNextSub("CRED")) // creature only + esm.getHExact(mCombatStats, 3*2*sizeof(int)); + + mScript = esm.getHNOString("SCRI"); + + if (esm.isNextSub("ND3D")) + esm.skipHSub(); + } + +} diff --git a/apps/essimporter/importacdt.hpp b/apps/essimporter/importacdt.hpp index 1d79f899e..6efae9dc5 100644 --- a/apps/essimporter/importacdt.hpp +++ b/apps/essimporter/importacdt.hpp @@ -1,9 +1,17 @@ #ifndef OPENMW_ESSIMPORT_ACDT_H #define OPENMW_ESSIMPORT_ACDT_H +#include + +namespace ESM +{ + struct ESMReader; +} + namespace ESSImport { + /// Actor data, shared by (at least) REFR and CellRef struct ACDT { @@ -14,6 +22,22 @@ namespace ESSImport unsigned char mUnknown3[120]; }; + struct ActorData + { + ACDT mACDT; + + int mSkills[27][2]; + + // creature combat stats, base and modified + // I think these can be ignored in the conversion, because it is not possible + // to change them ingame + int mCombatStats[3][2]; + + std::string mScript; + + void load(ESM::ESMReader& esm); + }; + /// Unknown, shared by (at least) REFR and CellRef struct ACSC { diff --git a/apps/essimporter/importcellref.cpp b/apps/essimporter/importcellref.cpp index 51e771081..76356769a 100644 --- a/apps/essimporter/importcellref.cpp +++ b/apps/essimporter/importcellref.cpp @@ -16,22 +16,19 @@ namespace ESSImport mIndexedRefId = esm.getHNString("NAME"); - esm.getHNT(mACDT, "ACDT"); + // the following two occur in ESM::CellRef too (Charge and Gold), + // but may have entirely different meanings here + int intv; + esm.getHNOT(intv, "INTV"); + int nam9; + esm.getHNOT(nam9, "NAM9"); - ACSC acsc; - esm.getHNOT(acsc, "ACSC"); - esm.getHNOT(acsc, "ACSL"); - - if (esm.isNextSub("CRED")) - esm.skipHSub(); - - if (esm.isNextSub("ND3D")) - esm.skipHSub(); + mActorData.load(esm); mEnabled = true; esm.getHNOT(mEnabled, "ZNAM"); - esm.getHNOT(mPos, "DATA", 24); + esm.getHNT(mPos, "DATA", 24); } } diff --git a/apps/essimporter/importcellref.hpp b/apps/essimporter/importcellref.hpp index 72c5af257..77763d434 100644 --- a/apps/essimporter/importcellref.hpp +++ b/apps/essimporter/importcellref.hpp @@ -21,10 +21,12 @@ namespace ESSImport std::string mIndexedRefId; ESM::RefNum mRefNum; - ACDT mACDT; + ActorData mActorData; ESM::Position mPos; + std::string mScript; + bool mEnabled; void load(ESM::ESMReader& esm); diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index b511dfe5e..572489d9a 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -185,6 +185,9 @@ namespace ESSImport Context context; + const ESM::Header& header = esm.getHeader(); + context.mPlayerCellName = header.mGameData.mCurrentCell.toString(); + const unsigned int recREFR = ESM::FourCC<'R','E','F','R'>::value; const unsigned int recPCDT = ESM::FourCC<'P','C','D','T'>::value; const unsigned int recFMAP = ESM::FourCC<'F','M','A','P'>::value; @@ -234,8 +237,6 @@ namespace ESSImport } } - const ESM::Header& header = esm.getHeader(); - ESM::ESMWriter writer; writer.setFormat (ESM::Header::CurrentFormat); @@ -247,6 +248,11 @@ namespace ESSImport writer.setAuthor(""); writer.setDescription(""); writer.setRecordCount (0); + + for (std::vector::const_iterator it = header.mMaster.begin(); + it != header.mMaster.end(); ++it) + writer.addMaster (it->name, 0); // not using the size information anyway -> use value of 0 + writer.save (stream); ESM::SavedGame profile; @@ -298,6 +304,15 @@ namespace ESSImport } writer.startRecord(ESM::REC_PLAY); + if (context.mPlayer.mCellId.mPaged) + { + // exterior cell -> determine cell coordinates based on position + const int cellSize = 8192; + int cellX = std::floor(context.mPlayer.mObject.mPosition.pos[0]/cellSize); + int cellY = std::floor(context.mPlayer.mObject.mPosition.pos[1]/cellSize); + context.mPlayer.mCellId.mIndex.mX = cellX; + context.mPlayer.mCellId.mIndex.mY = cellY; + } context.mPlayer.save(writer); writer.endRecord(ESM::REC_PLAY); } diff --git a/apps/essimporter/importercontext.hpp b/apps/essimporter/importercontext.hpp index 6f26e8329..9183e6179 100644 --- a/apps/essimporter/importercontext.hpp +++ b/apps/essimporter/importercontext.hpp @@ -17,6 +17,9 @@ namespace ESSImport struct Context { + // set from the TES3 header + std::string mPlayerCellName; + ESM::Player mPlayer; ESM::NPC mPlayerBase; std::string mCustomPlayerClassName; @@ -38,33 +41,8 @@ namespace ESSImport //mPlayer.mLastKnownExteriorPosition mPlayer.mHasMark = 0; // TODO mPlayer.mCurrentCrimeId = 0; // TODO - mPlayer.mObject.mCount = 1; - mPlayer.mObject.mEnabled = 1; - mPlayer.mObject.mHasLocals = false; + mPlayer.mObject.blank(); mPlayer.mObject.mRef.mRefID = "player"; // REFR.mRefID would be PlayerSaveGame - mPlayer.mObject.mCreatureStats.mHasAiSettings = true; - mPlayer.mObject.mCreatureStats.mDead = false; - mPlayer.mObject.mCreatureStats.mDied = false; - mPlayer.mObject.mCreatureStats.mKnockdown = false; - mPlayer.mObject.mCreatureStats.mKnockdownOneFrame = false; - mPlayer.mObject.mCreatureStats.mKnockdownOverOneFrame = false; - mPlayer.mObject.mCreatureStats.mHitRecovery = false; - mPlayer.mObject.mCreatureStats.mBlock = false; - mPlayer.mObject.mCreatureStats.mMovementFlags = 0; - mPlayer.mObject.mCreatureStats.mAttackStrength = 0.f; - mPlayer.mObject.mCreatureStats.mFallHeight = 0.f; - mPlayer.mObject.mCreatureStats.mRecalcDynamicStats = false; - mPlayer.mObject.mCreatureStats.mDrawState = 0; - mPlayer.mObject.mCreatureStats.mDeathAnimation = 0; - mPlayer.mObject.mNpcStats.mIsWerewolf = false; - mPlayer.mObject.mNpcStats.mTimeToStartDrowning = 20; - mPlayer.mObject.mNpcStats.mLevelProgress = 0; - mPlayer.mObject.mNpcStats.mDisposition = 0; - mPlayer.mObject.mNpcStats.mTimeToStartDrowning = 20; - mPlayer.mObject.mNpcStats.mReputation = 0; - mPlayer.mObject.mNpcStats.mCrimeId = -1; - mPlayer.mObject.mNpcStats.mWerewolfKills = 0; - mPlayer.mObject.mNpcStats.mProfit = 0; } }; diff --git a/apps/essimporter/importnpcc.cpp b/apps/essimporter/importnpcc.cpp index 192fe5da4..4cfc816c9 100644 --- a/apps/essimporter/importnpcc.cpp +++ b/apps/essimporter/importnpcc.cpp @@ -7,12 +7,29 @@ namespace ESSImport void NPCC::load(ESM::ESMReader &esm) { + mIndex = 0; + esm.getHNOT(mIndex, "INDX"); + esm.getHNT(mNPDT, "NPDT"); - // container: - // XIDX - // XHLT - condition - // WIDX - equipping? + while (esm.isNextSub("NPCO")) + { + InventoryItem item; + item.mId = esm.getHString(); + + if (esm.isNextSub("XIDX")) + esm.skipHSub(); + + item.mCondition = -1; + esm.getHNOT(item.mCondition, "XHLT"); + mInventory.push_back(item); + } + + while (esm.isNextSub("WIDX")) + { + // equipping? + esm.skipHSub(); + } } } diff --git a/apps/essimporter/importnpcc.hpp b/apps/essimporter/importnpcc.hpp index 12135850f..d10048fe0 100644 --- a/apps/essimporter/importnpcc.hpp +++ b/apps/essimporter/importnpcc.hpp @@ -1,7 +1,6 @@ #ifndef OPENMW_ESSIMPORT_NPCC_H #define OPENMW_ESSIMPORT_NPCC_H -#include #include namespace ESM @@ -12,7 +11,7 @@ namespace ESM namespace ESSImport { - struct NPCC : public ESM::NPC + struct NPCC { struct NPDT { @@ -21,6 +20,15 @@ namespace ESSImport unsigned char unknown2[5]; } mNPDT; + struct InventoryItem + { + std::string mId; + int mCondition; + }; + std::vector mInventory; + + int mIndex; + void load(ESM::ESMReader &esm); }; diff --git a/apps/essimporter/importplayer.cpp b/apps/essimporter/importplayer.cpp index 81f81e764..f8c78dab0 100644 --- a/apps/essimporter/importplayer.cpp +++ b/apps/essimporter/importplayer.cpp @@ -14,16 +14,7 @@ namespace ESSImport if (esm.isNextSub("STPR")) esm.skipHSub(); // ESS TODO - esm.getHNT(mACDT, "ACDT"); - - ACSC acsc; - esm.getHNOT(acsc, "ACSC"); - esm.getHNOT(acsc, "ACSL"); - - esm.getHNExact(mSkills, 27*2*sizeof(int), "CHRD"); - - if (esm.isNextSub("ND3D")) - esm.skipHSub(); // ESS TODO (1 byte) + mActorData.load(esm); esm.getHNOT(mPos, "DATA", 24); } @@ -45,6 +36,9 @@ namespace ESSImport if (esm.isNextSub("ENAM")) esm.skipHSub(); + if (esm.isNextSub("LNAM")) + esm.skipHSub(); + while (esm.isNextSub("FNAM")) { FNAM fnam; diff --git a/apps/essimporter/importplayer.hpp b/apps/essimporter/importplayer.hpp index 8a0a087a5..2493fcdad 100644 --- a/apps/essimporter/importplayer.hpp +++ b/apps/essimporter/importplayer.hpp @@ -21,15 +21,12 @@ namespace ESSImport /// Player-agnostic player data struct REFR { - ACDT mACDT; + ActorData mActorData; std::string mRefID; ESM::Position mPos; ESM::RefNum mRefNum; - int mSkills[27][2]; - float mAttributes[8][2]; - void load(ESM::ESMReader& esm); }; diff --git a/components/esm/creaturestate.cpp b/components/esm/creaturestate.cpp index 9e9b56102..c2838f78d 100644 --- a/components/esm/creaturestate.cpp +++ b/components/esm/creaturestate.cpp @@ -17,4 +17,10 @@ void ESM::CreatureState::save (ESMWriter &esm, bool inInventory) const mInventory.save (esm); mCreatureStats.save (esm); -} \ No newline at end of file +} + +void ESM::CreatureState::blank() +{ + ObjectState::blank(); + mCreatureStats.blank(); +} diff --git a/components/esm/creaturestate.hpp b/components/esm/creaturestate.hpp index 604c2f3a7..9a3d41daa 100644 --- a/components/esm/creaturestate.hpp +++ b/components/esm/creaturestate.hpp @@ -14,6 +14,9 @@ namespace ESM InventoryState mInventory; CreatureStats mCreatureStats; + /// Initialize to default state + void blank(); + virtual void load (ESMReader &esm); virtual void save (ESMWriter &esm, bool inInventory = false) const; }; diff --git a/components/esm/creaturestats.cpp b/components/esm/creaturestats.cpp index 1fdce703c..a1ef7eb0e 100644 --- a/components/esm/creaturestats.cpp +++ b/components/esm/creaturestats.cpp @@ -218,6 +218,38 @@ void ESM::CreatureStats::save (ESMWriter &esm) const } esm.writeHNT("AISE", mHasAiSettings); - for (int i=0; i<4; ++i) - mAiSettings[i].save(esm); + if (mHasAiSettings) + { + for (int i=0; i<4; ++i) + mAiSettings[i].save(esm); + } +} + +void ESM::CreatureStats::blank() +{ + mTradeTime.mHour = 0; + mTradeTime.mDay = 0; + mGoldPool = 0; + mActorId = 0; + mHasAiSettings = false; + mDead = false; + mDied = false; + mMurdered = false; + mFriendlyHits = 0; + mTalkedTo = false; + mAlarmed = false; + mAttacked = false; + mAttackingOrSpell = false; + mKnockdown = false; + mKnockdownOneFrame = false; + mKnockdownOverOneFrame = false; + mHitRecovery = false; + mBlock = false; + mMovementFlags = 0; + mAttackStrength = 0.f; + mFallHeight = 0.f; + mRecalcDynamicStats = false; + mDrawState = 0; + mDeathAnimation = 0; + mLevel = 1; } diff --git a/components/esm/creaturestats.hpp b/components/esm/creaturestats.hpp index 680577f93..91ee98333 100644 --- a/components/esm/creaturestats.hpp +++ b/components/esm/creaturestats.hpp @@ -66,6 +66,9 @@ namespace ESM SpellState mSpells; ActiveSpells mActiveSpells; + /// Initialize to default state + void blank(); + void load (ESMReader &esm); void save (ESMWriter &esm) const; }; diff --git a/components/esm/npcstate.cpp b/components/esm/npcstate.cpp index e59ec3e26..6134193c2 100644 --- a/components/esm/npcstate.cpp +++ b/components/esm/npcstate.cpp @@ -21,4 +21,11 @@ void ESM::NpcState::save (ESMWriter &esm, bool inInventory) const mNpcStats.save (esm); mCreatureStats.save (esm); -} \ No newline at end of file +} + +void ESM::NpcState::blank() +{ + ObjectState::blank(); + mNpcStats.blank(); + mCreatureStats.blank(); +} diff --git a/components/esm/npcstate.hpp b/components/esm/npcstate.hpp index 39858d553..b90cd85e6 100644 --- a/components/esm/npcstate.hpp +++ b/components/esm/npcstate.hpp @@ -16,6 +16,9 @@ namespace ESM NpcStats mNpcStats; CreatureStats mCreatureStats; + /// Initialize to default state + void blank(); + virtual void load (ESMReader &esm); virtual void save (ESMWriter &esm, bool inInventory = false) const; }; diff --git a/components/esm/npcstats.cpp b/components/esm/npcstats.cpp index 4ba0ce7e3..e305ddab0 100644 --- a/components/esm/npcstats.cpp +++ b/components/esm/npcstats.cpp @@ -150,3 +150,18 @@ void ESM::NpcStats::save (ESMWriter &esm) const if (mCrimeId != -1) esm.writeHNT ("CRID", mCrimeId); } + +void ESM::NpcStats::blank() +{ + mIsWerewolf = false; + mDisposition = 0; + mBounty = 0; + mReputation = 0; + mWerewolfKills = 0; + mProfit = 0; + mLevelProgress = 0; + for (int i=0; i<8; ++i) + mSkillIncrease[i] = 0; + mTimeToStartDrowning = 20; + mCrimeId = -1; +} diff --git a/components/esm/npcstats.hpp b/components/esm/npcstats.hpp index f6e9c1e58..a8ec4cf44 100644 --- a/components/esm/npcstats.hpp +++ b/components/esm/npcstats.hpp @@ -47,6 +47,9 @@ namespace ESM float mTimeToStartDrowning; int mCrimeId; + /// Initialize to default state + void blank(); + void load (ESMReader &esm); void save (ESMWriter &esm) const; }; diff --git a/components/esm/objectstate.cpp b/components/esm/objectstate.cpp index be00f3ef6..f7755f8cb 100644 --- a/components/esm/objectstate.cpp +++ b/components/esm/objectstate.cpp @@ -48,4 +48,18 @@ void ESM::ObjectState::save (ESMWriter &esm, bool inInventory) const } } -ESM::ObjectState::~ObjectState() {} \ No newline at end of file +void ESM::ObjectState::blank() +{ + mRef.blank(); + mHasLocals = 0; + mEnabled = false; + mCount = 1; + for (int i=0;i<3;++i) + { + mPosition.pos[i] = 0; + mPosition.rot[i] = 0; + mLocalRotation[i] = 0; + } +} + +ESM::ObjectState::~ObjectState() {} diff --git a/components/esm/objectstate.hpp b/components/esm/objectstate.hpp index 9c9ca5f2e..5b05e0949 100644 --- a/components/esm/objectstate.hpp +++ b/components/esm/objectstate.hpp @@ -29,8 +29,11 @@ namespace ESM virtual void load (ESMReader &esm); virtual void save (ESMWriter &esm, bool inInventory = false) const; + /// Initialize to default state + void blank(); + virtual ~ObjectState(); }; } -#endif \ No newline at end of file +#endif From 19ed047dec4763362556141e876b12945a4894b6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 18 Jan 2015 22:52:11 +0100 Subject: [PATCH 233/740] ESSImport: add some subrecords to CellRef and others, most files should load now, importacdt/cellref class structure need some refactoring --- apps/essimporter/CMakeLists.txt | 1 + apps/essimporter/converter.cpp | 34 +++++++++++-- apps/essimporter/converter.hpp | 16 ++++--- apps/essimporter/convertnpcc.cpp | 12 ----- apps/essimporter/importacdt.cpp | 71 +++++++++++++++++++++++++++- apps/essimporter/importcellref.cpp | 24 ++++++---- apps/essimporter/importcrec.cpp | 7 +++ apps/essimporter/importcrec.hpp | 4 ++ apps/essimporter/importinventory.cpp | 46 ++++++++++++++++++ apps/essimporter/importinventory.hpp | 31 ++++++++++++ apps/essimporter/importnpcc.cpp | 24 +++------- apps/essimporter/importnpcc.hpp | 11 ++--- apps/essimporter/importplayer.cpp | 28 +++++++++-- apps/essimporter/importplayer.hpp | 2 + components/esm/cellref.cpp | 5 ++ components/esm/cellref.hpp | 3 ++ 16 files changed, 261 insertions(+), 58 deletions(-) create mode 100644 apps/essimporter/importinventory.cpp create mode 100644 apps/essimporter/importinventory.hpp diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index 257a466ee..3d3e0860c 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -6,6 +6,7 @@ set(ESSIMPORTER_FILES importcrec.cpp importcellref.cpp importacdt.cpp + importinventory.cpp importercontext.cpp converter.cpp convertacdt.cpp diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 2e7a954e0..c51e91ed7 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -60,12 +60,17 @@ namespace ESSImport // TODO: add bleeding of FOW into neighbouring cells (openmw handles this by writing to the textures, // MW handles it when rendering only) unsigned char nam8[32]; - if (esm.isNextSub("NAM8")) + // exterior has 1 NAM8, interior can have multiple ones, and have an extra 4 byte flag at the start + // (probably offset of that specific fog texture?) + while (esm.isNextSub("NAM8")) { esm.getSubHeader(); - // FIXME: different size in interior cells for some reason + if (esm.getSubSize() == 36) + { + // flag on interiors esm.skip(4); + } esm.getExact(nam8, 32); @@ -82,10 +87,24 @@ namespace ESSImport } } - std::ostringstream filename; - filename << "fog_" << cell.mData.mX << "_" << cell.mData.mY << ".tga"; + if (cell.isExterior()) + { + std::ostringstream filename; + filename << "fog_" << cell.mData.mX << "_" << cell.mData.mY << ".tga"; + + convertImage((char*)&newcell.mFogOfWar[0], newcell.mFogOfWar.size()*4, 16, 16, Ogre::PF_BYTE_RGBA, filename.str()); + } + } - convertImage((char*)&newcell.mFogOfWar[0], newcell.mFogOfWar.size()*4, 16, 16, Ogre::PF_BYTE_RGBA, filename.str()); + // moved reference, not handled yet + // NOTE: MVRF can also occur in within normal references (importcellref.cpp)? + // this does not match the ESM file implementation, + // verify if that can happen with ESM files too + while (esm.isNextSub("MVRF")) + { + esm.skipHSub(); // skip MVRF + esm.getSubName(); + esm.skipHSub(); // skip CNDT } std::vector cellrefs; @@ -94,7 +113,11 @@ namespace ESSImport CellRef ref; ref.load (esm); if (esm.isNextSub("DELE")) + { + // strangely this can be e.g. 52 instead of just 1, std::cout << "deleted ref " << ref.mIndexedRefId << std::endl; + esm.skipHSub(); + } cellrefs.push_back(ref); } @@ -148,6 +171,7 @@ namespace ESSImport objstate.mPosition = cellref.mPos; objstate.mRef = out; objstate.mRef.mRefNum = cellref.mRefNum; + // FIXME: change save format to not require object type, instead look up it up using the RefId esm.writeHNT ("OBJE", ESM::REC_CREA); objstate.save(esm); continue; diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 7e9166902..3f8b4cbbe 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -83,13 +83,17 @@ public: // this is always the player ESM::NPC npc; std::string id = esm.getHNString("NAME"); - assert (id == "player"); npc.load(esm); - mContext->mPlayer.mObject.mCreatureStats.mLevel = npc.mNpdt52.mLevel; - mContext->mPlayerBase = npc; - std::map empty; - for (std::vector::const_iterator it = npc.mSpells.mList.begin(); it != npc.mSpells.mList.end(); ++it) - mContext->mPlayer.mObject.mCreatureStats.mSpells.mSpells[*it] = empty; + if (id != "player") // seems to occur sometimes, with "chargen X" names + std::cerr << "non-player NPC record: " << id << std::endl; + else + { + mContext->mPlayer.mObject.mCreatureStats.mLevel = npc.mNpdt52.mLevel; + mContext->mPlayerBase = npc; + std::map empty; + for (std::vector::const_iterator it = npc.mSpells.mList.begin(); it != npc.mSpells.mList.end(); ++it) + mContext->mPlayer.mObject.mCreatureStats.mSpells.mSpells[*it] = empty; + } } }; diff --git a/apps/essimporter/convertnpcc.cpp b/apps/essimporter/convertnpcc.cpp index 11e665bfd..fdf96c15a 100644 --- a/apps/essimporter/convertnpcc.cpp +++ b/apps/essimporter/convertnpcc.cpp @@ -6,17 +6,5 @@ namespace ESSImport void convertNPCC(const NPCC &npcc, ESM::NpcState &npcState) { npcState.mNpcStats.mReputation = npcc.mNPDT.mReputation; - - for (std::vector::const_iterator it = npcc.mInventory.begin(); - it != npcc.mInventory.end(); ++it) - { - ESM::ObjectState obj; - obj.blank(); - obj.mRef.mRefID = it->mId; - obj.mRef.mCharge = it->mCondition; - - // Don't know type of object :( change save format? - // npcState.mInventory.mItems.push_back(std::make_pair(obj, std::make_pair(0,0))); - } } } diff --git a/apps/essimporter/importacdt.cpp b/apps/essimporter/importacdt.cpp index b3e399f9f..5bec5bd82 100644 --- a/apps/essimporter/importacdt.cpp +++ b/apps/essimporter/importacdt.cpp @@ -2,17 +2,73 @@ #include +#include + namespace ESSImport { void ActorData::load(ESM::ESMReader &esm) { - esm.getHNT(mACDT, "ACDT"); + // unsure at which point between NAME and ESM::CellRef + if (esm.isNextSub("MNAM")) + esm.skipHSub(); + + if (esm.isNextSub("ACTN")) + esm.skipHSub(); + + if (esm.isNextSub("STPR")) + esm.skipHSub(); + + ESM::CellRef bla; + bla.ESM::CellRef::loadData(esm); + + // FIXME: actually should be required for all actors?, but ActorData is currently in base CellRef + esm.getHNOT(mACDT, "ACDT"); ACSC acsc; esm.getHNOT(acsc, "ACSC"); esm.getHNOT(acsc, "ACSL"); + if (esm.isNextSub("CSTN")) + esm.skipHSub(); // "PlayerSaveGame", link to some object? + + if (esm.isNextSub("LSTN")) + esm.skipHSub(); // "PlayerSaveGame", link to some object? + + // unsure at which point between LSTN and TGTN + if (esm.isNextSub("CSHN")) + esm.skipHSub(); // "PlayerSaveGame", link to some object? + + // unsure if before or after CSTN/LSTN + if (esm.isNextSub("LSHN")) + esm.skipHSub(); // "PlayerSaveGame", link to some object? + + while (esm.isNextSub("TGTN")) + esm.skipHSub(); // "PlayerSaveGame", link to some object? + + while (esm.isNextSub("FGTN")) + esm.getHString(); // fight target? + + // unsure at which point between FGTN and CHRD + if (esm.isNextSub("PWPC")) + esm.skipHSub(); + if (esm.isNextSub("PWPS")) + esm.skipHSub(); + + if (esm.isNextSub("WNAM")) + { + esm.skipHSub(); // seen values: "ancestor guardian", "bound dagger_en". Summoned creature / bound weapons? + + if (esm.isNextSub("XNAM")) + { + // "demon tanto", probably the ID of spell/item that created the bound weapon/crature? + esm.skipHSub(); + } + + if (esm.isNextSub("YNAM")) + esm.skipHSub(); // 4 byte, 0 + } + if (esm.isNextSub("CHRD")) // npc only esm.getHExact(mSkills, 27*2*sizeof(int)); @@ -21,8 +77,21 @@ namespace ESSImport mScript = esm.getHNOString("SCRI"); + // script variables? + if (!mScript.empty()) + { + if (esm.isNextSub("SLCS")) + esm.skipHSub(); + if (esm.isNextSub("SLSD")) // Short Data? + esm.skipHSub(); + if (esm.isNextSub("SLFD")) // Float Data? + esm.skipHSub(); + } + if (esm.isNextSub("ND3D")) esm.skipHSub(); + if (esm.isNextSub("ANIS")) + esm.skipHSub(); } } diff --git a/apps/essimporter/importcellref.cpp b/apps/essimporter/importcellref.cpp index 76356769a..454690adc 100644 --- a/apps/essimporter/importcellref.cpp +++ b/apps/essimporter/importcellref.cpp @@ -7,7 +7,7 @@ namespace ESSImport void CellRef::load(ESM::ESMReader &esm) { - esm.getHNT(mRefNum.mIndex, "FRMR"); // TODO: adjust RefNum + esm.getHNT(mRefNum.mIndex, "FRMR"); // this is required since openmw supports more than 255 content files int pluginIndex = (mRefNum.mIndex & 0xff000000) >> 24; @@ -16,19 +16,27 @@ namespace ESSImport mIndexedRefId = esm.getHNString("NAME"); - // the following two occur in ESM::CellRef too (Charge and Gold), - // but may have entirely different meanings here - int intv; - esm.getHNOT(intv, "INTV"); - int nam9; - esm.getHNOT(nam9, "NAM9"); + if (esm.isNextSub("LVCR")) + esm.skipHSub(); mActorData.load(esm); mEnabled = true; esm.getHNOT(mEnabled, "ZNAM"); - esm.getHNT(mPos, "DATA", 24); + // should occur for all references but not levelled creature spawners + esm.getHNOT(mPos, "DATA", 24); + + // i've seen DATA record TWICE on a creature record - and with the exact same content too! weird + // alarmvoi0000.ess + esm.getHNOT(mPos, "DATA", 24); + + if (esm.isNextSub("MVRF")) + { + esm.skipHSub(); + esm.getSubName(); + esm.skipHSub(); + } } } diff --git a/apps/essimporter/importcrec.cpp b/apps/essimporter/importcrec.cpp index c770b2386..9cf455588 100644 --- a/apps/essimporter/importcrec.cpp +++ b/apps/essimporter/importcrec.cpp @@ -8,6 +8,13 @@ namespace ESSImport void CREC::load(ESM::ESMReader &esm) { esm.getHNT(mIndex, "INDX"); + + // equivalent of ESM::Creature XSCL? probably don't have to convert this, + // since the value can't be changed + float scale; + esm.getHNOT(scale, "XSCL"); + + mInventory.load(esm); } } diff --git a/apps/essimporter/importcrec.hpp b/apps/essimporter/importcrec.hpp index 62881c582..16b752807 100644 --- a/apps/essimporter/importcrec.hpp +++ b/apps/essimporter/importcrec.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_ESSIMPORT_CREC_H #define OPENMW_ESSIMPORT_CREC_H +#include "importinventory.hpp" + namespace ESM { class ESMReader; @@ -14,6 +16,8 @@ namespace ESSImport { int mIndex; + Inventory mInventory; + void load(ESM::ESMReader& esm); }; diff --git a/apps/essimporter/importinventory.cpp b/apps/essimporter/importinventory.cpp new file mode 100644 index 000000000..d132fd76d --- /dev/null +++ b/apps/essimporter/importinventory.cpp @@ -0,0 +1,46 @@ +#include "importinventory.hpp" + +#include + +namespace ESSImport +{ + + void Inventory::load(ESM::ESMReader &esm) + { + while (esm.isNextSub("NPCO")) + { + InventoryItem item; + item.mId = esm.getHString(); + + if (esm.isNextSub("XIDX")) + esm.skipHSub(); + + std::string script = esm.getHNOString("SCRI"); + // script variables? + // unsure if before or after ESM::CellRef + if (!script.empty()) + { + if (esm.isNextSub("SLCS")) + esm.skipHSub(); + if (esm.isNextSub("SLSD")) // Short Data? + esm.skipHSub(); + if (esm.isNextSub("SLFD")) // Float Data? + esm.skipHSub(); + } + + // for XSOL and XCHG seen so far, but probably others too + item.ESM::CellRef::loadData(esm); + + item.mCondition = -1; + esm.getHNOT(item.mCondition, "XHLT"); + mItems.push_back(item); + } + + while (esm.isNextSub("WIDX")) + { + // equipping? + esm.skipHSub(); + } + } + +} diff --git a/apps/essimporter/importinventory.hpp b/apps/essimporter/importinventory.hpp new file mode 100644 index 000000000..e31cab76a --- /dev/null +++ b/apps/essimporter/importinventory.hpp @@ -0,0 +1,31 @@ +#ifndef OPENMW_ESSIMPORT_IMPORTINVENTORY_H +#define OPENMW_ESSIMPORT_IMPORTINVENTORY_H + +#include +#include + +#include + +namespace ESM +{ + class ESMReader; +} + +namespace ESSImport +{ + + struct Inventory + { + struct InventoryItem : public ESM::CellRef + { + std::string mId; + int mCondition; + }; + std::vector mItems; + + void load(ESM::ESMReader& esm); + }; + +} + +#endif diff --git a/apps/essimporter/importnpcc.cpp b/apps/essimporter/importnpcc.cpp index 4cfc816c9..8400a9e4a 100644 --- a/apps/essimporter/importnpcc.cpp +++ b/apps/essimporter/importnpcc.cpp @@ -12,24 +12,14 @@ namespace ESSImport esm.getHNT(mNPDT, "NPDT"); - while (esm.isNextSub("NPCO")) - { - InventoryItem item; - item.mId = esm.getHString(); - - if (esm.isNextSub("XIDX")) - esm.skipHSub(); - - item.mCondition = -1; - esm.getHNOT(item.mCondition, "XHLT"); - mInventory.push_back(item); - } - - while (esm.isNextSub("WIDX")) - { - // equipping? + if (esm.isNextSub("AI_E")) esm.skipHSub(); - } + if (esm.isNextSub("AI_T")) + esm.skipHSub(); + if (esm.isNextSub("AI_F")) + esm.skipHSub(); + + mInventory.load(esm); } } diff --git a/apps/essimporter/importnpcc.hpp b/apps/essimporter/importnpcc.hpp index d10048fe0..f3c4e24c7 100644 --- a/apps/essimporter/importnpcc.hpp +++ b/apps/essimporter/importnpcc.hpp @@ -3,6 +3,10 @@ #include +#include + +#include "importinventory.hpp" + namespace ESM { class ESMReader; @@ -20,12 +24,7 @@ namespace ESSImport unsigned char unknown2[5]; } mNPDT; - struct InventoryItem - { - std::string mId; - int mCondition; - }; - std::vector mInventory; + Inventory mInventory; int mIndex; diff --git a/apps/essimporter/importplayer.cpp b/apps/essimporter/importplayer.cpp index f8c78dab0..8a57ae588 100644 --- a/apps/essimporter/importplayer.cpp +++ b/apps/essimporter/importplayer.cpp @@ -11,9 +11,6 @@ namespace ESSImport mRefID = esm.getHNString("NAME"); - if (esm.isNextSub("STPR")) - esm.skipHSub(); // ESS TODO - mActorData.load(esm); esm.getHNOT(mPos, "DATA", 24); @@ -21,6 +18,12 @@ namespace ESSImport void PCDT::load(ESM::ESMReader &esm) { + while (esm.isNextSub("DNAM")) + { + // TODO: deal with encoding? + mKnownDialogueTopics.push_back(esm.getHString()); + } + if (esm.isNextSub("PNAM")) esm.skipHSub(); if (esm.isNextSub("SNAM")) @@ -33,6 +36,17 @@ namespace ESSImport mBirthsign = esm.getHNOString("BNAM"); + // Holds the names of the last used Alchemy apparatus. Don't need to import this ATM, + // because our GUI auto-selects the best apparatus. + if (esm.isNextSub("NAM0")) + esm.skipHSub(); + if (esm.isNextSub("NAM1")) + esm.skipHSub(); + if (esm.isNextSub("NAM2")) + esm.skipHSub(); + if (esm.isNextSub("NAM3")) + esm.skipHSub(); + if (esm.isNextSub("ENAM")) esm.skipHSub(); @@ -48,6 +62,14 @@ namespace ESSImport if (esm.isNextSub("KNAM")) esm.skipHSub(); + + if (esm.isNextSub("WERE")) + { + // some werewolf data, 152 bytes + // maybe current skills and attributes for werewolf form + esm.getSubHeader(); + esm.skip(152); + } } } diff --git a/apps/essimporter/importplayer.hpp b/apps/essimporter/importplayer.hpp index 2493fcdad..af8625fa6 100644 --- a/apps/essimporter/importplayer.hpp +++ b/apps/essimporter/importplayer.hpp @@ -36,6 +36,8 @@ struct PCDT int mBounty; std::string mBirthsign; + std::vector mKnownDialogueTopics; + struct FNAM { unsigned char mRank; diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index f93fe1535..43b1f4d29 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -20,6 +20,11 @@ void ESM::CellRef::load (ESMReader& esm, bool wideRefNum) mRefID = esm.getHNString ("NAME"); + loadData(esm); +} + +void ESM::CellRef::loadData(ESMReader &esm) +{ // Again, UNAM sometimes appears after NAME and sometimes later. // Or perhaps this UNAM means something different? mReferenceBlocked = -1; diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index f3986ccf3..b7b00a654 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -91,6 +91,9 @@ namespace ESM void load (ESMReader& esm, bool wideRefNum = false); + /// Implicitly called by load + void loadData (ESMReader& esm); + void save (ESMWriter &esm, bool wideRefNum = false, bool inInventory = false) const; void blank(); From f9cf31fcd5319dca02dddf89dead998cff3e9955 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 19 Jan 2015 00:35:19 +0100 Subject: [PATCH 234/740] ESSImport: convert custom map markers, not working for interiors yet --- apps/essimporter/converter.cpp | 39 +++++++++++++++++++++++++- apps/essimporter/converter.hpp | 3 ++ apps/essimporter/importacdt.cpp | 7 +++++ apps/essimporter/importcellref.cpp | 3 +- apps/essimporter/importer.cpp | 5 +++- apps/openmw/mwgui/mapwindow.cpp | 39 +++++++------------------- apps/openmw/mwgui/mapwindow.hpp | 34 ++++++---------------- apps/openmw/mwgui/windowmanagerimp.cpp | 4 +-- components/CMakeLists.txt | 2 +- components/esm/custommarkerstate.cpp | 26 +++++++++++++++++ components/esm/custommarkerstate.hpp | 30 ++++++++++++++++++++ 11 files changed, 132 insertions(+), 60 deletions(-) create mode 100644 components/esm/custommarkerstate.cpp create mode 100644 components/esm/custommarkerstate.hpp diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index c51e91ed7..ce3cea675 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -108,7 +108,7 @@ namespace ESSImport } std::vector cellrefs; - while (esm.hasMoreSubs()) + while (esm.hasMoreSubs() && esm.isNextSub("FRMR")) { CellRef ref; ref.load (esm); @@ -121,6 +121,36 @@ namespace ESSImport cellrefs.push_back(ref); } + while (esm.isNextSub("MPCD")) + { + float notepos[3]; + esm.getHT(notepos, 3*sizeof(float)); + + // Markers seem to be arranged in a 32*32 grid, notepos has grid-indices. + // This seems to be the reason markers can't be placed everywhere in interior cells, + // i.e. when the grid is exceeded. + // Converting the interior markers correctly could be rather tricky, but is probably similar logic + // as used for the FoW texture placement, which we need to figure out anyway + notepos[1] += 31.f; + notepos[0] += 0.5; + notepos[1] += 0.5; + notepos[0] = 8192 * notepos[0] / 32.f; + notepos[1] = 8192 * notepos[1] / 32.f; + if (cell.isExterior()) + { + notepos[0] += 8192 * cell.mData.mX; + notepos[1] += 8192 * cell.mData.mY; + } + // TODO: what encoding is this in? + std::string note = esm.getHNString("MPNT"); + ESM::CustomMarker marker; + marker.mWorldX = notepos[0]; + marker.mWorldY = notepos[1]; + marker.mNote = note; + marker.mCell = cell.getCellId(); + mMarkers.push_back(marker); + } + newcell.mRefs = cellrefs; // FIXME: map by ID for exterior cells @@ -199,6 +229,13 @@ namespace ESSImport esm.endRecord(ESM::REC_CSTA); } + + for (std::vector::const_iterator it = mMarkers.begin(); it != mMarkers.end(); ++it) + { + esm.startRecord(ESM::REC_MARK); + it->save(esm); + esm.endRecord(ESM::REC_MARK); + } } } diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 3f8b4cbbe..5f1961717 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -9,6 +9,8 @@ #include #include #include +#include + #include "importcrec.hpp" #include "importercontext.hpp" @@ -240,6 +242,7 @@ private: std::map mCells; + std::vector mMarkers; }; } diff --git a/apps/essimporter/importacdt.cpp b/apps/essimporter/importacdt.cpp index 5bec5bd82..d961720a7 100644 --- a/apps/essimporter/importacdt.cpp +++ b/apps/essimporter/importacdt.cpp @@ -49,6 +49,13 @@ namespace ESSImport while (esm.isNextSub("FGTN")) esm.getHString(); // fight target? + // unsure at which point between TGTN and CRED + if (esm.isNextSub("AADT")) + { + // occured when a creature was in the middle of its attack, 44 bytes + esm.skipHSub(); + } + // unsure at which point between FGTN and CHRD if (esm.isNextSub("PWPC")) esm.skipHSub(); diff --git a/apps/essimporter/importcellref.cpp b/apps/essimporter/importcellref.cpp index 454690adc..8c2b8f36d 100644 --- a/apps/essimporter/importcellref.cpp +++ b/apps/essimporter/importcellref.cpp @@ -7,7 +7,8 @@ namespace ESSImport void CellRef::load(ESM::ESMReader &esm) { - esm.getHNT(mRefNum.mIndex, "FRMR"); + // (FRMR subrecord name is already read by the loop in ConvertCell) + esm.getHT(mRefNum.mIndex); // FRMR // this is required since openmw supports more than 255 content files int pluginIndex = (mRefNum.mIndex & 0xff000000) >> 24; diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 572489d9a..12136cdea 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -213,6 +213,7 @@ namespace ESSImport converters[ESM::REC_LEVC] = boost::shared_ptr(new DefaultConverter()); converters[ESM::REC_LEVI] = boost::shared_ptr(new DefaultConverter()); + std::set unknownRecords; for (std::map >::const_iterator it = converters.begin(); it != converters.end(); ++it) @@ -232,7 +233,9 @@ namespace ESSImport } else { - std::cerr << "unknown record " << n.toString() << std::endl; + if (unknownRecords.insert(n.val).second) + std::cerr << "unknown record " << n.toString() << std::endl; + esm.skipRecord(); } } diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 4de9af108..abd1256d7 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -86,35 +86,16 @@ namespace namespace MWGui { - void CustomMarker::save(ESM::ESMWriter &esm) const - { - esm.writeHNT("POSX", mWorldX); - esm.writeHNT("POSY", mWorldY); - mCell.save(esm); - if (!mNote.empty()) - esm.writeHNString("NOTE", mNote); - } - - void CustomMarker::load(ESM::ESMReader &esm) - { - esm.getHNT(mWorldX, "POSX"); - esm.getHNT(mWorldY, "POSY"); - mCell.load(esm); - mNote = esm.getHNOString("NOTE"); - } - - // ------------------------------------------------------ - - void CustomMarkerCollection::addMarker(const CustomMarker &marker, bool triggerEvent) + void CustomMarkerCollection::addMarker(const ESM::CustomMarker &marker, bool triggerEvent) { mMarkers.push_back(marker); if (triggerEvent) eventMarkersChanged(); } - void CustomMarkerCollection::deleteMarker(const CustomMarker &marker) + void CustomMarkerCollection::deleteMarker(const ESM::CustomMarker &marker) { - std::vector::iterator it = std::find(mMarkers.begin(), mMarkers.end(), marker); + std::vector::iterator it = std::find(mMarkers.begin(), mMarkers.end(), marker); if (it != mMarkers.end()) mMarkers.erase(it); else @@ -123,9 +104,9 @@ namespace MWGui eventMarkersChanged(); } - void CustomMarkerCollection::updateMarker(const CustomMarker &marker, const std::string &newNote) + void CustomMarkerCollection::updateMarker(const ESM::CustomMarker &marker, const std::string &newNote) { - std::vector::iterator it = std::find(mMarkers.begin(), mMarkers.end(), marker); + std::vector::iterator it = std::find(mMarkers.begin(), mMarkers.end(), marker); if (it != mMarkers.end()) it->mNote = newNote; else @@ -140,12 +121,12 @@ namespace MWGui eventMarkersChanged(); } - std::vector::const_iterator CustomMarkerCollection::begin() const + std::vector::const_iterator CustomMarkerCollection::begin() const { return mMarkers.begin(); } - std::vector::const_iterator CustomMarkerCollection::end() const + std::vector::const_iterator CustomMarkerCollection::end() const { return mMarkers.end(); } @@ -295,9 +276,9 @@ namespace MWGui MyGUI::Gui::getInstance().destroyWidget(*it); mCustomMarkerWidgets.clear(); - for (std::vector::const_iterator it = mCustomMarkers.begin(); it != mCustomMarkers.end(); ++it) + for (std::vector::const_iterator it = mCustomMarkers.begin(); it != mCustomMarkers.end(); ++it) { - const CustomMarker& marker = *it; + const ESM::CustomMarker& marker = *it; if (marker.mCell.mPaged != !mInterior) continue; @@ -654,7 +635,7 @@ namespace MWGui void MapWindow::onCustomMarkerDoubleClicked(MyGUI::Widget *sender) { - mEditingMarker = *sender->getUserData(); + mEditingMarker = *sender->getUserData(); mEditNoteDialog.setText(mEditingMarker.mNote); mEditNoteDialog.showDeleteButton(true); mEditNoteDialog.setVisible(true); diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 118fee0f6..684069467 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -7,6 +7,8 @@ #include +#include + namespace MWRender { class GlobalMap; @@ -26,43 +28,25 @@ namespace Loading namespace MWGui { - struct CustomMarker - { - float mWorldX; - float mWorldY; - - ESM::CellId mCell; - - std::string mNote; - - bool operator == (const CustomMarker& other) - { - return mNote == other.mNote && mCell == other.mCell && mWorldX == other.mWorldX && mWorldY == other.mWorldY; - } - - void load (ESM::ESMReader& reader); - void save (ESM::ESMWriter& writer) const; - }; - class CustomMarkerCollection { public: - void addMarker(const CustomMarker& marker, bool triggerEvent=true); - void deleteMarker (const CustomMarker& marker); - void updateMarker(const CustomMarker& marker, const std::string& newNote); + void addMarker(const ESM::CustomMarker& marker, bool triggerEvent=true); + void deleteMarker (const ESM::CustomMarker& marker); + void updateMarker(const ESM::CustomMarker& marker, const std::string& newNote); void clear(); size_t size() const; - std::vector::const_iterator begin() const; - std::vector::const_iterator end() const; + std::vector::const_iterator begin() const; + std::vector::const_iterator end() const; typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; EventHandle_Void eventMarkersChanged; private: - std::vector mMarkers; + std::vector mMarkers; }; class LocalMapBase @@ -233,7 +217,7 @@ namespace MWGui MWRender::GlobalMap* mGlobalMapRender; EditNoteDialog mEditNoteDialog; - CustomMarker mEditingMarker; + ESM::CustomMarker mEditingMarker; virtual void onPinToggled(); virtual void onTitleDoubleClicked(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index d5a71bc77..5b2bbee90 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1612,7 +1612,7 @@ namespace MWGui writer.endRecord(ESM::REC_ASPL); } - for (std::vector::const_iterator it = mCustomMarkers.begin(); it != mCustomMarkers.end(); ++it) + for (std::vector::const_iterator it = mCustomMarkers.begin(); it != mCustomMarkers.end(); ++it) { writer.startRecord(ESM::REC_MARK); (*it).save(writer); @@ -1633,7 +1633,7 @@ namespace MWGui } else if (type == ESM::REC_MARK) { - CustomMarker marker; + ESM::CustomMarker marker; marker.load(reader); mCustomMarkers.addMarker(marker, false); } diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a3e79758f..0578a44b0 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -63,7 +63,7 @@ add_component_dir (esm loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap lightstate inventorystate containerstate npcstate creaturestate dialoguestate statstate npcstats creaturestats weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate debugprofile - aisequence magiceffects util + aisequence magiceffects util custommarkerstate ) add_component_dir (esmterrain diff --git a/components/esm/custommarkerstate.cpp b/components/esm/custommarkerstate.cpp new file mode 100644 index 000000000..dc81c123d --- /dev/null +++ b/components/esm/custommarkerstate.cpp @@ -0,0 +1,26 @@ +#include "custommarkerstate.hpp" + +#include "esmwriter.hpp" +#include "esmreader.hpp" + +namespace ESM +{ + +void CustomMarker::save(ESM::ESMWriter &esm) const +{ + esm.writeHNT("POSX", mWorldX); + esm.writeHNT("POSY", mWorldY); + mCell.save(esm); + if (!mNote.empty()) + esm.writeHNString("NOTE", mNote); +} + +void CustomMarker::load(ESM::ESMReader &esm) +{ + esm.getHNT(mWorldX, "POSX"); + esm.getHNT(mWorldY, "POSY"); + mCell.load(esm); + mNote = esm.getHNOString("NOTE"); +} + +} diff --git a/components/esm/custommarkerstate.hpp b/components/esm/custommarkerstate.hpp new file mode 100644 index 000000000..fc9286bfe --- /dev/null +++ b/components/esm/custommarkerstate.hpp @@ -0,0 +1,30 @@ +#ifndef OPENMW_ESM_CUSTOMMARKERSTATE_H +#define OPENMW_ESM_CUSTOMMARKERSTATE_H + +#include "cellid.hpp" + +namespace ESM +{ + +// format 0, saved games only +struct CustomMarker +{ + float mWorldX; + float mWorldY; + + ESM::CellId mCell; + + std::string mNote; + + bool operator == (const CustomMarker& other) + { + return mNote == other.mNote && mCell == other.mCell && mWorldX == other.mWorldX && mWorldY == other.mWorldY; + } + + void load (ESM::ESMReader& reader); + void save (ESM::ESMWriter& writer) const; +}; + +} + +#endif From ad398f0c65d2df8299d22bdb7182c5deb89e71ca Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 19 Jan 2015 01:06:45 +0100 Subject: [PATCH 235/740] ESSImport: convert kill counter --- apps/essimporter/CMakeLists.txt | 1 + apps/essimporter/converter.hpp | 29 +++++++++++++++++++++++++++++ apps/essimporter/importer.cpp | 5 ++++- apps/essimporter/importklst.cpp | 22 ++++++++++++++++++++++ apps/essimporter/importklst.hpp | 28 ++++++++++++++++++++++++++++ 5 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 apps/essimporter/importklst.cpp create mode 100644 apps/essimporter/importklst.hpp diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index 3d3e0860c..cf3218454 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -7,6 +7,7 @@ set(ESSIMPORTER_FILES importcellref.cpp importacdt.cpp importinventory.cpp + importklst.cpp importercontext.cpp converter.cpp convertacdt.cpp diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 5f1961717..aee60f2e7 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -15,6 +15,7 @@ #include "importercontext.hpp" #include "importcellref.hpp" +#include "importklst.hpp" #include "convertacdt.hpp" #include "convertnpcc.hpp" @@ -93,6 +94,7 @@ public: mContext->mPlayer.mObject.mCreatureStats.mLevel = npc.mNpdt52.mLevel; mContext->mPlayerBase = npc; std::map empty; + // FIXME: not working? for (std::vector::const_iterator it = npc.mSpells.mList.begin(); it != npc.mSpells.mList.end(); ++it) mContext->mPlayer.mObject.mCreatureStats.mSpells.mSpells[*it] = empty; } @@ -245,6 +247,33 @@ private: std::vector mMarkers; }; +class ConvertKLST : public Converter +{ +public: + virtual void read(ESM::ESMReader& esm) + { + KLST klst; + klst.load(esm); + mKillCounter = klst.mKillCounter; + + mContext->mPlayer.mObject.mNpcStats.mWerewolfKills = klst.mWerewolfKills; + } + + virtual void write(ESM::ESMWriter &esm) + { + esm.startRecord(ESM::REC_DCOU); + for (std::map::const_iterator it = mKillCounter.begin(); it != mKillCounter.end(); ++it) + { + esm.writeHNString("ID__", it->first); + esm.writeHNT ("COUN", it->second); + } + esm.endRecord(ESM::REC_DCOU); + } + +private: + std::map mKillCounter; +}; + } #endif diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 12136cdea..4cf41a861 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -146,7 +146,7 @@ namespace ESSImport { std::cout << "Different subrecord name (" << rec.mName << "." << sub.mName << " vs. " << sub2.mName << ") at (1) 0x" << std::hex << sub.mFileOffset << " (2) 0x" << sub2.mFileOffset << std::endl; - return; // TODO: try to recover + break; // TODO: try to recover } if (sub.mData != sub2.mData) @@ -177,6 +177,7 @@ namespace ESSImport void Importer::run() { + // construct Ogre::Root to gain access to image codecs Ogre::LogManager logman; Ogre::Root root; @@ -191,6 +192,7 @@ namespace ESSImport const unsigned int recREFR = ESM::FourCC<'R','E','F','R'>::value; const unsigned int recPCDT = ESM::FourCC<'P','C','D','T'>::value; const unsigned int recFMAP = ESM::FourCC<'F','M','A','P'>::value; + const unsigned int recKLST = ESM::FourCC<'K','L','S','T'>::value; std::map > converters; converters[ESM::REC_GLOB] = boost::shared_ptr(new ConvertGlobal()); @@ -201,6 +203,7 @@ namespace ESSImport converters[recREFR] = boost::shared_ptr(new ConvertREFR()); converters[recPCDT] = boost::shared_ptr(new ConvertPCDT()); converters[recFMAP] = boost::shared_ptr(new ConvertFMAP()); + converters[recKLST] = boost::shared_ptr(new ConvertKLST()); converters[ESM::REC_CELL] = boost::shared_ptr(new ConvertCell()); converters[ESM::REC_ALCH] = boost::shared_ptr(new DefaultConverter()); converters[ESM::REC_CLAS] = boost::shared_ptr(new ConvertClass()); diff --git a/apps/essimporter/importklst.cpp b/apps/essimporter/importklst.cpp new file mode 100644 index 000000000..daa1ab077 --- /dev/null +++ b/apps/essimporter/importklst.cpp @@ -0,0 +1,22 @@ +#include "importklst.hpp" + +#include + +namespace ESSImport +{ + + void KLST::load(ESM::ESMReader &esm) + { + while (esm.isNextSub("KNAM")) + { + std::string refId = esm.getHString(); + int count; + esm.getHNT(count, "CNAM"); + mKillCounter[refId] = count; + } + + mWerewolfKills = 0; + esm.getHNOT(mWerewolfKills, "INTV"); + } + +} diff --git a/apps/essimporter/importklst.hpp b/apps/essimporter/importklst.hpp new file mode 100644 index 000000000..e333e7150 --- /dev/null +++ b/apps/essimporter/importklst.hpp @@ -0,0 +1,28 @@ +#ifndef OPENMW_ESSIMPORT_KLST_H +#define OPENMW_ESSIMPORT_KLST_H + +#include +#include + +namespace ESM +{ + struct ESMReader; +} + +namespace ESSImport +{ + + /// Kill Stats + struct KLST + { + void load(ESM::ESMReader& esm); + + /// RefId, kill count + std::map mKillCounter; + + int mWerewolfKills; + }; + +} + +#endif From 235683e44943bc68528527f9da14953749126b21 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 19 Jan 2015 10:34:49 +0100 Subject: [PATCH 236/740] Remove LightState from openmw save format to streamline inventory loading --- apps/openmw/mwclass/light.cpp | 10 ++---- apps/openmw/mwworld/cellstore.cpp | 5 ++- apps/openmw/mwworld/containerstore.cpp | 36 ++++++++------------- apps/openmw/mwworld/containerstore.hpp | 2 +- components/CMakeLists.txt | 2 +- components/esm/inventorystate.cpp | 43 +++++++++----------------- components/esm/inventorystate.hpp | 7 +---- components/esm/lightstate.cpp | 21 ------------- components/esm/lightstate.hpp | 19 ------------ components/esm/objectstate.cpp | 8 +++++ components/esm/objectstate.hpp | 2 ++ 11 files changed, 45 insertions(+), 110 deletions(-) delete mode 100644 components/esm/lightstate.cpp delete mode 100644 components/esm/lightstate.hpp diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 669b8187c..c50ad52d8 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -2,7 +2,7 @@ #include "light.hpp" #include -#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -285,21 +285,17 @@ namespace MWClass void Light::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const { - const ESM::LightState& state2 = dynamic_cast (state); - ensureCustomData (ptr); - dynamic_cast (*ptr.getRefData().getCustomData()).mTime = state2.mTime; + dynamic_cast (*ptr.getRefData().getCustomData()).mTime = state.mTime; } void Light::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) const { - ESM::LightState& state2 = dynamic_cast (state); - ensureCustomData (ptr); - state2.mTime = dynamic_cast (*ptr.getRefData().getCustomData()).mTime; + state.mTime = dynamic_cast (*ptr.getRefData().getCustomData()).mTime; } std::string Light::getSound(const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 1c0e7e385..4cf99fdb7 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -624,7 +623,7 @@ namespace MWWorld writeReferenceCollection (writer, mIngreds); writeReferenceCollection (writer, mCreatureLists); writeReferenceCollection (writer, mItemLists); - writeReferenceCollection (writer, mLights); + writeReferenceCollection (writer, mLights); writeReferenceCollection (writer, mLockpicks); writeReferenceCollection (writer, mMiscItems); writeReferenceCollection (writer, mNpcs); @@ -708,7 +707,7 @@ namespace MWWorld case ESM::REC_LIGH: - readReferenceCollection (reader, mLights, contentFileMap); + readReferenceCollection (reader, mLights, contentFileMap); break; case ESM::REC_LOCK: diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index e9c968a07..bd14720f7 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -87,7 +87,7 @@ void MWWorld::ContainerStore::storeState (const LiveCellRef& ref, ESM::Object template void MWWorld::ContainerStore::storeStates (const CellRefList& collection, - std::vector > >& states, bool equipable) const + std::vector >& states, bool equipable) const { for (typename CellRefList::List::const_iterator iter (collection.mList.begin()); iter!=collection.mList.end(); ++iter) @@ -97,7 +97,7 @@ void MWWorld::ContainerStore::storeStates (const CellRefList& collection, ESM::ObjectState state; storeState (*iter, state); int slot = equipable ? getSlot (*iter) : -1; - states.push_back (std::make_pair (state, std::make_pair (T::sRecordId, slot))); + states.push_back (std::make_pair (state, slot)); } } @@ -656,30 +656,25 @@ void MWWorld::ContainerStore::writeState (ESM::InventoryState& state) const storeStates (probes, state.mItems, true); storeStates (repairs, state.mItems); storeStates (weapons, state.mItems, true); - - state.mLights.clear(); + storeStates (lights, state.mItems, true); state.mLevelledItemMap = mLevelledItemMap; - - for (MWWorld::CellRefList::List::const_iterator iter (lights.mList.begin()); - iter!=lights.mList.end(); ++iter) - { - ESM::LightState objectState; - storeState (*iter, objectState); - state.mLights.push_back (std::make_pair (objectState, getSlot (*iter))); - } } void MWWorld::ContainerStore::readState (const ESM::InventoryState& state) { clear(); - for (std::vector > >::const_iterator + for (std::vector >::const_iterator iter (state.mItems.begin()); iter!=state.mItems.end(); ++iter) { - int slot = iter->second.second; + int slot = iter->second; + + const ESM::ObjectState& state = iter->first; - switch (iter->second.first) + int type = MWBase::Environment::get().getWorld()->getStore().find(state.mRef.mRefID); + + switch (type) { case ESM::REC_ALCH: getState (potions, iter->first); break; case ESM::REC_APPA: getState (appas, iter->first); break; @@ -692,19 +687,14 @@ void MWWorld::ContainerStore::readState (const ESM::InventoryState& state) case ESM::REC_PROB: setSlot (getState (probes, iter->first), slot); break; case ESM::REC_REPA: getState (repairs, iter->first); break; case ESM::REC_WEAP: setSlot (getState (weapons, iter->first), slot); break; + case ESM::REC_LIGH: setSlot (getState (lights, iter->first), slot); break; default: - - std::cerr << "invalid item type in inventory state" << std::endl; + std::cerr << "invalid item type in inventory state, refid " << state.mRef.mRefID << std::endl; + break; } } - for (std::vector >::const_iterator iter (state.mLights.begin()); - iter!=state.mLights.end(); ++iter) - { - int slot = iter->second; - setSlot (getState (lights, iter->first), slot); - } mLevelledItemMap = state.mLevelledItemMap; } diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 2849463c9..68ee41a1d 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -86,7 +86,7 @@ namespace MWWorld template void storeStates (const CellRefList& collection, - std::vector > >& states, + std::vector >& states, bool equipable = false) const; virtual int getSlot (const MWWorld::LiveCellRefBase& ref) const; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 0578a44b0..93228f87a 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -61,7 +61,7 @@ add_component_dir (esm loadinfo loadingr loadland loadlevlist loadligh loadlock loadprob loadrepa loadltex loadmgef loadmisc loadnpcc loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter - savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap lightstate inventorystate containerstate npcstate creaturestate dialoguestate statstate + savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap inventorystate containerstate npcstate creaturestate dialoguestate statstate npcstats creaturestats weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate debugprofile aisequence magiceffects util custommarkerstate ) diff --git a/components/esm/inventorystate.cpp b/components/esm/inventorystate.cpp index a2d49b144..fdaba3322 100644 --- a/components/esm/inventorystate.cpp +++ b/components/esm/inventorystate.cpp @@ -14,9 +14,10 @@ namespace state.load (esm); } - void write (ESM::ESMWriter &esm, const ESM::ObjectState& state, unsigned int type, int slot) + void write (ESM::ESMWriter &esm, const ESM::ObjectState& state, int slot) { - esm.writeHNT ("IOBJ", type); + int unused = 0; + esm.writeHNT ("IOBJ", unused); if (slot!=-1) esm.writeHNT ("SLOT", slot); @@ -29,27 +30,15 @@ void ESM::InventoryState::load (ESMReader &esm) { while (esm.isNextSub ("IOBJ")) { - unsigned int id = 0; - esm.getHT (id); - - if (id==ESM::REC_LIGH) - { - LightState state; - int slot; - read (esm, state, slot); - if (state.mCount == 0) - continue; - mLights.push_back (std::make_pair (state, slot)); - } - else - { - ObjectState state; - int slot; - read (esm, state, slot); - if (state.mCount == 0) - continue; - mItems.push_back (std::make_pair (state, std::make_pair (id, slot))); - } + int unused; // no longer used + esm.getHT(unused); + + ObjectState state; + int slot; + read (esm, state, slot); + if (state.mCount == 0) + continue; + mItems.push_back (std::make_pair (state, slot)); } while (esm.isNextSub("LEVM")) @@ -78,12 +67,8 @@ void ESM::InventoryState::load (ESMReader &esm) void ESM::InventoryState::save (ESMWriter &esm) const { - for (std::vector > >::const_iterator iter (mItems.begin()); iter!=mItems.end(); ++iter) - write (esm, iter->first, iter->second.first, iter->second.second); - - for (std::vector >::const_iterator iter (mLights.begin()); - iter!=mLights.end(); ++iter) - write (esm, iter->first, ESM::REC_LIGH, iter->second); + for (std::vector >::const_iterator iter (mItems.begin()); iter!=mItems.end(); ++iter) + write (esm, iter->first, iter->second); for (std::map::const_iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it) { diff --git a/components/esm/inventorystate.hpp b/components/esm/inventorystate.hpp index bd0b46a22..3d4407e7b 100644 --- a/components/esm/inventorystate.hpp +++ b/components/esm/inventorystate.hpp @@ -4,7 +4,6 @@ #include #include "objectstate.hpp" -#include "lightstate.hpp" namespace ESM { @@ -16,11 +15,7 @@ namespace ESM /// \brief State for inventories and containers struct InventoryState { - // anything but lights (type, slot) - std::vector > > mItems; - - // lights (slot) - std::vector > mLights; + std::vector > mItems; std::map mLevelledItemMap; diff --git a/components/esm/lightstate.cpp b/components/esm/lightstate.cpp deleted file mode 100644 index 1ef040823..000000000 --- a/components/esm/lightstate.cpp +++ /dev/null @@ -1,21 +0,0 @@ - -#include "lightstate.hpp" - -#include "esmreader.hpp" -#include "esmwriter.hpp" - -void ESM::LightState::load (ESMReader &esm) -{ - ObjectState::load (esm); - - mTime = 0; - esm.getHNOT (mTime, "LTIM"); -} - -void ESM::LightState::save (ESMWriter &esm, bool inInventory) const -{ - ObjectState::save (esm, inInventory); - - if (mTime) - esm.writeHNT ("LTIM", mTime); -} \ No newline at end of file diff --git a/components/esm/lightstate.hpp b/components/esm/lightstate.hpp deleted file mode 100644 index a22735e07..000000000 --- a/components/esm/lightstate.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef OPENMW_ESM_LIGHTSTATE_H -#define OPENMW_ESM_LIGHTSTATE_H - -#include "objectstate.hpp" - -namespace ESM -{ - // format 0, saved games only - - struct LightState : public ObjectState - { - float mTime; - - virtual void load (ESMReader &esm); - virtual void save (ESMWriter &esm, bool inInventory = false) const; - }; -} - -#endif diff --git a/components/esm/objectstate.cpp b/components/esm/objectstate.cpp index f7755f8cb..98cf3eba6 100644 --- a/components/esm/objectstate.cpp +++ b/components/esm/objectstate.cpp @@ -23,6 +23,10 @@ void ESM::ObjectState::load (ESMReader &esm) esm.getHNOT (mPosition, "POS_", 24); esm.getHNOT (mLocalRotation, "LROT", 12); + + // used for lights only + mTime = 0; + esm.getHNOT (mTime, "LTIM"); } void ESM::ObjectState::save (ESMWriter &esm, bool inInventory) const @@ -46,6 +50,9 @@ void ESM::ObjectState::save (ESMWriter &esm, bool inInventory) const esm.writeHNT ("POS_", mPosition, 24); esm.writeHNT ("LROT", mLocalRotation, 12); } + + if (mTime) + esm.writeHNT ("LTIM", mTime); } void ESM::ObjectState::blank() @@ -60,6 +67,7 @@ void ESM::ObjectState::blank() mPosition.rot[i] = 0; mLocalRotation[i] = 0; } + mTime = 0; } ESM::ObjectState::~ObjectState() {} diff --git a/components/esm/objectstate.hpp b/components/esm/objectstate.hpp index 5b05e0949..6b536bd01 100644 --- a/components/esm/objectstate.hpp +++ b/components/esm/objectstate.hpp @@ -26,6 +26,8 @@ namespace ESM ESM::Position mPosition; float mLocalRotation[3]; + float mTime; // Used for lights only. Overhead should not be so awful, besides CellRef isn't OO either + virtual void load (ESMReader &esm); virtual void save (ESMWriter &esm, bool inInventory = false) const; From f7e32a24c9f8550c018495860a2f9e0b4dc36194 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 19 Jan 2015 12:03:30 +0100 Subject: [PATCH 237/740] Fix terrain assertion --- components/esmterrain/storage.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index 3c76cc3b4..a66193f97 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -402,8 +402,8 @@ namespace ESMTerrain int endX = startX + 1; int endY = startY + 1; - assert(endX < ESM::Land::LAND_SIZE); - assert(endY < ESM::Land::LAND_SIZE); + endX = std::min(endX, ESM::Land::LAND_SIZE-1); + endY = std::min(endY, ESM::Land::LAND_SIZE-1); // now get points in terrain space (effectively rounding them to boundaries) float startXTS = startX * invFactor; From a7b82e5107caed0fceb407abfa364071d0338053 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 19 Jan 2015 12:22:51 +0100 Subject: [PATCH 238/740] ESSImport: inventory loading works, equipment slots need more work --- apps/essimporter/CMakeLists.txt | 2 ++ apps/essimporter/convertcrec.cpp | 13 +++++++++++++ apps/essimporter/convertcrec.hpp | 15 +++++++++++++++ apps/essimporter/converter.cpp | 4 ++++ apps/essimporter/convertinventory.cpp | 23 +++++++++++++++++++++++ apps/essimporter/convertinventory.hpp | 15 +++++++++++++++ apps/essimporter/convertnpcc.cpp | 4 ++++ apps/essimporter/importinventory.cpp | 22 +++++++++++++++++++--- apps/essimporter/importinventory.hpp | 1 + components/esm/cellref.cpp | 4 ++-- 10 files changed, 98 insertions(+), 5 deletions(-) create mode 100644 apps/essimporter/convertcrec.cpp create mode 100644 apps/essimporter/convertcrec.hpp create mode 100644 apps/essimporter/convertinventory.cpp create mode 100644 apps/essimporter/convertinventory.hpp diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index cf3218454..1af55de9b 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -12,6 +12,8 @@ set(ESSIMPORTER_FILES converter.cpp convertacdt.cpp convertnpcc.cpp + convertinventory.cpp + convertcrec.cpp ) add_executable(openmw-essimporter diff --git a/apps/essimporter/convertcrec.cpp b/apps/essimporter/convertcrec.cpp new file mode 100644 index 000000000..34e1c0070 --- /dev/null +++ b/apps/essimporter/convertcrec.cpp @@ -0,0 +1,13 @@ +#include "convertcrec.hpp" + +#include "convertinventory.hpp" + +namespace ESSImport +{ + + void convertCREC(const CREC &crec, ESM::CreatureState &state) + { + convertInventory(crec.mInventory, state.mInventory); + } + +} diff --git a/apps/essimporter/convertcrec.hpp b/apps/essimporter/convertcrec.hpp new file mode 100644 index 000000000..7d317f03e --- /dev/null +++ b/apps/essimporter/convertcrec.hpp @@ -0,0 +1,15 @@ +#ifndef OPENMW_ESSIMPORT_CONVERTCREC_H +#define OPENMW_ESSIMPORT_CONVERTCREC_H + +#include "importcrec.hpp" + +#include + +namespace ESSImport +{ + + void convertCREC(const CREC& crec, ESM::CreatureState& state); + +} + +#endif diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index ce3cea675..22d6d8282 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -4,6 +4,8 @@ #include +#include "convertcrec.hpp" + namespace { @@ -197,6 +199,7 @@ namespace ESSImport ESM::CreatureState objstate; objstate.blank(); convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats); + convertCREC(crecIt->second, objstate); objstate.mEnabled = cellref.mEnabled; objstate.mPosition = cellref.mPos; objstate.mRef = out; @@ -215,6 +218,7 @@ namespace ESSImport objstate.blank(); convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats); convertNpcData(cellref.mActorData, objstate.mNpcStats); + convertNPCC(npccIt->second, objstate); objstate.mEnabled = cellref.mEnabled; objstate.mPosition = cellref.mPos; objstate.mRef = out; diff --git a/apps/essimporter/convertinventory.cpp b/apps/essimporter/convertinventory.cpp new file mode 100644 index 000000000..42535d946 --- /dev/null +++ b/apps/essimporter/convertinventory.cpp @@ -0,0 +1,23 @@ +#include "convertinventory.hpp" + +#include + +namespace ESSImport +{ + + void convertInventory(const Inventory &inventory, ESM::InventoryState &state) + { + for (std::vector::const_iterator it = inventory.mItems.begin(); + it != inventory.mItems.end(); ++it) + { + ESM::ObjectState objstate; + objstate.blank(); + objstate.mRef.mRefID = Misc::StringUtils::lowerCase(it->mId); + objstate.mCount = std::abs(it->mCount); // restocking items have negative count in the savefile + // openmw handles them differently, so no need to set any flags + objstate.mRef.mCharge = it->mCondition; + state.mItems.push_back(std::make_pair(objstate, -1)); + } + } + +} diff --git a/apps/essimporter/convertinventory.hpp b/apps/essimporter/convertinventory.hpp new file mode 100644 index 000000000..8abe85a44 --- /dev/null +++ b/apps/essimporter/convertinventory.hpp @@ -0,0 +1,15 @@ +#ifndef OPENMW_ESSIMPORT_CONVERTINVENTORY_H +#define OPENMW_ESSIMPORT_CONVERTINVENTORY_H + +#include "importinventory.hpp" + +#include + +namespace ESSImport +{ + + void convertInventory (const Inventory& inventory, ESM::InventoryState& state); + +} + +#endif diff --git a/apps/essimporter/convertnpcc.cpp b/apps/essimporter/convertnpcc.cpp index fdf96c15a..2155f46fb 100644 --- a/apps/essimporter/convertnpcc.cpp +++ b/apps/essimporter/convertnpcc.cpp @@ -1,10 +1,14 @@ #include "convertnpcc.hpp" +#include "convertinventory.hpp" + namespace ESSImport { void convertNPCC(const NPCC &npcc, ESM::NpcState &npcState) { npcState.mNpcStats.mReputation = npcc.mNPDT.mReputation; + + convertInventory(npcc.mInventory, npcState.mInventory); } } diff --git a/apps/essimporter/importinventory.cpp b/apps/essimporter/importinventory.cpp index d132fd76d..b3bd4a86b 100644 --- a/apps/essimporter/importinventory.cpp +++ b/apps/essimporter/importinventory.cpp @@ -2,6 +2,8 @@ #include +#include + namespace ESSImport { @@ -9,8 +11,12 @@ namespace ESSImport { while (esm.isNextSub("NPCO")) { + ESM::ContItem contItem; + esm.getHT(contItem); + InventoryItem item; - item.mId = esm.getHString(); + item.mId = contItem.mItem.toString(); + item.mCount = contItem.mCount; if (esm.isNextSub("XIDX")) esm.skipHSub(); @@ -32,14 +38,24 @@ namespace ESSImport item.ESM::CellRef::loadData(esm); item.mCondition = -1; + // FIXME: for Lights, this is actually a float esm.getHNOT(item.mCondition, "XHLT"); mItems.push_back(item); } + // equipped items while (esm.isNextSub("WIDX")) { - // equipping? - esm.skipHSub(); + // note: same item can be equipped 2 items (e.g. 2 rings) + // and will be *stacked* in the NPCO list, unlike openmw! + esm.getSubHeader(); + int itemIndex; // index of the item in the NPCO list + esm.getT(itemIndex); + + // appears to be a relative index for only the *possible* slots this item can be equipped in, + // i.e. 0 most of the time, unlike openmw slot enum index + int slotIndex; + esm.getT(slotIndex); } } diff --git a/apps/essimporter/importinventory.hpp b/apps/essimporter/importinventory.hpp index e31cab76a..359e43fa6 100644 --- a/apps/essimporter/importinventory.hpp +++ b/apps/essimporter/importinventory.hpp @@ -19,6 +19,7 @@ namespace ESSImport struct InventoryItem : public ESM::CellRef { std::string mId; + int mCount; int mCondition; }; std::vector mItems; diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index 43b1f4d29..0c2dfd5db 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -142,8 +142,8 @@ void ESM::CellRef::blank() mSoul.clear(); mFaction.clear(); mFactionRank = -2; - mCharge = 0; - mEnchantmentCharge = 0; + mCharge = -1; + mEnchantmentCharge = -1; mGoldValue = 0; mDestCell.clear(); mLockLevel = 0; From 8e1eeccbe190f3ec04fc60283313683e7ea7dac2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 19 Jan 2015 13:16:12 +0100 Subject: [PATCH 239/740] ESSImport: container state --- apps/essimporter/CMakeLists.txt | 2 + apps/essimporter/convertcntc.cpp | 13 +++ apps/essimporter/convertcntc.hpp | 15 +++ apps/essimporter/converter.cpp | 163 ++++++++++++++++----------- apps/essimporter/converter.hpp | 20 +++- apps/essimporter/importcntc.cpp | 16 +++ apps/essimporter/importcntc.hpp | 25 ++++ apps/essimporter/importer.cpp | 1 + apps/essimporter/importercontext.hpp | 2 + components/CMakeLists.txt | 2 +- components/esm/loadcrec.hpp | 49 -------- components/esm/records.hpp | 1 - 12 files changed, 189 insertions(+), 120 deletions(-) create mode 100644 apps/essimporter/convertcntc.cpp create mode 100644 apps/essimporter/convertcntc.hpp create mode 100644 apps/essimporter/importcntc.cpp create mode 100644 apps/essimporter/importcntc.hpp delete mode 100644 components/esm/loadcrec.hpp diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index 1af55de9b..8d1af714d 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -8,12 +8,14 @@ set(ESSIMPORTER_FILES importacdt.cpp importinventory.cpp importklst.cpp + importcntc.cpp importercontext.cpp converter.cpp convertacdt.cpp convertnpcc.cpp convertinventory.cpp convertcrec.cpp + convertcntc.cpp ) add_executable(openmw-essimporter diff --git a/apps/essimporter/convertcntc.cpp b/apps/essimporter/convertcntc.cpp new file mode 100644 index 000000000..426ef4496 --- /dev/null +++ b/apps/essimporter/convertcntc.cpp @@ -0,0 +1,13 @@ +#include "convertcntc.hpp" + +#include "convertinventory.hpp" + +namespace ESSImport +{ + + void convertCNTC(const CNTC &cntc, ESM::ContainerState &state) + { + convertInventory(cntc.mInventory, state.mInventory); + } + +} diff --git a/apps/essimporter/convertcntc.hpp b/apps/essimporter/convertcntc.hpp new file mode 100644 index 000000000..c299d87a1 --- /dev/null +++ b/apps/essimporter/convertcntc.hpp @@ -0,0 +1,15 @@ +#ifndef OPENMW_ESSIMPORT_CONVERTCNTC_H +#define OPENMW_ESSIMPORT_CONVERTCNTC_H + +#include "importcntc.hpp" + +#include + +namespace ESSImport +{ + + void convertCNTC(const CNTC& cntc, ESM::ContainerState& state); + +} + +#endif diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 22d6d8282..293c48624 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -3,8 +3,10 @@ #include #include +#include #include "convertcrec.hpp" +#include "convertcntc.hpp" namespace { @@ -17,6 +19,13 @@ namespace screenshot.save(out); } + + void convertCellRef(const ESSImport::CellRef& cellref, ESM::ObjectState& objstate) + { + objstate.mEnabled = cellref.mEnabled; + objstate.mPosition = cellref.mPos; + objstate.mRef.mRefNum = cellref.mRefNum; + } } namespace ESSImport @@ -116,8 +125,9 @@ namespace ESSImport ref.load (esm); if (esm.isNextSub("DELE")) { + // TODO // strangely this can be e.g. 52 instead of just 1, - std::cout << "deleted ref " << ref.mIndexedRefId << std::endl; + //std::cout << "deleted ref " << ref.mIndexedRefId << std::endl; esm.skipHSub(); } cellrefs.push_back(ref); @@ -155,85 +165,104 @@ namespace ESSImport newcell.mRefs = cellrefs; - // FIXME: map by ID for exterior cells - mCells[id] = newcell; + + if (cell.isExterior()) + mExtCells[std::make_pair(cell.mData.mX, cell.mData.mY)] = newcell; + else + mIntCells[id] = newcell; } - void ConvertCell::write(ESM::ESMWriter &esm) + void ConvertCell::writeCell(const Cell &cell, ESM::ESMWriter& esm) { - for (std::map::const_iterator it = mCells.begin(); it != mCells.end(); ++it) + ESM::Cell esmcell = cell.mCell; + esm.startRecord(ESM::REC_CSTA); + ESM::CellState csta; + csta.mHasFogOfWar = 0; + csta.mId = esmcell.getCellId(); + csta.mId.save(esm); + // TODO csta.mLastRespawn; + // shouldn't be needed if we respawn on global schedule like in original MW + csta.mWaterLevel = esmcell.mWater; + csta.save(esm); + + for (std::vector::const_iterator refIt = cell.mRefs.begin(); refIt != cell.mRefs.end(); ++refIt) { - const ESM::Cell& cell = it->second.mCell; - esm.startRecord(ESM::REC_CSTA); - ESM::CellState csta; - csta.mHasFogOfWar = 0; - csta.mId = cell.getCellId(); - csta.mId.save(esm); - // TODO csta.mLastRespawn; - // shouldn't be needed if we respawn on global schedule like in original MW - csta.mWaterLevel = cell.mWater; - csta.save(esm); - - for (std::vector::const_iterator refIt = it->second.mRefs.begin(); refIt != it->second.mRefs.end(); ++refIt) - { - const CellRef& cellref = *refIt; - ESM::CellRef out; - out.blank(); + const CellRef& cellref = *refIt; + ESM::CellRef out; + out.blank(); - if (cellref.mIndexedRefId.size() < 8) - { - std::cerr << "CellRef with no index?" << std::endl; - continue; - } - std::stringstream stream; - stream << cellref.mIndexedRefId.substr(cellref.mIndexedRefId.size()-8,8); - int refIndex; - stream >> refIndex; + if (cellref.mIndexedRefId.size() < 8) + { + std::cerr << "CellRef with no index?" << std::endl; + continue; + } + std::stringstream stream; + stream << cellref.mIndexedRefId.substr(cellref.mIndexedRefId.size()-8,8); + int refIndex; + stream >> refIndex; - out.mRefID = cellref.mIndexedRefId.substr(0,cellref.mIndexedRefId.size()-8); + out.mRefID = cellref.mIndexedRefId.substr(0,cellref.mIndexedRefId.size()-8); - std::map, CREC>::const_iterator crecIt = mContext->mCreatureChanges.find( - std::make_pair(refIndex, out.mRefID)); - if (crecIt != mContext->mCreatureChanges.end()) - { - ESM::CreatureState objstate; - objstate.blank(); - convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats); - convertCREC(crecIt->second, objstate); - objstate.mEnabled = cellref.mEnabled; - objstate.mPosition = cellref.mPos; - objstate.mRef = out; - objstate.mRef.mRefNum = cellref.mRefNum; - // FIXME: change save format to not require object type, instead look up it up using the RefId - esm.writeHNT ("OBJE", ESM::REC_CREA); - objstate.save(esm); - continue; - } + std::map, CREC>::const_iterator crecIt = mContext->mCreatureChanges.find( + std::make_pair(refIndex, out.mRefID)); + if (crecIt != mContext->mCreatureChanges.end()) + { + ESM::CreatureState objstate; + objstate.blank(); + objstate.mRef = out; + convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats); + convertCREC(crecIt->second, objstate); + convertCellRef(cellref, objstate); + // FIXME: change save format to not require object type, instead look up it up using the RefId + esm.writeHNT ("OBJE", ESM::REC_CREA); + objstate.save(esm); + continue; + } - std::map, NPCC>::const_iterator npccIt = mContext->mNpcChanges.find( - std::make_pair(refIndex, out.mRefID)); - if (npccIt != mContext->mNpcChanges.end()) - { - ESM::NpcState objstate; - objstate.blank(); - convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats); - convertNpcData(cellref.mActorData, objstate.mNpcStats); - convertNPCC(npccIt->second, objstate); - objstate.mEnabled = cellref.mEnabled; - objstate.mPosition = cellref.mPos; - objstate.mRef = out; - objstate.mRef.mRefNum = cellref.mRefNum; - esm.writeHNT ("OBJE", ESM::REC_NPC_); - objstate.save(esm); - continue; - } + std::map, NPCC>::const_iterator npccIt = mContext->mNpcChanges.find( + std::make_pair(refIndex, out.mRefID)); + if (npccIt != mContext->mNpcChanges.end()) + { + ESM::NpcState objstate; + objstate.blank(); + objstate.mRef = out; + convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats); + convertNpcData(cellref.mActorData, objstate.mNpcStats); + convertNPCC(npccIt->second, objstate); + convertCellRef(cellref, objstate); + esm.writeHNT ("OBJE", ESM::REC_NPC_); + objstate.save(esm); + continue; + } - std::cerr << "Can't find type for " << refIndex << " " << out.mRefID << std::endl; + std::map, CNTC>::const_iterator cntcIt = mContext->mContainerChanges.find( + std::make_pair(refIndex, out.mRefID)); + if (cntcIt != mContext->mContainerChanges.end()) + { + ESM::ContainerState objstate; + objstate.blank(); + objstate.mRef = out; + convertCNTC(cntcIt->second, objstate); + convertCellRef(cellref, objstate); + esm.writeHNT ("OBJE", ESM::REC_CONT); + objstate.save(esm); + continue; } - esm.endRecord(ESM::REC_CSTA); + std::cerr << "Can't find type for " << refIndex << " " << out.mRefID << std::endl; } + esm.endRecord(ESM::REC_CSTA); + } + + void ConvertCell::write(ESM::ESMWriter &esm) + { + for (std::map::const_iterator it = mIntCells.begin(); it != mIntCells.end(); ++it) + writeCell(it->second, esm); + + for (std::map, Cell>::const_iterator it = mExtCells.begin(); it != mExtCells.end(); ++it) + writeCell(it->second, esm); + for (std::vector::const_iterator it = mMarkers.begin(); it != mMarkers.end(); ++it) { esm.startRecord(ESM::REC_MARK); diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index aee60f2e7..e758db964 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -12,6 +12,7 @@ #include #include "importcrec.hpp" +#include "importcntc.hpp" #include "importercontext.hpp" #include "importcellref.hpp" @@ -94,7 +95,8 @@ public: mContext->mPlayer.mObject.mCreatureStats.mLevel = npc.mNpdt52.mLevel; mContext->mPlayerBase = npc; std::map empty; - // FIXME: not working? + // FIXME: player start spells, racial spells and birthsign spells aren't listed here, + // need to fix openmw to account for this for (std::vector::const_iterator it = npc.mSpells.mList.begin(); it != npc.mSpells.mList.end(); ++it) mContext->mPlayer.mObject.mCreatureStats.mSpells.mSpells[*it] = empty; } @@ -209,6 +211,17 @@ public: } }; +class ConvertCNTC : public Converter +{ + virtual void read(ESM::ESMReader &esm) + { + std::string id = esm.getHNString("NAME"); + CNTC cntc; + cntc.load(esm); + mContext->mContainerChanges.insert(std::make_pair(std::make_pair(cntc.mIndex,id), cntc)); + } +}; + class ConvertCREC : public Converter { public: @@ -242,9 +255,12 @@ private: std::vector mFogOfWar; }; - std::map mCells; + std::map mIntCells; + std::map, Cell> mExtCells; std::vector mMarkers; + + void writeCell(const Cell& cell, ESM::ESMWriter &esm); }; class ConvertKLST : public Converter diff --git a/apps/essimporter/importcntc.cpp b/apps/essimporter/importcntc.cpp new file mode 100644 index 000000000..a492aef5a --- /dev/null +++ b/apps/essimporter/importcntc.cpp @@ -0,0 +1,16 @@ +#include "importcntc.hpp" + +#include + +namespace ESSImport +{ + + void CNTC::load(ESM::ESMReader &esm) + { + mIndex = 0; + esm.getHNT(mIndex, "INDX"); + + mInventory.load(esm); + } + +} diff --git a/apps/essimporter/importcntc.hpp b/apps/essimporter/importcntc.hpp new file mode 100644 index 000000000..1bc7d94bd --- /dev/null +++ b/apps/essimporter/importcntc.hpp @@ -0,0 +1,25 @@ +#ifndef OPENMW_ESSIMPORT_IMPORTCNTC_H +#define OPENMW_ESSIMPORT_IMPORTCNTC_H + +#include "importinventory.hpp" + +namespace ESM +{ + class ESMReader; +} + +namespace ESSImport +{ + + /// Changed container contents + struct CNTC + { + int mIndex; + + Inventory mInventory; + + void load(ESM::ESMReader& esm); + }; + +} +#endif diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 4cf41a861..9075db404 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -215,6 +215,7 @@ namespace ESSImport converters[ESM::REC_WEAP] = boost::shared_ptr(new DefaultConverter()); converters[ESM::REC_LEVC] = boost::shared_ptr(new DefaultConverter()); converters[ESM::REC_LEVI] = boost::shared_ptr(new DefaultConverter()); + converters[ESM::REC_CNTC] = boost::shared_ptr(new ConvertCNTC()); std::set unknownRecords; diff --git a/apps/essimporter/importercontext.hpp b/apps/essimporter/importercontext.hpp index 9183e6179..a921b81ef 100644 --- a/apps/essimporter/importercontext.hpp +++ b/apps/essimporter/importercontext.hpp @@ -8,6 +8,7 @@ #include "importnpcc.hpp" #include "importcrec.hpp" +#include "importcntc.hpp" #include "importplayer.hpp" @@ -30,6 +31,7 @@ namespace ESSImport // key std::map, CREC> mCreatureChanges; std::map, NPCC> mNpcChanges; + std::map, CNTC> mContainerChanges; Context() { diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 93228f87a..a0500127c 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -57,7 +57,7 @@ add_component_dir (to_utf8 add_component_dir (esm attr defs esmcommon esmreader esmwriter loadacti loadalch loadappa loadarmo loadbody loadbook loadbsgn loadcell - loadclas loadclot loadcont loadcrea loadcrec loaddial loaddoor loadench loadfact loadglob loadgmst + loadclas loadclot loadcont loadcrea loaddial loaddoor loadench loadfact loadglob loadgmst loadinfo loadingr loadland loadlevlist loadligh loadlock loadprob loadrepa loadltex loadmgef loadmisc loadnpcc loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter diff --git a/components/esm/loadcrec.hpp b/components/esm/loadcrec.hpp deleted file mode 100644 index 280739aca..000000000 --- a/components/esm/loadcrec.hpp +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef OPENMW_ESM_CREC_H -#define OPENMW_ESM_CREC_H - -#include - -// TODO create implementation files and remove this one -#include "esmreader.hpp" - -namespace ESM { - -class ESMReader; -class ESMWriter; - -/* These two are only used in save games. They are not decoded yet. - */ - -/// Changes a creature -struct LoadCREC -{ - static unsigned int sRecordId; - - std::string mId; - - void load(ESMReader &esm) - { - esm.skipRecord(); - } - - void save(ESMWriter &esm) const - { - } -}; - -/// Changes an item list / container -struct LoadCNTC -{ - std::string mId; - - void load(ESMReader &esm) - { - esm.skipRecord(); - } - - void save(ESMWriter &esm) const - { - } -}; -} -#endif diff --git a/components/esm/records.hpp b/components/esm/records.hpp index 7a0452eb3..c01c89d57 100644 --- a/components/esm/records.hpp +++ b/components/esm/records.hpp @@ -14,7 +14,6 @@ #include "loadclot.hpp" #include "loadcont.hpp" #include "loadcrea.hpp" -#include "loadcrec.hpp" #include "loadinfo.hpp" #include "loaddial.hpp" #include "loaddoor.hpp" From 9014dc48ee166ff9d3e5750971787056a318356e Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 19 Jan 2015 23:29:06 +0100 Subject: [PATCH 240/740] Don't require the object type id for reading references from savegames This is redundant, since we can look it up from the RefID. --- apps/openmw/mwclass/creature.cpp | 10 ++++- apps/openmw/mwclass/npc.cpp | 9 +++++ apps/openmw/mwworld/cellstore.cpp | 65 +++++++++++++++++++------------ components/esm/cellref.cpp | 8 +++- components/esm/cellref.hpp | 3 ++ components/esm/creaturestate.cpp | 14 +++++-- components/esm/esmreader.cpp | 11 ++++++ components/esm/esmreader.hpp | 3 ++ components/esm/inventorystate.cpp | 1 + components/esm/npcstate.cpp | 19 ++++++--- components/esm/objectstate.cpp | 10 ++++- components/esm/objectstate.hpp | 8 ++++ components/esm/player.cpp | 1 + 13 files changed, 123 insertions(+), 39 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index a3614af96..2e53fe802 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -816,6 +816,9 @@ namespace MWClass void Creature::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const { + if (!state.mHasCustomState) + return; + const ESM::CreatureState& state2 = dynamic_cast (state); ensureCustomData(ptr); @@ -844,7 +847,6 @@ namespace MWClass customData.mContainerStore->readState (state2.mInventory); customData.mCreatureStats.readState (state2.mCreatureStats); - } void Creature::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) @@ -852,6 +854,12 @@ namespace MWClass { ESM::CreatureState& state2 = dynamic_cast (state); + if (!ptr.getRefData().getCustomData()) + { + state.mHasCustomState = false; + return; + } + ensureCustomData (ptr); CreatureCustomData& customData = dynamic_cast (*ptr.getRefData().getCustomData()); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index ac4182734..8f62cc1e8 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1275,6 +1275,9 @@ namespace MWClass void Npc::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const { + if (!state.mHasCustomState) + return; + const ESM::NpcState& state2 = dynamic_cast (state); ensureCustomData(ptr); @@ -1302,6 +1305,12 @@ namespace MWClass { ESM::NpcState& state2 = dynamic_cast (state); + if (!ptr.getRefData().getCustomData()) + { + state.mHasCustomState = false; + return; + } + ensureCustomData (ptr); NpcCustomData& customData = dynamic_cast (*ptr.getRefData().getCustomData()); diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 4cf99fdb7..605c8f9d2 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -85,7 +85,9 @@ namespace RecordType state; iter->save (state); + // recordId currently unused writer.writeHNT ("OBJE", collection.mList.front().mBase->sRecordId); + state.save (writer); } } @@ -93,12 +95,13 @@ namespace template void readReferenceCollection (ESM::ESMReader& reader, - MWWorld::CellRefList& collection, const std::map& contentFileMap) + MWWorld::CellRefList& collection, const ESM::CellRef& cref, const std::map& contentFileMap) { const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); RecordType state; - state.load (reader); + state.mRef = cref; + state.load(reader); // If the reference came from a content file, make sure this content file is loaded if (state.mRef.mRefNum.hasContentFile()) @@ -640,109 +643,121 @@ namespace MWWorld while (reader.isNextSub ("OBJE")) { - unsigned int id = 0; - reader.getHT (id); + unsigned int unused; + reader.getHT (unused); + + // load the RefID first so we know what type of object it is + ESM::CellRef cref; + cref.loadId(reader, true); + + int type = MWBase::Environment::get().getWorld()->getStore().find(cref.mRefID); + if (type == 0) + { + std::cerr << "Dropping reference to '" << cref.mRefID << "' (object no longer exists)" << std::endl; + reader.skipHSubUntil("OBJE"); + continue; + } - switch (id) + switch (type) { case ESM::REC_ACTI: - readReferenceCollection (reader, mActivators, contentFileMap); + readReferenceCollection (reader, mActivators, cref, contentFileMap); break; case ESM::REC_ALCH: - readReferenceCollection (reader, mPotions, contentFileMap); + readReferenceCollection (reader, mPotions, cref, contentFileMap); break; case ESM::REC_APPA: - readReferenceCollection (reader, mAppas, contentFileMap); + readReferenceCollection (reader, mAppas, cref, contentFileMap); break; case ESM::REC_ARMO: - readReferenceCollection (reader, mArmors, contentFileMap); + readReferenceCollection (reader, mArmors, cref, contentFileMap); break; case ESM::REC_BOOK: - readReferenceCollection (reader, mBooks, contentFileMap); + readReferenceCollection (reader, mBooks, cref, contentFileMap); break; case ESM::REC_CLOT: - readReferenceCollection (reader, mClothes, contentFileMap); + readReferenceCollection (reader, mClothes, cref, contentFileMap); break; case ESM::REC_CONT: - readReferenceCollection (reader, mContainers, contentFileMap); + readReferenceCollection (reader, mContainers, cref, contentFileMap); break; case ESM::REC_CREA: - readReferenceCollection (reader, mCreatures, contentFileMap); + readReferenceCollection (reader, mCreatures, cref, contentFileMap); break; case ESM::REC_DOOR: - readReferenceCollection (reader, mDoors, contentFileMap); + readReferenceCollection (reader, mDoors, cref, contentFileMap); break; case ESM::REC_INGR: - readReferenceCollection (reader, mIngreds, contentFileMap); + readReferenceCollection (reader, mIngreds, cref, contentFileMap); break; case ESM::REC_LEVC: - readReferenceCollection (reader, mCreatureLists, contentFileMap); + readReferenceCollection (reader, mCreatureLists, cref, contentFileMap); break; case ESM::REC_LEVI: - readReferenceCollection (reader, mItemLists, contentFileMap); + readReferenceCollection (reader, mItemLists, cref, contentFileMap); break; case ESM::REC_LIGH: - readReferenceCollection (reader, mLights, contentFileMap); + readReferenceCollection (reader, mLights, cref, contentFileMap); break; case ESM::REC_LOCK: - readReferenceCollection (reader, mLockpicks, contentFileMap); + readReferenceCollection (reader, mLockpicks, cref, contentFileMap); break; case ESM::REC_MISC: - readReferenceCollection (reader, mMiscItems, contentFileMap); + readReferenceCollection (reader, mMiscItems, cref, contentFileMap); break; case ESM::REC_NPC_: - readReferenceCollection (reader, mNpcs, contentFileMap); + readReferenceCollection (reader, mNpcs, cref, contentFileMap); break; case ESM::REC_PROB: - readReferenceCollection (reader, mProbes, contentFileMap); + readReferenceCollection (reader, mProbes, cref, contentFileMap); break; case ESM::REC_REPA: - readReferenceCollection (reader, mRepairs, contentFileMap); + readReferenceCollection (reader, mRepairs, cref, contentFileMap); break; case ESM::REC_STAT: - readReferenceCollection (reader, mStatics, contentFileMap); + readReferenceCollection (reader, mStatics, cref, contentFileMap); break; case ESM::REC_WEAP: - readReferenceCollection (reader, mWeapons, contentFileMap); + readReferenceCollection (reader, mWeapons, cref, contentFileMap); break; default: diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index 0c2dfd5db..cd9fe8570 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -5,6 +5,12 @@ #include "esmwriter.hpp" void ESM::CellRef::load (ESMReader& esm, bool wideRefNum) +{ + loadId(esm, wideRefNum); + loadData(esm); +} + +void ESM::CellRef::loadId(ESMReader &esm, bool wideRefNum) { // According to Hrnchamd, this does not belong to the actual ref. Instead, it is a marker indicating that // the following refs are part of a "temp refs" section. A temp ref is not being tracked by the moved references system. @@ -19,8 +25,6 @@ void ESM::CellRef::load (ESMReader& esm, bool wideRefNum) esm.getHNT (mRefNum.mIndex, "FRMR"); mRefID = esm.getHNString ("NAME"); - - loadData(esm); } void ESM::CellRef::loadData(ESMReader &esm) diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index b7b00a654..7aa0e4d44 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -89,8 +89,11 @@ namespace ESM // Position and rotation of this object within the cell Position mPos; + /// Calls loadId and loadData void load (ESMReader& esm, bool wideRefNum = false); + void loadId (ESMReader& esm, bool wideRefNum = false); + /// Implicitly called by load void loadData (ESMReader& esm); diff --git a/components/esm/creaturestate.cpp b/components/esm/creaturestate.cpp index c2838f78d..c15becd98 100644 --- a/components/esm/creaturestate.cpp +++ b/components/esm/creaturestate.cpp @@ -5,18 +5,24 @@ void ESM::CreatureState::load (ESMReader &esm) { ObjectState::load (esm); - mInventory.load (esm); + if (mHasCustomState) + { + mInventory.load (esm); - mCreatureStats.load (esm); + mCreatureStats.load (esm); + } } void ESM::CreatureState::save (ESMWriter &esm, bool inInventory) const { ObjectState::save (esm, inInventory); - mInventory.save (esm); + if (mHasCustomState) + { + mInventory.save (esm); - mCreatureStats.save (esm); + mCreatureStats.save (esm); + } } void ESM::CreatureState::blank() diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 7cf0de1a9..de110dd18 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -210,6 +210,17 @@ void ESMReader::skipHSubSize(int size) fail("skipHSubSize() mismatch"); } +void ESMReader::skipHSubUntil(const char *name) +{ + while (hasMoreSubs() && !isNextSub(name)) + { + mCtx.subCached = false; + skipHSub(); + } + if (hasMoreSubs()) + mCtx.subCached = true; +} + void ESMReader::getSubHeader() { if (mCtx.leftRec < 4) diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index 642ec4168..bb615af11 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -195,6 +195,9 @@ public: // Skip sub record and check its size void skipHSubSize(int size); + // Skip all subrecords until the given subrecord or no more subrecords remaining + void skipHSubUntil(const char* name); + /* Sub-record header. This updates leftRec beyond the current sub-record as well. leftSub contains size of current sub-record. */ diff --git a/components/esm/inventorystate.cpp b/components/esm/inventorystate.cpp index fdaba3322..b946f9501 100644 --- a/components/esm/inventorystate.cpp +++ b/components/esm/inventorystate.cpp @@ -11,6 +11,7 @@ namespace slot = -1; esm.getHNOT (slot, "SLOT"); + state.mRef.loadId(esm, true); state.load (esm); } diff --git a/components/esm/npcstate.cpp b/components/esm/npcstate.cpp index 6134193c2..724d67326 100644 --- a/components/esm/npcstate.cpp +++ b/components/esm/npcstate.cpp @@ -5,22 +5,28 @@ void ESM::NpcState::load (ESMReader &esm) { ObjectState::load (esm); - mInventory.load (esm); + if (mHasCustomState) + { + mInventory.load (esm); - mNpcStats.load (esm); + mNpcStats.load (esm); - mCreatureStats.load (esm); + mCreatureStats.load (esm); + } } void ESM::NpcState::save (ESMWriter &esm, bool inInventory) const { ObjectState::save (esm, inInventory); - mInventory.save (esm); + if (mHasCustomState) + { + mInventory.save (esm); - mNpcStats.save (esm); + mNpcStats.save (esm); - mCreatureStats.save (esm); + mCreatureStats.save (esm); + } } void ESM::NpcState::blank() @@ -28,4 +34,5 @@ void ESM::NpcState::blank() ObjectState::blank(); mNpcStats.blank(); mCreatureStats.blank(); + mHasCustomState = true; } diff --git a/components/esm/objectstate.cpp b/components/esm/objectstate.cpp index 98cf3eba6..66fd49663 100644 --- a/components/esm/objectstate.cpp +++ b/components/esm/objectstate.cpp @@ -6,7 +6,7 @@ void ESM::ObjectState::load (ESMReader &esm) { - mRef.load (esm, true); + mRef.loadData(esm); mHasLocals = 0; esm.getHNOT (mHasLocals, "HLOC"); @@ -27,6 +27,10 @@ void ESM::ObjectState::load (ESMReader &esm) // used for lights only mTime = 0; esm.getHNOT (mTime, "LTIM"); + + // FIXME: assuming "false" as default would make more sense, but also break compatibility with older save files + mHasCustomState = true; + esm.getHNOT (mHasCustomState, "HCUS"); } void ESM::ObjectState::save (ESMWriter &esm, bool inInventory) const @@ -53,6 +57,9 @@ void ESM::ObjectState::save (ESMWriter &esm, bool inInventory) const if (mTime) esm.writeHNT ("LTIM", mTime); + + if (!mHasCustomState) + esm.writeHNT ("HCUS", false); } void ESM::ObjectState::blank() @@ -68,6 +75,7 @@ void ESM::ObjectState::blank() mLocalRotation[i] = 0; } mTime = 0; + mHasCustomState = true; } ESM::ObjectState::~ObjectState() {} diff --git a/components/esm/objectstate.hpp b/components/esm/objectstate.hpp index 6b536bd01..b03689653 100644 --- a/components/esm/objectstate.hpp +++ b/components/esm/objectstate.hpp @@ -28,7 +28,15 @@ namespace ESM float mTime; // Used for lights only. Overhead should not be so awful, besides CellRef isn't OO either + // Is there any class-specific state following the ObjectState + bool mHasCustomState; + + ObjectState() : mHasCustomState(true) + {} + + /// @note Does not load the CellRef ID, it should already be loaded before calling this method virtual void load (ESMReader &esm); + virtual void save (ESMWriter &esm, bool inInventory = false) const; /// Initialize to default state diff --git a/components/esm/player.cpp b/components/esm/player.cpp index 52b44c945..70c4b79e2 100644 --- a/components/esm/player.cpp +++ b/components/esm/player.cpp @@ -6,6 +6,7 @@ void ESM::Player::load (ESMReader &esm) { + mObject.mRef.loadId(esm, true); mObject.load (esm); mCellId.load (esm); From 40c29abe20445d8cdd61b3dc63ce8e63891757c4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 19 Jan 2015 23:51:43 +0100 Subject: [PATCH 241/740] ESSImport: convert other references (non-creature/npc/container) --- apps/essimporter/converter.cpp | 129 ++++++++++++++++++----------- apps/essimporter/converter.hpp | 9 +- apps/essimporter/importcellref.cpp | 9 +- apps/essimporter/importnpcc.cpp | 3 - apps/essimporter/importnpcc.hpp | 2 - 5 files changed, 95 insertions(+), 57 deletions(-) diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 293c48624..83ea077ea 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -26,6 +26,17 @@ namespace objstate.mPosition = cellref.mPos; objstate.mRef.mRefNum = cellref.mRefNum; } + + bool isIndexedRefId(const std::string& indexedRefId) + { + if (indexedRefId.size() <= 8) + return false; + + std::string index = indexedRefId.substr(indexedRefId.size()-8); + if(index.find_first_not_of("0123456789ABCDEF") == std::string::npos ) + return true; + return false; + } } namespace ESSImport @@ -191,65 +202,87 @@ namespace ESSImport ESM::CellRef out; out.blank(); - if (cellref.mIndexedRefId.size() < 8) + if (!isIndexedRefId(cellref.mIndexedRefId)) { - std::cerr << "CellRef with no index?" << std::endl; - continue; - } - std::stringstream stream; - stream << cellref.mIndexedRefId.substr(cellref.mIndexedRefId.size()-8,8); - int refIndex; - stream >> refIndex; + // non-indexed RefNum, i.e. no CREC/NPCC/CNTC record associated with it + // this could be any type of object really (even creatures/npcs too) + out.mRefID = cellref.mIndexedRefId; + std::string idLower = Misc::StringUtils::lowerCase(out.mRefID); - out.mRefID = cellref.mIndexedRefId.substr(0,cellref.mIndexedRefId.size()-8); - - std::map, CREC>::const_iterator crecIt = mContext->mCreatureChanges.find( - std::make_pair(refIndex, out.mRefID)); - if (crecIt != mContext->mCreatureChanges.end()) - { - ESM::CreatureState objstate; + ESM::ObjectState objstate; objstate.blank(); objstate.mRef = out; - convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats); - convertCREC(crecIt->second, objstate); + objstate.mRef.mRefID = idLower; + objstate.mHasCustomState = false; convertCellRef(cellref, objstate); - // FIXME: change save format to not require object type, instead look up it up using the RefId - esm.writeHNT ("OBJE", ESM::REC_CREA); + esm.writeHNT ("OBJE", 0); objstate.save(esm); continue; } - - std::map, NPCC>::const_iterator npccIt = mContext->mNpcChanges.find( - std::make_pair(refIndex, out.mRefID)); - if (npccIt != mContext->mNpcChanges.end()) + else { - ESM::NpcState objstate; - objstate.blank(); - objstate.mRef = out; - convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats); - convertNpcData(cellref.mActorData, objstate.mNpcStats); - convertNPCC(npccIt->second, objstate); - convertCellRef(cellref, objstate); - esm.writeHNT ("OBJE", ESM::REC_NPC_); - objstate.save(esm); - continue; - } + std::stringstream stream; + stream << std::hex << cellref.mIndexedRefId.substr(cellref.mIndexedRefId.size()-8,8); + int refIndex; + stream >> refIndex; - std::map, CNTC>::const_iterator cntcIt = mContext->mContainerChanges.find( - std::make_pair(refIndex, out.mRefID)); - if (cntcIt != mContext->mContainerChanges.end()) - { - ESM::ContainerState objstate; - objstate.blank(); - objstate.mRef = out; - convertCNTC(cntcIt->second, objstate); - convertCellRef(cellref, objstate); - esm.writeHNT ("OBJE", ESM::REC_CONT); - objstate.save(esm); - continue; - } + 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( + std::make_pair(refIndex, out.mRefID)); + if (npccIt != mContext->mNpcChanges.end()) + { + ESM::NpcState objstate; + objstate.blank(); + objstate.mRef = out; + objstate.mRef.mRefID = idLower; + // probably need more micromanagement here so we don't overwrite values + // from the ESM with default values + convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats); + convertNpcData(cellref.mActorData, objstate.mNpcStats); + convertNPCC(npccIt->second, objstate); + convertCellRef(cellref, objstate); + esm.writeHNT ("OBJE", ESM::REC_NPC_); + objstate.save(esm); + continue; + } + + std::map, CNTC>::const_iterator cntcIt = mContext->mContainerChanges.find( + std::make_pair(refIndex, out.mRefID)); + if (cntcIt != mContext->mContainerChanges.end()) + { + ESM::ContainerState objstate; + objstate.blank(); + objstate.mRef = out; + objstate.mRef.mRefID = idLower; + convertCNTC(cntcIt->second, objstate); + convertCellRef(cellref, objstate); + esm.writeHNT ("OBJE", ESM::REC_CONT); + objstate.save(esm); + continue; + } - std::cerr << "Can't find type for " << refIndex << " " << out.mRefID << std::endl; + std::map, CREC>::const_iterator crecIt = mContext->mCreatureChanges.find( + std::make_pair(refIndex, out.mRefID)); + if (crecIt != mContext->mCreatureChanges.end()) + { + ESM::CreatureState objstate; + objstate.blank(); + objstate.mRef = out; + objstate.mRef.mRefID = idLower; + convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats); + // probably need more micromanagement here so we don't overwrite values + // from the ESM with default values + convertCREC(crecIt->second, objstate); + convertCellRef(cellref, objstate); + esm.writeHNT ("OBJE", ESM::REC_CREA); + objstate.save(esm); + continue; + } + + std::cerr << "Can't find type for " << cellref.mIndexedRefId << std::endl; + } } esm.endRecord(ESM::REC_CSTA); diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index e758db964..187386b9d 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -167,8 +167,14 @@ public: convertNPCC(npcc, mContext->mPlayer.mObject); } else - mContext->mNpcChanges.insert(std::make_pair(std::make_pair(npcc.mIndex,id), npcc)); + { + int index = mIndexCounter[id]++; + mContext->mNpcChanges.insert(std::make_pair(std::make_pair(index,id), npcc)).second; + } } + +private: + std::map mIndexCounter; }; class ConvertREFR : public Converter @@ -230,7 +236,6 @@ public: std::string id = esm.getHNString("NAME"); CREC crec; crec.load(esm); - mContext->mCreatureChanges.insert(std::make_pair(std::make_pair(crec.mIndex,id), crec)); } }; diff --git a/apps/essimporter/importcellref.cpp b/apps/essimporter/importcellref.cpp index 8c2b8f36d..fd58d5bc1 100644 --- a/apps/essimporter/importcellref.cpp +++ b/apps/essimporter/importcellref.cpp @@ -18,8 +18,13 @@ namespace ESSImport mIndexedRefId = esm.getHNString("NAME"); if (esm.isNextSub("LVCR")) - esm.skipHSub(); - + { + // occurs on leveled creature spawner references + // probably some identifier for the the creature that has been spawned? + unsigned char lvcr; + esm.getHT(lvcr); + //std::cout << "LVCR: " << (int)lvcr << std::endl; + } mActorData.load(esm); mEnabled = true; diff --git a/apps/essimporter/importnpcc.cpp b/apps/essimporter/importnpcc.cpp index 8400a9e4a..c389ede7f 100644 --- a/apps/essimporter/importnpcc.cpp +++ b/apps/essimporter/importnpcc.cpp @@ -7,9 +7,6 @@ namespace ESSImport void NPCC::load(ESM::ESMReader &esm) { - mIndex = 0; - esm.getHNOT(mIndex, "INDX"); - esm.getHNT(mNPDT, "NPDT"); if (esm.isNextSub("AI_E")) diff --git a/apps/essimporter/importnpcc.hpp b/apps/essimporter/importnpcc.hpp index f3c4e24c7..2f474aba0 100644 --- a/apps/essimporter/importnpcc.hpp +++ b/apps/essimporter/importnpcc.hpp @@ -26,8 +26,6 @@ namespace ESSImport Inventory mInventory; - int mIndex; - void load(ESM::ESMReader &esm); }; From 5104a5a0235061454c8aae984e88dce6b928be8c Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 19 Jan 2015 23:55:17 +0100 Subject: [PATCH 242/740] Add missing setFactionReaction instruction, use absolute storage instead of difference Seems to be closer to how MW is storing it (it has the complete FACT record in the savegame, actually). This (somewhat) breaks OMW savegame compatibility in that old changes are discarded, but I don't think the faction reactions are quest relevant anywhere. --- apps/openmw/mwbase/dialoguemanager.hpp | 2 ++ apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 36 ++++++++++++------- apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 4 ++- apps/openmw/mwscript/dialogueextensions.cpp | 20 +++++++++++ apps/openmw/mwscript/docs/vmformat.txt | 3 +- components/compiler/extensions0.cpp | 1 + components/compiler/opcodes.hpp | 1 + components/esm/dialoguestate.cpp | 17 ++++++--- components/esm/dialoguestate.hpp | 2 +- 9 files changed, 66 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwbase/dialoguemanager.hpp b/apps/openmw/mwbase/dialoguemanager.hpp index d0e64b23c..d35b5950f 100644 --- a/apps/openmw/mwbase/dialoguemanager.hpp +++ b/apps/openmw/mwbase/dialoguemanager.hpp @@ -74,6 +74,8 @@ namespace MWBase /// Changes faction1's opinion of faction2 by \a diff. virtual void modFactionReaction (const std::string& faction1, const std::string& faction2, int diff) = 0; + virtual void setFactionReaction (const std::string& faction1, const std::string& faction2, int absolute) = 0; + /// @return faction1's opinion of faction2 virtual int getFactionReaction (const std::string& faction1, const std::string& faction2) const = 0; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index dd0fa21fa..0ee7dfe94 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -640,7 +640,7 @@ namespace MWDialogue if (iter->second) state.mKnownTopics.push_back (iter->first); - state.mModFactionReaction = mModFactionReaction; + state.mChangedFactionReaction = mChangedFactionReaction; writer.startRecord (ESM::REC_DIAS); state.save (writer); @@ -661,7 +661,7 @@ namespace MWDialogue if (store.get().search (*iter)) mKnownTopics.insert (std::make_pair (*iter, true)); - mModFactionReaction = state.mModFactionReaction; + mChangedFactionReaction = state.mChangedFactionReaction; } } @@ -674,10 +674,23 @@ namespace MWDialogue MWBase::Environment::get().getWorld()->getStore().get().find(fact1); MWBase::Environment::get().getWorld()->getStore().get().find(fact2); - std::map& map = mModFactionReaction[fact1]; - if (map.find(fact2) == map.end()) - map[fact2] = 0; - map[fact2] += diff; + int newValue = getFactionReaction(faction1, faction2) + diff; + + std::map& map = mChangedFactionReaction[fact1]; + map[fact2] = newValue; + } + + void DialogueManager::setFactionReaction(const std::string &faction1, const std::string &faction2, int absolute) + { + std::string fact1 = Misc::StringUtils::lowerCase(faction1); + std::string fact2 = Misc::StringUtils::lowerCase(faction2); + + // Make sure the factions exist + MWBase::Environment::get().getWorld()->getStore().get().find(fact1); + MWBase::Environment::get().getWorld()->getStore().get().find(fact2); + + std::map& map = mChangedFactionReaction[fact1]; + map[fact2] = absolute; } int DialogueManager::getFactionReaction(const std::string &faction1, const std::string &faction2) const @@ -685,10 +698,9 @@ namespace MWDialogue std::string fact1 = Misc::StringUtils::lowerCase(faction1); std::string fact2 = Misc::StringUtils::lowerCase(faction2); - ModFactionReactionMap::const_iterator map = mModFactionReaction.find(fact1); - int diff = 0; - if (map != mModFactionReaction.end() && map->second.find(fact2) != map->second.end()) - diff = map->second.at(fact2); + ModFactionReactionMap::const_iterator map = mChangedFactionReaction.find(fact1); + if (map != mChangedFactionReaction.end() && map->second.find(fact2) != map->second.end()) + return map->second.at(fact2); const ESM::Faction* faction = MWBase::Environment::get().getWorld()->getStore().get().find(fact1); @@ -696,9 +708,9 @@ namespace MWDialogue for (; it != faction->mReactions.end(); ++it) { if (Misc::StringUtils::ciEqual(it->first, fact2)) - return it->second + diff; + return it->second; } - return diff; + return 0; } void DialogueManager::clearInfoActor(const MWWorld::Ptr &actor) const diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index 9c3d0d54b..c06299736 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -27,7 +27,7 @@ namespace MWDialogue // Modified faction reactions. > typedef std::map > ModFactionReactionMap; - ModFactionReactionMap mModFactionReaction; + ModFactionReactionMap mChangedFactionReaction; std::list mActorKnownTopics; @@ -97,6 +97,8 @@ namespace MWDialogue /// Changes faction1's opinion of faction2 by \a diff. virtual void modFactionReaction (const std::string& faction1, const std::string& faction2, int diff); + virtual void setFactionReaction (const std::string& faction1, const std::string& faction2, int absolute); + /// @return faction1's opinion of faction2 virtual int getFactionReaction (const std::string& faction1, const std::string& faction2) const; diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index 563a9dde3..1d82b8418 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -236,6 +236,25 @@ namespace MWScript } }; + class OpSetFactionReaction : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + std::string faction1 = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + std::string faction2 = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + int newValue = runtime[0].mInteger; + runtime.pop(); + + MWBase::Environment::get().getDialogueManager()->setFactionReaction(faction1, faction2, newValue); + } + }; + template class OpClearInfoActor : public Interpreter::Opcode0 { @@ -268,6 +287,7 @@ namespace MWScript interpreter.installSegment5 (Compiler::Dialogue::opcodeSameFaction, new OpSameFaction); interpreter.installSegment5 (Compiler::Dialogue::opcodeSameFactionExplicit, new OpSameFaction); interpreter.installSegment5 (Compiler::Dialogue::opcodeModFactionReaction, new OpModFactionReaction); + interpreter.installSegment5 (Compiler::Dialogue::opcodeSetFactionReaction, new OpSetFactionReaction); interpreter.installSegment5 (Compiler::Dialogue::opcodeGetFactionReaction, new OpGetFactionReaction); interpreter.installSegment5 (Compiler::Dialogue::opcodeClearInfoActor, new OpClearInfoActor); interpreter.installSegment5 (Compiler::Dialogue::opcodeClearInfoActorExplicit, new OpClearInfoActor); diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 172e1b528..b139d6138 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -442,5 +442,6 @@ op 0x20002fb: AddToLevCreature op 0x20002fc: RemoveFromLevCreature op 0x20002fd: AddToLevItem op 0x20002fe: RemoveFromLevItem +op 0x20002ff: SetFactionReaction -opcodes 0x20002ff-0x3ffffff unused +opcodes 0x2000300-0x3ffffff unused diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index 234c5b12d..a5cc0da62 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -192,6 +192,7 @@ namespace Compiler extensions.registerFunction("samefaction", 'l', "", opcodeSameFaction, opcodeSameFactionExplicit); extensions.registerInstruction("modfactionreaction", "ccl", opcodeModFactionReaction); + extensions.registerInstruction("setfactionreaction", "ccl", opcodeSetFactionReaction); extensions.registerFunction("getfactionreaction", 'l', "ccX", opcodeGetFactionReaction); extensions.registerInstruction("clearinfoactor", "", opcodeClearInfoActor, opcodeClearInfoActorExplicit); } diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index bbafd6b13..04666e976 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -167,6 +167,7 @@ namespace Compiler const int opcodeSameFaction = 0x20001b5; const int opcodeSameFactionExplicit = 0x20001b6; const int opcodeModFactionReaction = 0x2000242; + const int opcodeSetFactionReaction = 0x20002ff; const int opcodeGetFactionReaction = 0x2000243; const int opcodeClearInfoActor = 0x2000245; const int opcodeClearInfoActorExplicit = 0x2000246; diff --git a/components/esm/dialoguestate.cpp b/components/esm/dialoguestate.cpp index 14301ac19..f546462a3 100644 --- a/components/esm/dialoguestate.cpp +++ b/components/esm/dialoguestate.cpp @@ -13,13 +13,20 @@ void ESM::DialogueState::load (ESMReader &esm) { std::string faction = esm.getHString(); - while (esm.isNextSub ("REAC")) + while (esm.isNextSub("REA2")) { std::string faction2 = esm.getHString(); int reaction; esm.getHNT(reaction, "INTV"); + mChangedFactionReaction[faction][faction2] = reaction; + } - mModFactionReaction[faction][faction2] = reaction; + // no longer used + while (esm.isNextSub ("REAC")) + { + esm.skipHSub(); + esm.getSubHeader(); + esm.skipHSub(); } } } @@ -32,15 +39,15 @@ void ESM::DialogueState::save (ESMWriter &esm) const esm.writeHNString ("TOPI", *iter); } - for (std::map >::const_iterator iter = mModFactionReaction.begin(); - iter != mModFactionReaction.end(); ++iter) + for (std::map >::const_iterator iter = mChangedFactionReaction.begin(); + iter != mChangedFactionReaction.end(); ++iter) { esm.writeHNString ("FACT", iter->first); for (std::map::const_iterator reactIter = iter->second.begin(); reactIter != iter->second.end(); ++reactIter) { - esm.writeHNString ("REAC", reactIter->first); + esm.writeHNString ("REA2", reactIter->first); esm.writeHNT ("INTV", reactIter->second); } } diff --git a/components/esm/dialoguestate.hpp b/components/esm/dialoguestate.hpp index 5e5f602a3..1adade5a0 100644 --- a/components/esm/dialoguestate.hpp +++ b/components/esm/dialoguestate.hpp @@ -16,7 +16,7 @@ namespace ESM { std::vector mKnownTopics; - std::map > mModFactionReaction; + std::map > mChangedFactionReaction; void load (ESMReader &esm); void save (ESMWriter &esm) const; From 6d5bb57e00ea23f573731f7ed15f31f928a76576 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 20 Jan 2015 01:21:44 +0100 Subject: [PATCH 243/740] ESSImport: fix loading item stacks in containers --- apps/essimporter/importinventory.cpp | 43 ++++++++++++++++------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/apps/essimporter/importinventory.cpp b/apps/essimporter/importinventory.cpp index b3bd4a86b..b4d193540 100644 --- a/apps/essimporter/importinventory.cpp +++ b/apps/essimporter/importinventory.cpp @@ -18,28 +18,35 @@ namespace ESSImport item.mId = contItem.mItem.toString(); item.mCount = contItem.mCount; - if (esm.isNextSub("XIDX")) - esm.skipHSub(); - - std::string script = esm.getHNOString("SCRI"); - // script variables? - // unsure if before or after ESM::CellRef - if (!script.empty()) + // seems that a stack of items can have a set of subrecords for each item? rings0000.ess + // doesn't make any sense to me, if the values were different then the items shouldn't stack in the first place? + // I guess we should double check the stacking logic in OpenMW + for (int i=0;i Date: Tue, 20 Jan 2015 15:24:33 +0100 Subject: [PATCH 244/740] Fix broken windows builds due to README change --- CMakeLists.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0bbce7ad4..938162b01 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -457,8 +457,9 @@ if(WIN32) FILE(GLOB dll_files "${OpenMW_BINARY_DIR}/Release/*.dll") INSTALL(FILES ${dll_files} DESTINATION ".") INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg") + INSTALL(FILES "${OpenMW_SOURCE_DIR}/CHANGELOG.md" DESTINATION "." RENAME "CHANGELOG.txt") + INSTALL(FILES "${OpenMW_SOURCE_DIR}/README.md" DESTINATION "." RENAME "README.txt") INSTALL(FILES - "${OpenMW_SOURCE_DIR}/readme.txt" "${OpenMW_SOURCE_DIR}/Docs/license/GPL3.txt" "${OpenMW_SOURCE_DIR}/Docs/license/DejaVu Font License.txt" "${OpenMW_BINARY_DIR}/settings-default.cfg" @@ -502,13 +503,13 @@ if(WIN32) IF(BUILD_WIZARD) SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};openmw-wizard;OpenMW Wizard") ENDIF(BUILD_WIZARD) - SET(CPACK_NSIS_CREATE_ICONS_EXTRA "CreateShortCut '\$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Readme.lnk' '\$INSTDIR\\\\readme.txt'") + SET(CPACK_NSIS_CREATE_ICONS_EXTRA "CreateShortCut '\$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Readme.lnk' '\$INSTDIR\\\\README.txt'") SET(CPACK_NSIS_DELETE_ICONS_EXTRA " !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP Delete \\\"$SMPROGRAMS\\\\$MUI_TEMP\\\\Readme.lnk\\\" ") - SET(CPACK_RESOURCE_FILE_README "${OpenMW_SOURCE_DIR}/readme.txt") - SET(CPACK_PACKAGE_DESCRIPTION_FILE "${OpenMW_SOURCE_DIR}/readme.txt") + SET(CPACK_RESOURCE_FILE_README "${OpenMW_SOURCE_DIR}/README.md") + SET(CPACK_PACKAGE_DESCRIPTION_FILE "${OpenMW_SOURCE_DIR}/README.md") SET(CPACK_NSIS_EXECUTABLES_DIRECTORY ".") SET(CPACK_NSIS_DISPLAY_NAME "OpenMW ${OPENMW_VERSION}") SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\www.openmw.org") From 06736e9e0317037c0095971caff2213a9a94fa29 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 20 Jan 2015 01:28:34 +0100 Subject: [PATCH 245/740] ESSImport: convert faction reactions and known dialogue topics --- apps/essimporter/converter.hpp | 26 ++++++++++++++++++++++++++ apps/essimporter/importer.cpp | 7 +++++++ apps/essimporter/importercontext.hpp | 3 +++ apps/essimporter/importplayer.cpp | 1 - components/esm/dialoguestate.hpp | 2 ++ 5 files changed, 38 insertions(+), 1 deletion(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 187386b9d..62729cd03 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include "importcrec.hpp" @@ -214,6 +216,12 @@ public: mContext->mPlayer.mObject.mNpcStats.mFactions[it->mFactionName.toString()] = faction; } + for (std::vector::const_iterator it = pcdt.mKnownDialogueTopics.begin(); + it != pcdt.mKnownDialogueTopics.end(); ++it) + { + mContext->mDialogueState.mKnownTopics.push_back(Misc::StringUtils::lowerCase(*it)); + } + } }; @@ -295,6 +303,24 @@ private: std::map mKillCounter; }; +class ConvertFACT : public Converter +{ +public: + virtual void read(ESM::ESMReader& esm) + { + std::string id = esm.getHNString("NAME"); + ESM::Faction faction; + faction.load(esm); + + Misc::StringUtils::toLower(id); + for (std::map::const_iterator it = faction.mReactions.begin(); it != faction.mReactions.end(); ++it) + { + std::string faction2 = Misc::StringUtils::lowerCase(it->first); + mContext->mDialogueState.mChangedFactionReaction[id].insert(std::make_pair(faction2, it->second)); + } + } +}; + } #endif diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 9075db404..e73aaafae 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -181,6 +181,8 @@ namespace ESSImport Ogre::LogManager logman; Ogre::Root root; + // TODO: set up encoding on ESMReader based on openmw.cfg / --encoding switch + ESM::ESMReader esm; esm.open(mEssFile); @@ -216,6 +218,7 @@ namespace ESSImport converters[ESM::REC_LEVC] = boost::shared_ptr(new DefaultConverter()); converters[ESM::REC_LEVI] = boost::shared_ptr(new DefaultConverter()); converters[ESM::REC_CNTC] = boost::shared_ptr(new ConvertCNTC()); + converters[ESM::REC_FACT] = boost::shared_ptr(new ConvertFACT()); std::set unknownRecords; @@ -322,6 +325,10 @@ namespace ESSImport } context.mPlayer.save(writer); writer.endRecord(ESM::REC_PLAY); + + 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 a921b81ef..02585799a 100644 --- a/apps/essimporter/importercontext.hpp +++ b/apps/essimporter/importercontext.hpp @@ -5,6 +5,7 @@ #include #include +#include #include "importnpcc.hpp" #include "importcrec.hpp" @@ -25,6 +26,8 @@ namespace ESSImport ESM::NPC mPlayerBase; std::string mCustomPlayerClassName; + ESM::DialogueState mDialogueState; + int mDay, mMonth, mYear; float mHour; diff --git a/apps/essimporter/importplayer.cpp b/apps/essimporter/importplayer.cpp index 8a57ae588..f94d3aacc 100644 --- a/apps/essimporter/importplayer.cpp +++ b/apps/essimporter/importplayer.cpp @@ -20,7 +20,6 @@ namespace ESSImport { while (esm.isNextSub("DNAM")) { - // TODO: deal with encoding? mKnownDialogueTopics.push_back(esm.getHString()); } diff --git a/components/esm/dialoguestate.hpp b/components/esm/dialoguestate.hpp index 1adade5a0..d7cdb941c 100644 --- a/components/esm/dialoguestate.hpp +++ b/components/esm/dialoguestate.hpp @@ -14,8 +14,10 @@ namespace ESM struct DialogueState { + // must be lower case topic IDs std::vector mKnownTopics; + // must be lower case faction IDs std::map > mChangedFactionReaction; void load (ESMReader &esm); From 25ff45d819290feaa25a344ffdd491509a25083c Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 20 Jan 2015 15:44:47 +0100 Subject: [PATCH 246/740] Update command line options in Readme --- README.md | 51 +++++++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index bb59b7e02..7c24a4c81 100644 --- a/README.md +++ b/README.md @@ -41,51 +41,58 @@ Command line options --version print version information and quit --data arg (=data) set data directories (later directories have higher priority) - --data-local arg set local data directory (highest + --data-local arg set local data directory (highest priority) --fallback-archive arg (=fallback-archive) - set fallback BSA archives (later + set fallback BSA archives (later archives have higher priority) --resources arg (=resources) set resources directory - --start arg (=Beshara) set initial cell - --content arg content file(s): esm/esp, or + --start arg set initial cell + --content arg content file(s): esm/esp, or omwgame/omwaddon - --anim-verbose [=arg(=1)] (=0) output animation indices files --no-sound [=arg(=1)] (=0) disable all sounds --script-verbose [=arg(=1)] (=0) verbose script output --script-all [=arg(=1)] (=0) compile all scripts (excluding dialogue scripts) at startup - --script-console [=arg(=1)] (=0) enable console-only script + --script-all-dialogue [=arg(=1)] (=0) compile all dialogue scripts at startup + --script-console [=arg(=1)] (=0) enable console-only script functionality - --script-run arg select a file containing a list of - console commands that is executed on + --script-run arg select a file containing a list of + console commands that is executed on startup - --script-warn [=arg(=1)] (=1) handling of warnings when compiling + --script-warn [=arg(=1)] (=1) handling of warnings when compiling scripts 0 - ignore warning 1 - show warning but consider script as correctly compiled anyway 2 - treat warnings as errors + --script-blacklist arg ignore the specified script (if the use + of the blacklist is enabled) + --script-blacklist-use [=arg(=1)] (=1) + enable script blacklisting + --load-savegame arg load a save game file on game startup --skip-menu [=arg(=1)] (=0) skip main menu on game startup - --new-game [=arg(=1)] (=0) run new game sequence (ignored if + --new-game [=arg(=1)] (=0) run new game sequence (ignored if skip-menu=0) - --fs-strict [=arg(=1)] (=0) strict file system handling (no case + --fs-strict [=arg(=1)] (=0) strict file system handling (no case folding) - --encoding arg (=win1252) Character encoding used in OpenMW game + --encoding arg (=win1252) Character encoding used in OpenMW game messages: - - win1250 - Central and Eastern European - such as Polish, Czech, Slovak, - Hungarian, Slovene, Bosnian, Croatian, - Serbian (Latin script), Romanian and + + win1250 - Central and Eastern European + such as Polish, Czech, Slovak, + Hungarian, Slovene, Bosnian, Croatian, + Serbian (Latin script), Romanian and Albanian languages - - win1251 - Cyrillic alphabet such as - Russian, Bulgarian, Serbian Cyrillic + + win1251 - Cyrillic alphabet such as + Russian, Bulgarian, Serbian Cyrillic and other languages - - win1252 - Western European (Latin) + + win1252 - Western European (Latin) alphabet, used by default --fallback arg fallback values --no-grab Don't grab mouse cursor + --export-fonts [=arg(=1)] (=0) Export Morrowind .fnt fonts to PNG + image and XML file in current directory --activate-dist arg (=-1) activation distance override From 3a88f4ebd5fbaadae05b74a604399d78157392da Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 20 Jan 2015 17:07:26 +0100 Subject: [PATCH 247/740] Fix windows build, MessageBox is a defined symbol Windows and its stupid defines... --- apps/openmw/mwgui/messagebox.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 9cb778ea2..cdbcf784d 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -12,6 +12,8 @@ #include "../mwbase/inputmanager.hpp" #include "../mwbase/windowmanager.hpp" +#undef MessageBox + namespace MWGui { From 1375a4e4bb36ac144ba9511451feb1669783b1a3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 20 Jan 2015 16:06:15 +0100 Subject: [PATCH 248/740] ESSImport: read stolen items (not converted yet) --- apps/essimporter/converter.hpp | 24 ++++++++++++++++++++++++ apps/essimporter/importer.cpp | 10 ++++++---- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 62729cd03..716ddc9c7 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -321,6 +321,30 @@ public: } }; +/// Stolen items +class ConvertSTLN : public Converter +{ +public: + virtual void read(ESM::ESMReader &esm) + { + std::string itemid = esm.getHNString("NAME"); + + while (esm.isNextSub("ONAM")) + { + std::string ownerid = esm.getHString(); + mStolenItems.insert(std::make_pair(itemid, ownerid)); + } + while (esm.isNextSub("FNAM")) + { + std::string factionid = esm.getHString(); + mFactionStolenItems.insert(std::make_pair(itemid, factionid)); + } + } +private: + std::multimap mStolenItems; + std::multimap mFactionStolenItems; +}; + } #endif diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index e73aaafae..699725d67 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -195,6 +195,7 @@ namespace ESSImport const unsigned int recPCDT = ESM::FourCC<'P','C','D','T'>::value; const unsigned int recFMAP = ESM::FourCC<'F','M','A','P'>::value; const unsigned int recKLST = ESM::FourCC<'K','L','S','T'>::value; + const unsigned int recSTLN = ESM::FourCC<'S','T','L','N'>::value; std::map > converters; converters[ESM::REC_GLOB] = boost::shared_ptr(new ConvertGlobal()); @@ -202,10 +203,11 @@ namespace ESSImport converters[ESM::REC_NPC_] = boost::shared_ptr(new ConvertNPC()); converters[ESM::REC_NPCC] = boost::shared_ptr(new ConvertNPCC()); converters[ESM::REC_CREC] = boost::shared_ptr(new ConvertCREC()); - converters[recREFR] = boost::shared_ptr(new ConvertREFR()); - converters[recPCDT] = boost::shared_ptr(new ConvertPCDT()); - converters[recFMAP] = boost::shared_ptr(new ConvertFMAP()); - converters[recKLST] = boost::shared_ptr(new ConvertKLST()); + converters[recREFR ] = boost::shared_ptr(new ConvertREFR()); + converters[recPCDT ] = boost::shared_ptr(new ConvertPCDT()); + converters[recFMAP ] = boost::shared_ptr(new ConvertFMAP()); + converters[recKLST ] = boost::shared_ptr(new ConvertKLST()); + converters[recSTLN ] = boost::shared_ptr(new ConvertSTLN()); converters[ESM::REC_CELL] = boost::shared_ptr(new ConvertCell()); converters[ESM::REC_ALCH] = boost::shared_ptr(new DefaultConverter()); converters[ESM::REC_CLAS] = boost::shared_ptr(new ConvertClass()); From 0fc9221eb36058ccb31e4fb57f09cc1a1a3bc2fb Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 20 Jan 2015 18:22:02 +0100 Subject: [PATCH 249/740] ESSImport: convert NPC disposition --- apps/essimporter/convertnpcc.cpp | 1 + apps/essimporter/importnpcc.hpp | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/essimporter/convertnpcc.cpp b/apps/essimporter/convertnpcc.cpp index 2155f46fb..48d3d9232 100644 --- a/apps/essimporter/convertnpcc.cpp +++ b/apps/essimporter/convertnpcc.cpp @@ -7,6 +7,7 @@ namespace ESSImport void convertNPCC(const NPCC &npcc, ESM::NpcState &npcState) { + npcState.mNpcStats.mDisposition = npcc.mNPDT.mDisposition; npcState.mNpcStats.mReputation = npcc.mNPDT.mReputation; convertInventory(npcc.mInventory, npcState.mInventory); diff --git a/apps/essimporter/importnpcc.hpp b/apps/essimporter/importnpcc.hpp index 2f474aba0..ee8eccda2 100644 --- a/apps/essimporter/importnpcc.hpp +++ b/apps/essimporter/importnpcc.hpp @@ -19,7 +19,8 @@ namespace ESSImport { struct NPDT { - unsigned char unknown[2]; + unsigned char mDisposition; + unsigned char unknown; unsigned char mReputation; unsigned char unknown2[5]; } mNPDT; From d473629dcd6aa6e04d53accc2e7a69314b8fa79c Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 20 Jan 2015 19:12:07 +0100 Subject: [PATCH 250/740] Improve ESMReader error messages --- components/esm/esmreader.cpp | 6 +++++- components/esm/esmreader.hpp | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index de110dd18..3c43d067f 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -134,7 +134,11 @@ void ESMReader::getHExact(void*p, int size) { getSubHeader(); if (size != static_cast (mCtx.leftSub)) - fail("getHExact() size mismatch"); + { + std::stringstream error; + error << "getHExact(): size mismatch (requested " << size << ", got " << mCtx.leftSub << ")"; + fail(error.str()); + } getExact(p, size); } diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index bb615af11..e7721bb8f 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -137,7 +137,11 @@ public: { getSubHeader(); if (mCtx.leftSub != sizeof(X)) - fail("getHT(): subrecord size mismatch"); + { + std::stringstream error; + error << "getHT(): subrecord size mismatch (requested " << sizeof(X) << ", got " << mCtx.leftSub << ")"; + fail(error.str()); + } getT(x); } From eede2c8e55fe9579dd8e746385be2a794ce969bb Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 20 Jan 2015 19:30:39 +0100 Subject: [PATCH 251/740] ESSImport: convert breath meter and skill increases --- apps/essimporter/convertacdt.cpp | 2 ++ apps/essimporter/converter.hpp | 2 ++ apps/essimporter/importacdt.hpp | 16 +++++++++++++--- apps/essimporter/importer.cpp | 5 +++++ apps/essimporter/importplayer.cpp | 4 ++-- apps/essimporter/importplayer.hpp | 11 +++++++++++ apps/openmw/mwmechanics/npcstats.hpp | 22 +++++++++++----------- 7 files changed, 46 insertions(+), 16 deletions(-) diff --git a/apps/essimporter/convertacdt.cpp b/apps/essimporter/convertacdt.cpp index 81ab61084..af66ec272 100644 --- a/apps/essimporter/convertacdt.cpp +++ b/apps/essimporter/convertacdt.cpp @@ -37,6 +37,8 @@ namespace ESSImport npcStats.mSkills[i].mRegular.mCurrent = actorData.mSkills[i][1]; npcStats.mSkills[i].mRegular.mBase = actorData.mSkills[i][0]; } + + npcStats.mTimeToStartDrowning = actorData.mACDT.mBreathMeter; } } diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 716ddc9c7..23b0434b1 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -215,6 +215,8 @@ public: faction.mReputation = it->mReputation; mContext->mPlayer.mObject.mNpcStats.mFactions[it->mFactionName.toString()] = faction; } + for (int i=0; i<8; ++i) + mContext->mPlayer.mObject.mNpcStats.mSkillIncrease[i] = pcdt.mPNAM.mSkillIncreases[i]; for (std::vector::const_iterator it = pcdt.mKnownDialogueTopics.begin(); it != pcdt.mKnownDialogueTopics.end(); ++it) diff --git a/apps/essimporter/importacdt.hpp b/apps/essimporter/importacdt.hpp index 6efae9dc5..cf72b5cf7 100644 --- a/apps/essimporter/importacdt.hpp +++ b/apps/essimporter/importacdt.hpp @@ -13,14 +13,24 @@ namespace ESSImport /// Actor data, shared by (at least) REFR and CellRef +#pragma pack(push) +#pragma pack(1) struct ACDT { - unsigned char mUnknown1[40]; + // Note, not stored at *all*: + // - Level changes are lost on reload, except for the player (there it's in the NPC record). + unsigned char mUnknown1[16]; + float mBreathMeter; // Seconds left before drowning + unsigned char mUnknown2[20]; float mDynamic[3][2]; - unsigned char mUnknown2[16]; + unsigned char mUnknown3[16]; float mAttributes[8][2]; - unsigned char mUnknown3[120]; + unsigned char mUnknown4[109]; + // This seems to increase when purchasing training, though I don't see it anywhere ingame. + int mGold; + unsigned char mUnknown5[7]; }; +#pragma pack(pop) struct ActorData { diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 699725d67..c2092ea4d 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -104,6 +104,11 @@ namespace ESSImport blacklist.insert(std::make_pair("GLOB", "FLTV")); // gamehour blacklist.insert(std::make_pair("REFR", "DATA")); // player position blacklist.insert(std::make_pair("CELL", "NAM8")); // fog of war + blacklist.insert(std::make_pair("GAME", "GMDT")); // weather data, current time always changes + + // this changes way too often, name suggests some renderer internal data? + blacklist.insert(std::make_pair("CELL", "ND3D")); + blacklist.insert(std::make_pair("REFR", "ND3D")); File file1; read(mEssFile, file1); diff --git a/apps/essimporter/importplayer.cpp b/apps/essimporter/importplayer.cpp index f94d3aacc..285605068 100644 --- a/apps/essimporter/importplayer.cpp +++ b/apps/essimporter/importplayer.cpp @@ -23,8 +23,8 @@ namespace ESSImport mKnownDialogueTopics.push_back(esm.getHString()); } - if (esm.isNextSub("PNAM")) - esm.skipHSub(); + esm.getHNT(mPNAM, "PNAM"); + if (esm.isNextSub("SNAM")) esm.skipHSub(); if (esm.isNextSub("NAM9")) diff --git a/apps/essimporter/importplayer.hpp b/apps/essimporter/importplayer.hpp index af8625fa6..2bd55ef73 100644 --- a/apps/essimporter/importplayer.hpp +++ b/apps/essimporter/importplayer.hpp @@ -38,6 +38,8 @@ struct PCDT std::vector mKnownDialogueTopics; +#pragma pack(push) +#pragma pack(1) struct FNAM { unsigned char mRank; @@ -47,7 +49,16 @@ struct PCDT unsigned char mUnknown2[3]; ESM::NAME32 mFactionName; }; + struct PNAM + { + unsigned char mUnknown1[116]; + unsigned char mSkillIncreases[8]; // number of skill increases for each attribute + unsigned char mUnknown2[88]; + }; +#pragma pack(pop) + std::vector mFactions; + PNAM mPNAM; void load(ESM::ESMReader& esm); }; diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index 4594492e1..9e543bb79 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -22,27 +22,27 @@ namespace MWMechanics class NpcStats : public CreatureStats { - /// NPCs other than the player can only have one faction. But for the sake of consistency - /// we use the same data structure for the PC and the NPCs. - /// \note the faction key must be in lowercase - std::map mFactionRank; - int mDisposition; SkillValue mSkill[ESM::Skill::Length]; SkillValue mWerewolfSkill[ESM::Skill::Length]; - int mBounty; - std::set mExpelled; - std::map mFactionReputation; int mReputation; int mCrimeId; - int mWerewolfKills; + int mProfit; + // ----- used by the player only, maybe should be moved at some point ------- + int mBounty; + int mWerewolfKills; + /// NPCs other than the player can only have one faction. But for the sake of consistency + /// we use the same data structure for the PC and the NPCs. + /// \note the faction key must be in lowercase + std::map mFactionRank; + std::set mExpelled; + std::map mFactionReputation; int mLevelProgress; // 0-10 - std::vector mSkillIncreases; // number of skill increases for each attribute - std::set mUsedIds; + // --------------------------------------------------------------------------- /// Countdown to getting damage while underwater float mTimeToStartDrowning; From 5b705196bc11acb9e471ad96c6eb928bbe5bad3e Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 20 Jan 2015 19:47:54 +0100 Subject: [PATCH 252/740] ESSImport: convert level progress --- apps/essimporter/converter.hpp | 1 + apps/essimporter/importplayer.hpp | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 23b0434b1..920e6eead 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -217,6 +217,7 @@ public: } for (int i=0; i<8; ++i) mContext->mPlayer.mObject.mNpcStats.mSkillIncrease[i] = pcdt.mPNAM.mSkillIncreases[i]; + mContext->mPlayer.mObject.mNpcStats.mLevelProgress = pcdt.mPNAM.mLevelProgress; for (std::vector::const_iterator it = pcdt.mKnownDialogueTopics.begin(); it != pcdt.mKnownDialogueTopics.end(); ++it) diff --git a/apps/essimporter/importplayer.hpp b/apps/essimporter/importplayer.hpp index 2bd55ef73..64ceddfd7 100644 --- a/apps/essimporter/importplayer.hpp +++ b/apps/essimporter/importplayer.hpp @@ -51,9 +51,11 @@ struct PCDT }; struct PNAM { - unsigned char mUnknown1[116]; + unsigned char mUnknown1[4]; + unsigned char mLevelProgress; + unsigned char mUnknown2[111]; unsigned char mSkillIncreases[8]; // number of skill increases for each attribute - unsigned char mUnknown2[88]; + unsigned char mUnknown3[88]; }; #pragma pack(pop) From e38d75634505ea77173d492ee90fff5e0a347128 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 20 Jan 2015 20:18:30 +0100 Subject: [PATCH 253/740] ESSImport: fix NPCC indices --- apps/essimporter/converter.cpp | 6 +++++- apps/essimporter/converter.hpp | 5 +---- apps/essimporter/importnpcc.hpp | 3 ++- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 83ea077ea..099987762 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -1,5 +1,7 @@ #include "converter.hpp" +#include + #include #include @@ -281,7 +283,9 @@ namespace ESSImport continue; } - std::cerr << "Can't find type for " << cellref.mIndexedRefId << std::endl; + std::stringstream error; + error << "Can't find type for " << cellref.mIndexedRefId << std::endl; + throw std::runtime_error(error.str()); } } diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 920e6eead..b68f9a218 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -170,13 +170,10 @@ public: } else { - int index = mIndexCounter[id]++; + int index = npcc.mNPDT.mIndex; mContext->mNpcChanges.insert(std::make_pair(std::make_pair(index,id), npcc)).second; } } - -private: - std::map mIndexCounter; }; class ConvertREFR : public Converter diff --git a/apps/essimporter/importnpcc.hpp b/apps/essimporter/importnpcc.hpp index ee8eccda2..c69fa3e03 100644 --- a/apps/essimporter/importnpcc.hpp +++ b/apps/essimporter/importnpcc.hpp @@ -22,7 +22,8 @@ namespace ESSImport unsigned char mDisposition; unsigned char unknown; unsigned char mReputation; - unsigned char unknown2[5]; + unsigned char unknown2; + int mIndex; } mNPDT; Inventory mInventory; From 142a138b75e3391963ce109b216c7eb625a441b7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 20 Jan 2015 20:19:08 +0100 Subject: [PATCH 254/740] ESSImport: convert TalkedTo flag and gold pool --- apps/essimporter/convertacdt.cpp | 2 ++ apps/essimporter/importacdt.cpp | 3 ++- apps/essimporter/importacdt.hpp | 15 ++++++++++----- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/apps/essimporter/convertacdt.cpp b/apps/essimporter/convertacdt.cpp index af66ec272..496eab9e9 100644 --- a/apps/essimporter/convertacdt.cpp +++ b/apps/essimporter/convertacdt.cpp @@ -27,6 +27,8 @@ namespace ESSImport cStats.mAttributes[i].mMod = acdt.mAttributes[i][0]; cStats.mAttributes[i].mCurrent = acdt.mAttributes[i][0]; } + cStats.mGoldPool = acdt.mGoldPool; + cStats.mTalkedTo = acdt.mFlags & TalkedToPlayer; } void convertNpcData (const ActorData& actorData, ESM::NpcStats& npcStats) diff --git a/apps/essimporter/importacdt.cpp b/apps/essimporter/importacdt.cpp index d961720a7..84c800897 100644 --- a/apps/essimporter/importacdt.cpp +++ b/apps/essimporter/importacdt.cpp @@ -22,7 +22,7 @@ namespace ESSImport ESM::CellRef bla; bla.ESM::CellRef::loadData(esm); - // FIXME: actually should be required for all actors?, but ActorData is currently in base CellRef + // FIXME: not all actors have this, add flag esm.getHNOT(mACDT, "ACDT"); ACSC acsc; @@ -76,6 +76,7 @@ namespace ESSImport esm.skipHSub(); // 4 byte, 0 } + // FIXME: not all actors have this, add flag if (esm.isNextSub("CHRD")) // npc only esm.getHExact(mSkills, 27*2*sizeof(int)); diff --git a/apps/essimporter/importacdt.hpp b/apps/essimporter/importacdt.hpp index cf72b5cf7..79f67d2c2 100644 --- a/apps/essimporter/importacdt.hpp +++ b/apps/essimporter/importacdt.hpp @@ -11,6 +11,10 @@ namespace ESM namespace ESSImport { + enum ACDTFlags + { + TalkedToPlayer = 0x4 + }; /// Actor data, shared by (at least) REFR and CellRef #pragma pack(push) @@ -19,16 +23,17 @@ namespace ESSImport { // Note, not stored at *all*: // - Level changes are lost on reload, except for the player (there it's in the NPC record). - unsigned char mUnknown1[16]; + unsigned char mUnknown[12]; + unsigned char mFlags; // ACDTFlags + unsigned char mUnknown1[3]; float mBreathMeter; // Seconds left before drowning unsigned char mUnknown2[20]; float mDynamic[3][2]; unsigned char mUnknown3[16]; float mAttributes[8][2]; - unsigned char mUnknown4[109]; - // This seems to increase when purchasing training, though I don't see it anywhere ingame. - int mGold; - unsigned char mUnknown5[7]; + unsigned char mUnknown4[112]; + unsigned int mGoldPool; + unsigned char mUnknown5[4]; }; #pragma pack(pop) From 89d9649b50b2b6e102b90517a5b136cc74415ba0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 20 Jan 2015 23:55:26 +0100 Subject: [PATCH 255/740] Change save format to store relative equipment index Store the index for the allowedSlots vector instead of the absolute slot index. This will more gracefully handle edge cases like the available slots for an item having changed when loading the game, or the "allows stacking" property having changed. However the main reason this was done is to ease work on the essimporter. --- apps/openmw/mwworld/cellstore.cpp | 2 +- apps/openmw/mwworld/containerstore.cpp | 27 ++++++++++---------- apps/openmw/mwworld/containerstore.hpp | 12 +++++---- apps/openmw/mwworld/inventorystore.cpp | 35 ++++++++++++++++++++------ apps/openmw/mwworld/inventorystore.hpp | 6 ++--- apps/openmw/mwworld/worldimp.cpp | 4 +-- components/esm/inventorystate.hpp | 1 + 7 files changed, 56 insertions(+), 31 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 605c8f9d2..545bbd4b3 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -466,7 +466,7 @@ namespace MWWorld // List moved references, from separately tracked list. for (ESM::CellRefTracker::const_iterator it = mCell->mLeasedRefs.begin(); it != mCell->mLeasedRefs.end(); ++it) { - ESM::CellRef &ref = const_cast(*it); + const ESM::CellRef &ref = *it; mIds.push_back(Misc::StringUtils::lowerCase(ref.mRefID)); } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index bd14720f7..5911b45f7 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -85,28 +85,29 @@ void MWWorld::ContainerStore::storeState (const LiveCellRef& ref, ESM::Object ref.save (state); } +/// \todo make this method const once const-correct ContainerStoreIterators are available template -void MWWorld::ContainerStore::storeStates (const CellRefList& collection, - std::vector >& states, bool equipable) const +void MWWorld::ContainerStore::storeStates (CellRefList& collection, + std::vector >& states, bool equipable) { - for (typename CellRefList::List::const_iterator iter (collection.mList.begin()); + for (typename CellRefList::List::iterator iter (collection.mList.begin()); iter!=collection.mList.end(); ++iter) { if (iter->mData.getCount() == 0) continue; ESM::ObjectState state; storeState (*iter, state); - int slot = equipable ? getSlot (*iter) : -1; + int slot = equipable ? getRelativeSlot (MWWorld::ContainerStoreIterator(this, iter)) : -1; states.push_back (std::make_pair (state, slot)); } } -int MWWorld::ContainerStore::getSlot (const MWWorld::LiveCellRefBase& ref) const +int MWWorld::ContainerStore::getRelativeSlot (const MWWorld::ContainerStoreIterator& iter) const { return -1; } -void MWWorld::ContainerStore::setSlot (const MWWorld::ContainerStoreIterator& iter, int slot) {} +void MWWorld::ContainerStore::setRelativeSlot (const MWWorld::ContainerStoreIterator& iter, int slot) {} const std::string MWWorld::ContainerStore::sGoldId = "gold_001"; @@ -641,7 +642,7 @@ MWWorld::Ptr MWWorld::ContainerStore::search (const std::string& id) return Ptr(); } -void MWWorld::ContainerStore::writeState (ESM::InventoryState& state) const +void MWWorld::ContainerStore::writeState (ESM::InventoryState& state) { state.mItems.clear(); @@ -678,16 +679,16 @@ void MWWorld::ContainerStore::readState (const ESM::InventoryState& state) { case ESM::REC_ALCH: getState (potions, iter->first); break; case ESM::REC_APPA: getState (appas, iter->first); break; - case ESM::REC_ARMO: setSlot (getState (armors, iter->first), slot); break; + case ESM::REC_ARMO: setRelativeSlot (getState (armors, iter->first), slot); break; case ESM::REC_BOOK: getState (books, iter->first); break; - case ESM::REC_CLOT: setSlot (getState (clothes, iter->first), slot); break; + case ESM::REC_CLOT: setRelativeSlot (getState (clothes, iter->first), slot); break; case ESM::REC_INGR: getState (ingreds, iter->first); break; - case ESM::REC_LOCK: setSlot (getState (lockpicks, iter->first), slot); break; + case ESM::REC_LOCK: setRelativeSlot (getState (lockpicks, iter->first), slot); break; case ESM::REC_MISC: getState (miscItems, iter->first); break; - case ESM::REC_PROB: setSlot (getState (probes, iter->first), slot); break; + case ESM::REC_PROB: setRelativeSlot (getState (probes, iter->first), slot); break; case ESM::REC_REPA: getState (repairs, iter->first); break; - case ESM::REC_WEAP: setSlot (getState (weapons, iter->first), slot); break; - case ESM::REC_LIGH: setSlot (getState (lights, iter->first), slot); break; + case ESM::REC_WEAP: setRelativeSlot (getState (weapons, iter->first), slot); break; + case ESM::REC_LIGH: setRelativeSlot (getState (lights, iter->first), slot); break; default: std::cerr << "invalid item type in inventory state, refid " << state.mRef.mRefID << std::endl; diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 68ee41a1d..4a95606f7 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -84,15 +84,16 @@ namespace MWWorld template void storeState (const LiveCellRef& ref, ESM::ObjectState& state) const; + /// \todo make this method const once const-correct ContainerStoreIterators are available template - void storeStates (const CellRefList& collection, + void storeStates (CellRefList& collection, std::vector >& states, - bool equipable = false) const; + bool equipable = false); - virtual int getSlot (const MWWorld::LiveCellRefBase& ref) const; + virtual int getRelativeSlot (const MWWorld::ContainerStoreIterator& iter) const; ///< Return inventory slot that \a ref is in or -1 (if \a ref is not in a slot). - virtual void setSlot (const MWWorld::ContainerStoreIterator& iter, int slot); + virtual void setRelativeSlot (const MWWorld::ContainerStoreIterator& iter, int slot); ///< Set slot for \a iter. Ignored if \a iter is an end iterator or if slot==-1. public: @@ -171,7 +172,8 @@ namespace MWWorld Ptr search (const std::string& id); - virtual void writeState (ESM::InventoryState& state) const; + /// \todo make this method const once const-correct ContainerStoreIterators are available + virtual void writeState (ESM::InventoryState& state); virtual void readState (const ESM::InventoryState& state); diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 445b42d8d..8f272ca49 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -49,19 +49,40 @@ void MWWorld::InventoryStore::initSlots (TSlots& slots_) slots_.push_back (end()); } -int MWWorld::InventoryStore::getSlot (const MWWorld::LiveCellRefBase& ref) const +int MWWorld::InventoryStore::getRelativeSlot (const MWWorld::ContainerStoreIterator& iter) { for (int i = 0; i (mSlots.size()); ++i) - if (mSlots[i].getType()!=-1 && mSlots[i]->getBase()==&ref) - return i; + if (mSlots[i].getType()!=-1 && mSlots[i] == iter) + { + // linear complexity, but allowedSlots is most of the time just 1 anyway + std::vector allowedSlots = iter->getClass().getEquipmentSlots(*iter).first; + std::vector::iterator found = std::find(allowedSlots.begin(),allowedSlots.end(),i); + if (found == allowedSlots.end()) + return -1; + else + return std::distance(allowedSlots.begin(), found); + } return -1; } -void MWWorld::InventoryStore::setSlot (const MWWorld::ContainerStoreIterator& iter, int slot) +void MWWorld::InventoryStore::setRelativeSlot (const MWWorld::ContainerStoreIterator& iter, int relativeSlot) { - if (iter!=end() && slot>=0 && slot, bool> allowedSlots = iter->getClass().getEquipmentSlots(*iter); + relativeSlot = std::min(int(allowedSlots.first.size()-1), relativeSlot); + + // unstack if required + if (!allowedSlots.second && iter->getRefData().getCount() > 1) + { + MWWorld::ContainerStoreIterator newIter = addNewStack(*iter, 1); + iter->getRefData().setCount(iter->getRefData().getCount()-1); + mSlots[allowedSlots.first[relativeSlot]] = newIter; + } + else + mSlots[allowedSlots.first[relativeSlot]] = iter; } MWWorld::InventoryStore::InventoryStore() @@ -703,7 +724,7 @@ bool MWWorld::InventoryStore::isEquipped(const MWWorld::Ptr &item) return false; } -void MWWorld::InventoryStore::writeState(ESM::InventoryState &state) const +void MWWorld::InventoryStore::writeState(ESM::InventoryState &state) { MWWorld::ContainerStore::writeState(state); diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 9fd18c54b..ae2ced2b8 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -113,10 +113,10 @@ namespace MWWorld void fireEquipmentChangedEvent(); - virtual int getSlot (const MWWorld::LiveCellRefBase& ref) const; + virtual int getRelativeSlot (const MWWorld::ContainerStoreIterator& iter); ///< Return inventory slot that \a ref is in or -1 (if \a ref is not in a slot). - virtual void setSlot (const MWWorld::ContainerStoreIterator& iter, int slot); + virtual void setRelativeSlot (const MWWorld::ContainerStoreIterator& iter, int relativeSlot); ///< Set slot for \a iter. Ignored if \a iter is an end iterator or if slot==-1. public: @@ -209,7 +209,7 @@ namespace MWWorld virtual void clear(); ///< Empty container. - virtual void writeState (ESM::InventoryState& state) const; + virtual void writeState (ESM::InventoryState& state); virtual void readState (const ESM::InventoryState& state); }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 104605e65..f7d5d9616 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2031,7 +2031,7 @@ namespace MWWorld bool World::isOnGround(const MWWorld::Ptr &ptr) const { RefData &refdata = ptr.getRefData(); - const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); + OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); if(!physactor) return false; @@ -2049,7 +2049,7 @@ namespace MWWorld mPhysEngine); if(tracer.mFraction < 1.0f) // collision, must be close to something below { - const_cast (physactor)->setOnGround(true); + physactor->setOnGround(true); return true; } else diff --git a/components/esm/inventorystate.hpp b/components/esm/inventorystate.hpp index 3d4407e7b..13af28e30 100644 --- a/components/esm/inventorystate.hpp +++ b/components/esm/inventorystate.hpp @@ -15,6 +15,7 @@ namespace ESM /// \brief State for inventories and containers struct InventoryState { + /// std::vector > mItems; std::map mLevelledItemMap; From 03df659e7d60c1047dd51b8d293cdd26f1cb9e2d Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 20 Jan 2015 23:58:24 +0100 Subject: [PATCH 256/740] ESSImport: convert inventory equipment slots --- apps/essimporter/convertinventory.cpp | 2 +- apps/essimporter/importinventory.cpp | 12 +++++++++++- apps/essimporter/importinventory.hpp | 1 + 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/apps/essimporter/convertinventory.cpp b/apps/essimporter/convertinventory.cpp index 42535d946..6a31be6a3 100644 --- a/apps/essimporter/convertinventory.cpp +++ b/apps/essimporter/convertinventory.cpp @@ -16,7 +16,7 @@ namespace ESSImport objstate.mCount = std::abs(it->mCount); // restocking items have negative count in the savefile // openmw handles them differently, so no need to set any flags objstate.mRef.mCharge = it->mCondition; - state.mItems.push_back(std::make_pair(objstate, -1)); + state.mItems.push_back(std::make_pair(objstate, it->mRelativeEquipmentSlot)); } } diff --git a/apps/essimporter/importinventory.cpp b/apps/essimporter/importinventory.cpp index b4d193540..2f5c3c054 100644 --- a/apps/essimporter/importinventory.cpp +++ b/apps/essimporter/importinventory.cpp @@ -1,5 +1,7 @@ #include "importinventory.hpp" +#include + #include #include @@ -17,6 +19,7 @@ namespace ESSImport InventoryItem item; item.mId = contItem.mItem.toString(); item.mCount = contItem.mCount; + item.mRelativeEquipmentSlot = -1; // seems that a stack of items can have a set of subrecords for each item? rings0000.ess // doesn't make any sense to me, if the values were different then the items shouldn't stack in the first place? @@ -55,14 +58,21 @@ namespace ESSImport { // note: same item can be equipped 2 items (e.g. 2 rings) // and will be *stacked* in the NPCO list, unlike openmw! + // this is currently not handled properly. + esm.getSubHeader(); int itemIndex; // index of the item in the NPCO list esm.getT(itemIndex); + if (itemIndex < 0 || itemIndex >= int(mItems.size())) + esm.fail("equipment item index out of range"); + // appears to be a relative index for only the *possible* slots this item can be equipped in, - // i.e. 0 most of the time, unlike openmw slot enum index + // i.e. 0 most of the time int slotIndex; esm.getT(slotIndex); + + mItems[itemIndex].mRelativeEquipmentSlot = slotIndex; } } diff --git a/apps/essimporter/importinventory.hpp b/apps/essimporter/importinventory.hpp index 359e43fa6..8a1594465 100644 --- a/apps/essimporter/importinventory.hpp +++ b/apps/essimporter/importinventory.hpp @@ -21,6 +21,7 @@ namespace ESSImport std::string mId; int mCount; int mCondition; + int mRelativeEquipmentSlot; }; std::vector mItems; From 8c32b7e304ae5ce07209849a0f772ecbdb097aab Mon Sep 17 00:00:00 2001 From: Scott Howard Date: Tue, 20 Jan 2015 17:59:11 -0500 Subject: [PATCH 257/740] missing include in essimporter/main.cpp error: 'cout' is not a member of 'std' error: 'cerr' is not a member of 'std' https://launchpadlibrarian.net/195402684/buildlog_ubuntu-trusty-amd64.openmw_0.34.0%2Bgit20150120.442-0~ubuntu14.04.1_FAILEDTOBUILD.txt.gz --- apps/essimporter/main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/essimporter/main.cpp b/apps/essimporter/main.cpp index 0e5c65e95..1c7d51116 100644 --- a/apps/essimporter/main.cpp +++ b/apps/essimporter/main.cpp @@ -1,3 +1,5 @@ +#include + #include #include #include From db64ff66453245ecf0b273354bee3ec1af7a0810 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 21 Jan 2015 01:33:48 +0100 Subject: [PATCH 258/740] Fix actorId initialization --- components/esm/creaturestats.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/creaturestats.cpp b/components/esm/creaturestats.cpp index a1ef7eb0e..cac5cc0a6 100644 --- a/components/esm/creaturestats.cpp +++ b/components/esm/creaturestats.cpp @@ -230,7 +230,7 @@ void ESM::CreatureStats::blank() mTradeTime.mHour = 0; mTradeTime.mDay = 0; mGoldPool = 0; - mActorId = 0; + mActorId = -1; mHasAiSettings = false; mDead = false; mDied = false; From 5e0428243b38d18c55b80e7675ea74a0563f5e44 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 21 Jan 2015 01:59:45 +0100 Subject: [PATCH 259/740] Light charge handling fix --- apps/esmtool/esmtool.cpp | 2 +- apps/essimporter/convertinventory.cpp | 2 +- apps/essimporter/importinventory.cpp | 6 +-- apps/essimporter/importinventory.hpp | 1 - apps/opencs/model/world/columnimp.hpp | 4 +- apps/openmw/mwclass/light.cpp | 56 +++------------------------ apps/openmw/mwclass/light.hpp | 10 ----- apps/openmw/mwworld/cellref.cpp | 20 ++++++++-- apps/openmw/mwworld/cellref.hpp | 3 ++ apps/openmw/mwworld/manualref.hpp | 2 +- components/esm/cellref.cpp | 10 ++--- components/esm/cellref.hpp | 6 ++- components/esm/objectstate.cpp | 10 ++--- components/esm/objectstate.hpp | 2 - 14 files changed, 47 insertions(+), 87 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index a18736bf2..b23ba72f9 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -261,7 +261,7 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info) std::cout << " Faction: '" << ref.mFaction << "'" << std::endl; std::cout << " Faction rank: '" << ref.mFactionRank << "'" << std::endl; std::cout << " Enchantment charge: '" << ref.mEnchantmentCharge << "'\n"; - std::cout << " Uses/health: '" << ref.mCharge << "'\n"; + std::cout << " Uses/health: '" << ref.mChargeInt << "'\n"; std::cout << " Gold value: '" << ref.mGoldValue << "'\n"; std::cout << " Blocked: '" << static_cast(ref.mReferenceBlocked) << "'" << std::endl; std::cout << " Deleted: " << deleted << std::endl; diff --git a/apps/essimporter/convertinventory.cpp b/apps/essimporter/convertinventory.cpp index 6a31be6a3..31272bf5a 100644 --- a/apps/essimporter/convertinventory.cpp +++ b/apps/essimporter/convertinventory.cpp @@ -12,10 +12,10 @@ namespace ESSImport { ESM::ObjectState objstate; objstate.blank(); + objstate.mRef = *it; objstate.mRef.mRefID = Misc::StringUtils::lowerCase(it->mId); objstate.mCount = std::abs(it->mCount); // restocking items have negative count in the savefile // openmw handles them differently, so no need to set any flags - objstate.mRef.mCharge = it->mCondition; state.mItems.push_back(std::make_pair(objstate, it->mRelativeEquipmentSlot)); } } diff --git a/apps/essimporter/importinventory.cpp b/apps/essimporter/importinventory.cpp index 2f5c3c054..a20584ff5 100644 --- a/apps/essimporter/importinventory.cpp +++ b/apps/essimporter/importinventory.cpp @@ -45,9 +45,9 @@ namespace ESSImport // for XSOL and XCHG seen so far, but probably others too item.ESM::CellRef::loadData(esm); - item.mCondition = -1; - // FIXME: for Lights, this is actually a float - esm.getHNOT(item.mCondition, "XHLT"); + int charge=-1; + esm.getHNOT(charge, "XHLT"); + item.mChargeInt = charge; } mItems.push_back(item); diff --git a/apps/essimporter/importinventory.hpp b/apps/essimporter/importinventory.hpp index 8a1594465..99fed9b20 100644 --- a/apps/essimporter/importinventory.hpp +++ b/apps/essimporter/importinventory.hpp @@ -20,7 +20,6 @@ namespace ESSImport { std::string mId; int mCount; - int mCondition; int mRelativeEquipmentSlot; }; std::vector mItems; diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index eba73cf0b..da14bb495 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -1053,13 +1053,13 @@ namespace CSMWorld virtual QVariant get (const Record& record) const { - return record.get().mCharge; + return record.get().mChargeInt; } virtual void set (Record& record, const QVariant& data) { ESXRecordT record2 = record.get(); - record2.mCharge = data.toInt(); + record2.mChargeInt = data.toInt(); record.setModified (record2); } diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index c50ad52d8..35a21b63e 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -26,27 +26,6 @@ #include "../mwrender/actors.hpp" #include "../mwrender/renderinginterface.hpp" -namespace -{ - struct LightCustomData : public MWWorld::CustomData - { - float mTime; - ///< Time remaining - - LightCustomData(MWWorld::Ptr ptr) - { - MWWorld::LiveCellRef *ref = ptr.get(); - mTime = ref->mBase->mData.mTime; - } - ///< Constructs this CustomData from the base values for Ptr. - - virtual MWWorld::CustomData *clone() const - { - return new LightCustomData (*this); - } - }; -} - namespace MWClass { std::string Light::getId (const MWWorld::Ptr& ptr) const @@ -219,17 +198,16 @@ namespace MWClass void Light::setRemainingUsageTime (const MWWorld::Ptr& ptr, float duration) const { - ensureCustomData(ptr); - - float &timeRemaining = dynamic_cast (*ptr.getRefData().getCustomData()).mTime; - timeRemaining = duration; + ptr.getCellRef().setChargeFloat(duration); } float Light::getRemainingUsageTime (const MWWorld::Ptr& ptr) const { - ensureCustomData(ptr); - - return dynamic_cast (*ptr.getRefData().getCustomData()).mTime; + MWWorld::LiveCellRef *ref = ptr.get(); + if (ptr.getCellRef().getCharge() == -1) + return ref->mBase->mData.mTime; + else + return ptr.getCellRef().getChargeFloat(); } MWWorld::Ptr @@ -241,12 +219,6 @@ namespace MWClass return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } - void Light::ensureCustomData (const MWWorld::Ptr& ptr) const - { - if (!ptr.getRefData().getCustomData()) - ptr.getRefData().setCustomData(new LightCustomData(ptr)); - } - bool Light::canSell (const MWWorld::Ptr& item, int npcServices) const { return npcServices & ESM::NPC::Lights; @@ -282,22 +254,6 @@ namespace MWClass return std::make_pair(1,""); } - void Light::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) - const - { - ensureCustomData (ptr); - - dynamic_cast (*ptr.getRefData().getCustomData()).mTime = state.mTime; - } - - void Light::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) - const - { - ensureCustomData (ptr); - - state.mTime = dynamic_cast (*ptr.getRefData().getCustomData()).mTime; - } - std::string Light::getSound(const MWWorld::Ptr& ptr) const { return ptr.get()->mBase->mSound; diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index bbca30113..8658375b7 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -10,8 +10,6 @@ namespace MWClass virtual MWWorld::Ptr copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; - void ensureCustomData (const MWWorld::Ptr& ptr) const; - public: /// Return ID of \a ptr @@ -75,14 +73,6 @@ namespace MWClass std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; - virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) - const; - ///< Read additional state from \a state into \a ptr. - - virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) - const; - ///< Write additional state from \a ptr into \a state. - virtual std::string getSound(const MWWorld::Ptr& ptr) const; }; } diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index aa6627de5..744e0e27a 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -81,15 +81,29 @@ namespace MWWorld int CellRef::getCharge() const { - return mCellRef.mCharge; + return mCellRef.mChargeInt; } void CellRef::setCharge(int charge) { - if (charge != mCellRef.mCharge) + if (charge != mCellRef.mChargeInt) { mChanged = true; - mCellRef.mCharge = charge; + mCellRef.mChargeInt = charge; + } + } + + float CellRef::getChargeFloat() const + { + return mCellRef.mChargeFloat; + } + + void CellRef::setChargeFloat(float charge) + { + if (charge != mCellRef.mChargeFloat) + { + mChanged = true; + mCellRef.mChargeFloat = charge; } } diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index a7ffbe08b..054fd7fc6 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -60,8 +60,11 @@ namespace MWWorld // For weapon or armor, this is the remaining item health. // For tools (lockpicks, probes, repair hammer) it is the remaining uses. + // If this returns int(-1) it means full health. int getCharge() const; + float getChargeFloat() const; // Implemented as union with int charge void setCharge(int charge); + void setChargeFloat(float charge); // The NPC that owns this object (and will get angry if you steal it) std::string getOwner() const; diff --git a/apps/openmw/mwworld/manualref.hpp b/apps/openmw/mwworld/manualref.hpp index 4eb93543b..f32b07471 100644 --- a/apps/openmw/mwworld/manualref.hpp +++ b/apps/openmw/mwworld/manualref.hpp @@ -28,7 +28,7 @@ namespace MWWorld cellRef.mRefID = name; cellRef.mScale = 1; cellRef.mFactionRank = 0; - cellRef.mCharge = -1; + cellRef.mChargeInt = -1; cellRef.mGoldValue = 1; cellRef.mEnchantmentCharge = -1; cellRef.mTeleport = false; diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index cd9fe8570..dfc3052ee 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -46,12 +46,12 @@ void ESM::CellRef::loadData(ESMReader &esm) esm.getHNOT (mFactionRank, "INDX"); mGoldValue = 1; - mCharge = -1; + mChargeInt = -1; mEnchantmentCharge = -1; esm.getHNOT (mEnchantmentCharge, "XCHG"); - esm.getHNOT (mCharge, "INTV"); + esm.getHNOT (mChargeInt, "INTV"); esm.getHNOT (mGoldValue, "NAM9"); @@ -106,8 +106,8 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) cons if (mEnchantmentCharge != -1) esm.writeHNT("XCHG", mEnchantmentCharge); - if (mCharge != -1) - esm.writeHNT("INTV", mCharge); + if (mChargeInt != -1) + esm.writeHNT("INTV", mChargeInt); if (mGoldValue != 1) { esm.writeHNT("NAM9", mGoldValue); @@ -146,7 +146,7 @@ void ESM::CellRef::blank() mSoul.clear(); mFaction.clear(); mFactionRank = -2; - mCharge = -1; + mChargeInt = -1; mEnchantmentCharge = -1; mGoldValue = 0; mDestCell.clear(); diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index 7aa0e4d44..56932aa4d 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -59,7 +59,11 @@ namespace ESM // For weapon or armor, this is the remaining item health. // For tools (lockpicks, probes, repair hammer) it is the remaining uses. - int mCharge; + union + { + int mChargeInt; + float mChargeFloat; + }; // Remaining enchantment charge. This could be -1 if the charge was not touched yet (i.e. full). float mEnchantmentCharge; diff --git a/components/esm/objectstate.cpp b/components/esm/objectstate.cpp index 66fd49663..9ef1ccf80 100644 --- a/components/esm/objectstate.cpp +++ b/components/esm/objectstate.cpp @@ -24,9 +24,9 @@ void ESM::ObjectState::load (ESMReader &esm) esm.getHNOT (mLocalRotation, "LROT", 12); - // used for lights only - mTime = 0; - esm.getHNOT (mTime, "LTIM"); + // obsolete + int unused; + esm.getHNOT(unused, "LTIM"); // FIXME: assuming "false" as default would make more sense, but also break compatibility with older save files mHasCustomState = true; @@ -55,9 +55,6 @@ void ESM::ObjectState::save (ESMWriter &esm, bool inInventory) const esm.writeHNT ("LROT", mLocalRotation, 12); } - if (mTime) - esm.writeHNT ("LTIM", mTime); - if (!mHasCustomState) esm.writeHNT ("HCUS", false); } @@ -74,7 +71,6 @@ void ESM::ObjectState::blank() mPosition.rot[i] = 0; mLocalRotation[i] = 0; } - mTime = 0; mHasCustomState = true; } diff --git a/components/esm/objectstate.hpp b/components/esm/objectstate.hpp index b03689653..d1077733a 100644 --- a/components/esm/objectstate.hpp +++ b/components/esm/objectstate.hpp @@ -26,8 +26,6 @@ namespace ESM ESM::Position mPosition; float mLocalRotation[3]; - float mTime; // Used for lights only. Overhead should not be so awful, besides CellRef isn't OO either - // Is there any class-specific state following the ObjectState bool mHasCustomState; From b95748d044a421c2e02fa54cdc7e8aa902039e6c Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Jan 2015 02:32:38 +0100 Subject: [PATCH 260/740] Revert "Light charge handling fix" This reverts commit 5e0428243b38d18c55b80e7675ea74a0563f5e44. --- apps/esmtool/esmtool.cpp | 2 +- apps/essimporter/convertinventory.cpp | 2 +- apps/essimporter/importinventory.cpp | 6 +-- apps/essimporter/importinventory.hpp | 1 + apps/opencs/model/world/columnimp.hpp | 4 +- apps/openmw/mwclass/light.cpp | 56 ++++++++++++++++++++++++--- apps/openmw/mwclass/light.hpp | 10 +++++ apps/openmw/mwworld/cellref.cpp | 20 ++-------- apps/openmw/mwworld/cellref.hpp | 3 -- apps/openmw/mwworld/manualref.hpp | 2 +- components/esm/cellref.cpp | 10 ++--- components/esm/cellref.hpp | 6 +-- components/esm/objectstate.cpp | 10 +++-- components/esm/objectstate.hpp | 2 + 14 files changed, 87 insertions(+), 47 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index b23ba72f9..a18736bf2 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -261,7 +261,7 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info) std::cout << " Faction: '" << ref.mFaction << "'" << std::endl; std::cout << " Faction rank: '" << ref.mFactionRank << "'" << std::endl; std::cout << " Enchantment charge: '" << ref.mEnchantmentCharge << "'\n"; - std::cout << " Uses/health: '" << ref.mChargeInt << "'\n"; + std::cout << " Uses/health: '" << ref.mCharge << "'\n"; std::cout << " Gold value: '" << ref.mGoldValue << "'\n"; std::cout << " Blocked: '" << static_cast(ref.mReferenceBlocked) << "'" << std::endl; std::cout << " Deleted: " << deleted << std::endl; diff --git a/apps/essimporter/convertinventory.cpp b/apps/essimporter/convertinventory.cpp index 31272bf5a..6a31be6a3 100644 --- a/apps/essimporter/convertinventory.cpp +++ b/apps/essimporter/convertinventory.cpp @@ -12,10 +12,10 @@ namespace ESSImport { ESM::ObjectState objstate; objstate.blank(); - objstate.mRef = *it; objstate.mRef.mRefID = Misc::StringUtils::lowerCase(it->mId); objstate.mCount = std::abs(it->mCount); // restocking items have negative count in the savefile // openmw handles them differently, so no need to set any flags + objstate.mRef.mCharge = it->mCondition; state.mItems.push_back(std::make_pair(objstate, it->mRelativeEquipmentSlot)); } } diff --git a/apps/essimporter/importinventory.cpp b/apps/essimporter/importinventory.cpp index a20584ff5..2f5c3c054 100644 --- a/apps/essimporter/importinventory.cpp +++ b/apps/essimporter/importinventory.cpp @@ -45,9 +45,9 @@ namespace ESSImport // for XSOL and XCHG seen so far, but probably others too item.ESM::CellRef::loadData(esm); - int charge=-1; - esm.getHNOT(charge, "XHLT"); - item.mChargeInt = charge; + item.mCondition = -1; + // FIXME: for Lights, this is actually a float + esm.getHNOT(item.mCondition, "XHLT"); } mItems.push_back(item); diff --git a/apps/essimporter/importinventory.hpp b/apps/essimporter/importinventory.hpp index 99fed9b20..8a1594465 100644 --- a/apps/essimporter/importinventory.hpp +++ b/apps/essimporter/importinventory.hpp @@ -20,6 +20,7 @@ namespace ESSImport { std::string mId; int mCount; + int mCondition; int mRelativeEquipmentSlot; }; std::vector mItems; diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index da14bb495..eba73cf0b 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -1053,13 +1053,13 @@ namespace CSMWorld virtual QVariant get (const Record& record) const { - return record.get().mChargeInt; + return record.get().mCharge; } virtual void set (Record& record, const QVariant& data) { ESXRecordT record2 = record.get(); - record2.mChargeInt = data.toInt(); + record2.mCharge = data.toInt(); record.setModified (record2); } diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 35a21b63e..c50ad52d8 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -26,6 +26,27 @@ #include "../mwrender/actors.hpp" #include "../mwrender/renderinginterface.hpp" +namespace +{ + struct LightCustomData : public MWWorld::CustomData + { + float mTime; + ///< Time remaining + + LightCustomData(MWWorld::Ptr ptr) + { + MWWorld::LiveCellRef *ref = ptr.get(); + mTime = ref->mBase->mData.mTime; + } + ///< Constructs this CustomData from the base values for Ptr. + + virtual MWWorld::CustomData *clone() const + { + return new LightCustomData (*this); + } + }; +} + namespace MWClass { std::string Light::getId (const MWWorld::Ptr& ptr) const @@ -198,16 +219,17 @@ namespace MWClass void Light::setRemainingUsageTime (const MWWorld::Ptr& ptr, float duration) const { - ptr.getCellRef().setChargeFloat(duration); + ensureCustomData(ptr); + + float &timeRemaining = dynamic_cast (*ptr.getRefData().getCustomData()).mTime; + timeRemaining = duration; } float Light::getRemainingUsageTime (const MWWorld::Ptr& ptr) const { - MWWorld::LiveCellRef *ref = ptr.get(); - if (ptr.getCellRef().getCharge() == -1) - return ref->mBase->mData.mTime; - else - return ptr.getCellRef().getChargeFloat(); + ensureCustomData(ptr); + + return dynamic_cast (*ptr.getRefData().getCustomData()).mTime; } MWWorld::Ptr @@ -219,6 +241,12 @@ namespace MWClass return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } + void Light::ensureCustomData (const MWWorld::Ptr& ptr) const + { + if (!ptr.getRefData().getCustomData()) + ptr.getRefData().setCustomData(new LightCustomData(ptr)); + } + bool Light::canSell (const MWWorld::Ptr& item, int npcServices) const { return npcServices & ESM::NPC::Lights; @@ -254,6 +282,22 @@ namespace MWClass return std::make_pair(1,""); } + void Light::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) + const + { + ensureCustomData (ptr); + + dynamic_cast (*ptr.getRefData().getCustomData()).mTime = state.mTime; + } + + void Light::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) + const + { + ensureCustomData (ptr); + + state.mTime = dynamic_cast (*ptr.getRefData().getCustomData()).mTime; + } + std::string Light::getSound(const MWWorld::Ptr& ptr) const { return ptr.get()->mBase->mSound; diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 8658375b7..bbca30113 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -10,6 +10,8 @@ namespace MWClass virtual MWWorld::Ptr copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + void ensureCustomData (const MWWorld::Ptr& ptr) const; + public: /// Return ID of \a ptr @@ -73,6 +75,14 @@ namespace MWClass std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; + virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) + const; + ///< Read additional state from \a state into \a ptr. + + virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) + const; + ///< Write additional state from \a ptr into \a state. + virtual std::string getSound(const MWWorld::Ptr& ptr) const; }; } diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index 744e0e27a..aa6627de5 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -81,29 +81,15 @@ namespace MWWorld int CellRef::getCharge() const { - return mCellRef.mChargeInt; + return mCellRef.mCharge; } void CellRef::setCharge(int charge) { - if (charge != mCellRef.mChargeInt) + if (charge != mCellRef.mCharge) { mChanged = true; - mCellRef.mChargeInt = charge; - } - } - - float CellRef::getChargeFloat() const - { - return mCellRef.mChargeFloat; - } - - void CellRef::setChargeFloat(float charge) - { - if (charge != mCellRef.mChargeFloat) - { - mChanged = true; - mCellRef.mChargeFloat = charge; + mCellRef.mCharge = charge; } } diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index 054fd7fc6..a7ffbe08b 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -60,11 +60,8 @@ namespace MWWorld // For weapon or armor, this is the remaining item health. // For tools (lockpicks, probes, repair hammer) it is the remaining uses. - // If this returns int(-1) it means full health. int getCharge() const; - float getChargeFloat() const; // Implemented as union with int charge void setCharge(int charge); - void setChargeFloat(float charge); // The NPC that owns this object (and will get angry if you steal it) std::string getOwner() const; diff --git a/apps/openmw/mwworld/manualref.hpp b/apps/openmw/mwworld/manualref.hpp index f32b07471..4eb93543b 100644 --- a/apps/openmw/mwworld/manualref.hpp +++ b/apps/openmw/mwworld/manualref.hpp @@ -28,7 +28,7 @@ namespace MWWorld cellRef.mRefID = name; cellRef.mScale = 1; cellRef.mFactionRank = 0; - cellRef.mChargeInt = -1; + cellRef.mCharge = -1; cellRef.mGoldValue = 1; cellRef.mEnchantmentCharge = -1; cellRef.mTeleport = false; diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index dfc3052ee..cd9fe8570 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -46,12 +46,12 @@ void ESM::CellRef::loadData(ESMReader &esm) esm.getHNOT (mFactionRank, "INDX"); mGoldValue = 1; - mChargeInt = -1; + mCharge = -1; mEnchantmentCharge = -1; esm.getHNOT (mEnchantmentCharge, "XCHG"); - esm.getHNOT (mChargeInt, "INTV"); + esm.getHNOT (mCharge, "INTV"); esm.getHNOT (mGoldValue, "NAM9"); @@ -106,8 +106,8 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) cons if (mEnchantmentCharge != -1) esm.writeHNT("XCHG", mEnchantmentCharge); - if (mChargeInt != -1) - esm.writeHNT("INTV", mChargeInt); + if (mCharge != -1) + esm.writeHNT("INTV", mCharge); if (mGoldValue != 1) { esm.writeHNT("NAM9", mGoldValue); @@ -146,7 +146,7 @@ void ESM::CellRef::blank() mSoul.clear(); mFaction.clear(); mFactionRank = -2; - mChargeInt = -1; + mCharge = -1; mEnchantmentCharge = -1; mGoldValue = 0; mDestCell.clear(); diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index 56932aa4d..7aa0e4d44 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -59,11 +59,7 @@ namespace ESM // For weapon or armor, this is the remaining item health. // For tools (lockpicks, probes, repair hammer) it is the remaining uses. - union - { - int mChargeInt; - float mChargeFloat; - }; + int mCharge; // Remaining enchantment charge. This could be -1 if the charge was not touched yet (i.e. full). float mEnchantmentCharge; diff --git a/components/esm/objectstate.cpp b/components/esm/objectstate.cpp index 9ef1ccf80..66fd49663 100644 --- a/components/esm/objectstate.cpp +++ b/components/esm/objectstate.cpp @@ -24,9 +24,9 @@ void ESM::ObjectState::load (ESMReader &esm) esm.getHNOT (mLocalRotation, "LROT", 12); - // obsolete - int unused; - esm.getHNOT(unused, "LTIM"); + // used for lights only + mTime = 0; + esm.getHNOT (mTime, "LTIM"); // FIXME: assuming "false" as default would make more sense, but also break compatibility with older save files mHasCustomState = true; @@ -55,6 +55,9 @@ void ESM::ObjectState::save (ESMWriter &esm, bool inInventory) const esm.writeHNT ("LROT", mLocalRotation, 12); } + if (mTime) + esm.writeHNT ("LTIM", mTime); + if (!mHasCustomState) esm.writeHNT ("HCUS", false); } @@ -71,6 +74,7 @@ void ESM::ObjectState::blank() mPosition.rot[i] = 0; mLocalRotation[i] = 0; } + mTime = 0; mHasCustomState = true; } diff --git a/components/esm/objectstate.hpp b/components/esm/objectstate.hpp index d1077733a..b03689653 100644 --- a/components/esm/objectstate.hpp +++ b/components/esm/objectstate.hpp @@ -26,6 +26,8 @@ namespace ESM ESM::Position mPosition; float mLocalRotation[3]; + float mTime; // Used for lights only. Overhead should not be so awful, besides CellRef isn't OO either + // Is there any class-specific state following the ObjectState bool mHasCustomState; From fe31ca0ac0649a0e34617a5821454e04863531ca Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Jan 2015 02:32:42 +0100 Subject: [PATCH 261/740] Revert "ESSImport: convert inventory equipment slots" This reverts commit 03df659e7d60c1047dd51b8d293cdd26f1cb9e2d. --- apps/essimporter/convertinventory.cpp | 2 +- apps/essimporter/importinventory.cpp | 12 +----------- apps/essimporter/importinventory.hpp | 1 - 3 files changed, 2 insertions(+), 13 deletions(-) diff --git a/apps/essimporter/convertinventory.cpp b/apps/essimporter/convertinventory.cpp index 6a31be6a3..42535d946 100644 --- a/apps/essimporter/convertinventory.cpp +++ b/apps/essimporter/convertinventory.cpp @@ -16,7 +16,7 @@ namespace ESSImport objstate.mCount = std::abs(it->mCount); // restocking items have negative count in the savefile // openmw handles them differently, so no need to set any flags objstate.mRef.mCharge = it->mCondition; - state.mItems.push_back(std::make_pair(objstate, it->mRelativeEquipmentSlot)); + state.mItems.push_back(std::make_pair(objstate, -1)); } } diff --git a/apps/essimporter/importinventory.cpp b/apps/essimporter/importinventory.cpp index 2f5c3c054..b4d193540 100644 --- a/apps/essimporter/importinventory.cpp +++ b/apps/essimporter/importinventory.cpp @@ -1,7 +1,5 @@ #include "importinventory.hpp" -#include - #include #include @@ -19,7 +17,6 @@ namespace ESSImport InventoryItem item; item.mId = contItem.mItem.toString(); item.mCount = contItem.mCount; - item.mRelativeEquipmentSlot = -1; // seems that a stack of items can have a set of subrecords for each item? rings0000.ess // doesn't make any sense to me, if the values were different then the items shouldn't stack in the first place? @@ -58,21 +55,14 @@ namespace ESSImport { // note: same item can be equipped 2 items (e.g. 2 rings) // and will be *stacked* in the NPCO list, unlike openmw! - // this is currently not handled properly. - esm.getSubHeader(); int itemIndex; // index of the item in the NPCO list esm.getT(itemIndex); - if (itemIndex < 0 || itemIndex >= int(mItems.size())) - esm.fail("equipment item index out of range"); - // appears to be a relative index for only the *possible* slots this item can be equipped in, - // i.e. 0 most of the time + // i.e. 0 most of the time, unlike openmw slot enum index int slotIndex; esm.getT(slotIndex); - - mItems[itemIndex].mRelativeEquipmentSlot = slotIndex; } } diff --git a/apps/essimporter/importinventory.hpp b/apps/essimporter/importinventory.hpp index 8a1594465..359e43fa6 100644 --- a/apps/essimporter/importinventory.hpp +++ b/apps/essimporter/importinventory.hpp @@ -21,7 +21,6 @@ namespace ESSImport std::string mId; int mCount; int mCondition; - int mRelativeEquipmentSlot; }; std::vector mItems; From c65f9cb3c0fa39f6f5664f68852ee5109663bf30 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Jan 2015 02:32:43 +0100 Subject: [PATCH 262/740] Revert "Change save format to store relative equipment index" This reverts commit 89d9649b50b2b6e102b90517a5b136cc74415ba0. --- apps/openmw/mwworld/cellstore.cpp | 2 +- apps/openmw/mwworld/containerstore.cpp | 27 ++++++++++---------- apps/openmw/mwworld/containerstore.hpp | 12 ++++----- apps/openmw/mwworld/inventorystore.cpp | 35 ++++++-------------------- apps/openmw/mwworld/inventorystore.hpp | 6 ++--- apps/openmw/mwworld/worldimp.cpp | 4 +-- components/esm/inventorystate.hpp | 1 - 7 files changed, 31 insertions(+), 56 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 545bbd4b3..605c8f9d2 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -466,7 +466,7 @@ namespace MWWorld // List moved references, from separately tracked list. for (ESM::CellRefTracker::const_iterator it = mCell->mLeasedRefs.begin(); it != mCell->mLeasedRefs.end(); ++it) { - const ESM::CellRef &ref = *it; + ESM::CellRef &ref = const_cast(*it); mIds.push_back(Misc::StringUtils::lowerCase(ref.mRefID)); } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 5911b45f7..bd14720f7 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -85,29 +85,28 @@ void MWWorld::ContainerStore::storeState (const LiveCellRef& ref, ESM::Object ref.save (state); } -/// \todo make this method const once const-correct ContainerStoreIterators are available template -void MWWorld::ContainerStore::storeStates (CellRefList& collection, - std::vector >& states, bool equipable) +void MWWorld::ContainerStore::storeStates (const CellRefList& collection, + std::vector >& states, bool equipable) const { - for (typename CellRefList::List::iterator iter (collection.mList.begin()); + for (typename CellRefList::List::const_iterator iter (collection.mList.begin()); iter!=collection.mList.end(); ++iter) { if (iter->mData.getCount() == 0) continue; ESM::ObjectState state; storeState (*iter, state); - int slot = equipable ? getRelativeSlot (MWWorld::ContainerStoreIterator(this, iter)) : -1; + int slot = equipable ? getSlot (*iter) : -1; states.push_back (std::make_pair (state, slot)); } } -int MWWorld::ContainerStore::getRelativeSlot (const MWWorld::ContainerStoreIterator& iter) const +int MWWorld::ContainerStore::getSlot (const MWWorld::LiveCellRefBase& ref) const { return -1; } -void MWWorld::ContainerStore::setRelativeSlot (const MWWorld::ContainerStoreIterator& iter, int slot) {} +void MWWorld::ContainerStore::setSlot (const MWWorld::ContainerStoreIterator& iter, int slot) {} const std::string MWWorld::ContainerStore::sGoldId = "gold_001"; @@ -642,7 +641,7 @@ MWWorld::Ptr MWWorld::ContainerStore::search (const std::string& id) return Ptr(); } -void MWWorld::ContainerStore::writeState (ESM::InventoryState& state) +void MWWorld::ContainerStore::writeState (ESM::InventoryState& state) const { state.mItems.clear(); @@ -679,16 +678,16 @@ void MWWorld::ContainerStore::readState (const ESM::InventoryState& state) { case ESM::REC_ALCH: getState (potions, iter->first); break; case ESM::REC_APPA: getState (appas, iter->first); break; - case ESM::REC_ARMO: setRelativeSlot (getState (armors, iter->first), slot); break; + case ESM::REC_ARMO: setSlot (getState (armors, iter->first), slot); break; case ESM::REC_BOOK: getState (books, iter->first); break; - case ESM::REC_CLOT: setRelativeSlot (getState (clothes, iter->first), slot); break; + case ESM::REC_CLOT: setSlot (getState (clothes, iter->first), slot); break; case ESM::REC_INGR: getState (ingreds, iter->first); break; - case ESM::REC_LOCK: setRelativeSlot (getState (lockpicks, iter->first), slot); break; + case ESM::REC_LOCK: setSlot (getState (lockpicks, iter->first), slot); break; case ESM::REC_MISC: getState (miscItems, iter->first); break; - case ESM::REC_PROB: setRelativeSlot (getState (probes, iter->first), slot); break; + case ESM::REC_PROB: setSlot (getState (probes, iter->first), slot); break; case ESM::REC_REPA: getState (repairs, iter->first); break; - case ESM::REC_WEAP: setRelativeSlot (getState (weapons, iter->first), slot); break; - case ESM::REC_LIGH: setRelativeSlot (getState (lights, iter->first), slot); break; + case ESM::REC_WEAP: setSlot (getState (weapons, iter->first), slot); break; + case ESM::REC_LIGH: setSlot (getState (lights, iter->first), slot); break; default: std::cerr << "invalid item type in inventory state, refid " << state.mRef.mRefID << std::endl; diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 4a95606f7..68ee41a1d 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -84,16 +84,15 @@ namespace MWWorld template void storeState (const LiveCellRef& ref, ESM::ObjectState& state) const; - /// \todo make this method const once const-correct ContainerStoreIterators are available template - void storeStates (CellRefList& collection, + void storeStates (const CellRefList& collection, std::vector >& states, - bool equipable = false); + bool equipable = false) const; - virtual int getRelativeSlot (const MWWorld::ContainerStoreIterator& iter) const; + virtual int getSlot (const MWWorld::LiveCellRefBase& ref) const; ///< Return inventory slot that \a ref is in or -1 (if \a ref is not in a slot). - virtual void setRelativeSlot (const MWWorld::ContainerStoreIterator& iter, int slot); + virtual void setSlot (const MWWorld::ContainerStoreIterator& iter, int slot); ///< Set slot for \a iter. Ignored if \a iter is an end iterator or if slot==-1. public: @@ -172,8 +171,7 @@ namespace MWWorld Ptr search (const std::string& id); - /// \todo make this method const once const-correct ContainerStoreIterators are available - virtual void writeState (ESM::InventoryState& state); + virtual void writeState (ESM::InventoryState& state) const; virtual void readState (const ESM::InventoryState& state); diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 8f272ca49..445b42d8d 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -49,40 +49,19 @@ void MWWorld::InventoryStore::initSlots (TSlots& slots_) slots_.push_back (end()); } -int MWWorld::InventoryStore::getRelativeSlot (const MWWorld::ContainerStoreIterator& iter) +int MWWorld::InventoryStore::getSlot (const MWWorld::LiveCellRefBase& ref) const { for (int i = 0; i (mSlots.size()); ++i) - if (mSlots[i].getType()!=-1 && mSlots[i] == iter) - { - // linear complexity, but allowedSlots is most of the time just 1 anyway - std::vector allowedSlots = iter->getClass().getEquipmentSlots(*iter).first; - std::vector::iterator found = std::find(allowedSlots.begin(),allowedSlots.end(),i); - if (found == allowedSlots.end()) - return -1; - else - return std::distance(allowedSlots.begin(), found); - } + if (mSlots[i].getType()!=-1 && mSlots[i]->getBase()==&ref) + return i; return -1; } -void MWWorld::InventoryStore::setRelativeSlot (const MWWorld::ContainerStoreIterator& iter, int relativeSlot) +void MWWorld::InventoryStore::setSlot (const MWWorld::ContainerStoreIterator& iter, int slot) { - if (relativeSlot < 0 || iter == end()) - return; - - std::pair, bool> allowedSlots = iter->getClass().getEquipmentSlots(*iter); - relativeSlot = std::min(int(allowedSlots.first.size()-1), relativeSlot); - - // unstack if required - if (!allowedSlots.second && iter->getRefData().getCount() > 1) - { - MWWorld::ContainerStoreIterator newIter = addNewStack(*iter, 1); - iter->getRefData().setCount(iter->getRefData().getCount()-1); - mSlots[allowedSlots.first[relativeSlot]] = newIter; - } - else - mSlots[allowedSlots.first[relativeSlot]] = iter; + if (iter!=end() && slot>=0 && slotgetCharacter(refdata.getHandle()); + const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); if(!physactor) return false; @@ -2049,7 +2049,7 @@ namespace MWWorld mPhysEngine); if(tracer.mFraction < 1.0f) // collision, must be close to something below { - physactor->setOnGround(true); + const_cast (physactor)->setOnGround(true); return true; } else diff --git a/components/esm/inventorystate.hpp b/components/esm/inventorystate.hpp index 13af28e30..3d4407e7b 100644 --- a/components/esm/inventorystate.hpp +++ b/components/esm/inventorystate.hpp @@ -15,7 +15,6 @@ namespace ESM /// \brief State for inventories and containers struct InventoryState { - /// std::vector > mItems; std::map mLevelledItemMap; From d13335ba40f10203cd9e9f86a198eab98c93c168 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Jan 2015 15:31:44 +0100 Subject: [PATCH 263/740] Ensure the item can be equipped in the given slot when loading inventory --- apps/openmw/mwworld/cellstore.cpp | 2 +- apps/openmw/mwworld/containerstore.cpp | 5 ++--- apps/openmw/mwworld/containerstore.hpp | 5 +++-- apps/openmw/mwworld/inventorystore.cpp | 22 ++++++++++++++++++---- apps/openmw/mwworld/inventorystore.hpp | 4 ++-- apps/openmw/mwworld/worldimp.cpp | 4 ++-- components/esm/inventorystate.hpp | 1 + 7 files changed, 29 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 605c8f9d2..545bbd4b3 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -466,7 +466,7 @@ namespace MWWorld // List moved references, from separately tracked list. for (ESM::CellRefTracker::const_iterator it = mCell->mLeasedRefs.begin(); it != mCell->mLeasedRefs.end(); ++it) { - ESM::CellRef &ref = const_cast(*it); + const ESM::CellRef &ref = *it; mIds.push_back(Misc::StringUtils::lowerCase(ref.mRefID)); } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index bd14720f7..ba70e2f8f 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -86,7 +86,7 @@ void MWWorld::ContainerStore::storeState (const LiveCellRef& ref, ESM::Object } template -void MWWorld::ContainerStore::storeStates (const CellRefList& collection, +void MWWorld::ContainerStore::storeStates (CellRefList& collection, std::vector >& states, bool equipable) const { for (typename CellRefList::List::const_iterator iter (collection.mList.begin()); @@ -641,7 +641,7 @@ MWWorld::Ptr MWWorld::ContainerStore::search (const std::string& id) return Ptr(); } -void MWWorld::ContainerStore::writeState (ESM::InventoryState& state) const +void MWWorld::ContainerStore::writeState (ESM::InventoryState& state) { state.mItems.clear(); @@ -688,7 +688,6 @@ void MWWorld::ContainerStore::readState (const ESM::InventoryState& state) case ESM::REC_REPA: getState (repairs, iter->first); break; case ESM::REC_WEAP: setSlot (getState (weapons, iter->first), slot); break; case ESM::REC_LIGH: setSlot (getState (lights, iter->first), slot); break; - default: std::cerr << "invalid item type in inventory state, refid " << state.mRef.mRefID << std::endl; break; diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 68ee41a1d..f7c8a369c 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -85,7 +85,7 @@ namespace MWWorld void storeState (const LiveCellRef& ref, ESM::ObjectState& state) const; template - void storeStates (const CellRefList& collection, + void storeStates (CellRefList& collection, std::vector >& states, bool equipable = false) const; @@ -171,7 +171,8 @@ namespace MWWorld Ptr search (const std::string& id); - virtual void writeState (ESM::InventoryState& state) const; + /// \todo make this method const once const-correct ContainerStoreIterators are available + virtual void writeState (ESM::InventoryState& state); virtual void readState (const ESM::InventoryState& state); diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 445b42d8d..be93824e5 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -58,10 +58,24 @@ int MWWorld::InventoryStore::getSlot (const MWWorld::LiveCellRefBase& ref) const return -1; } -void MWWorld::InventoryStore::setSlot (const MWWorld::ContainerStoreIterator& iter, int slot) +void MWWorld::InventoryStore::setSlot (const MWWorld::ContainerStoreIterator& iter, int relativeSlot) { - if (iter!=end() && slot>=0 && slot, bool> allowedSlots = iter->getClass().getEquipmentSlots(*iter); + relativeSlot = std::min(int(allowedSlots.first.size()-1), relativeSlot); + + // unstack if required + if (!allowedSlots.second && iter->getRefData().getCount() > 1) + { + MWWorld::ContainerStoreIterator newIter = addNewStack(*iter, 1); + iter->getRefData().setCount(iter->getRefData().getCount()-1); + mSlots[allowedSlots.first[relativeSlot]] = newIter; + } + else + mSlots[allowedSlots.first[relativeSlot]] = iter; } MWWorld::InventoryStore::InventoryStore() @@ -703,7 +717,7 @@ bool MWWorld::InventoryStore::isEquipped(const MWWorld::Ptr &item) return false; } -void MWWorld::InventoryStore::writeState(ESM::InventoryState &state) const +void MWWorld::InventoryStore::writeState(ESM::InventoryState &state) { MWWorld::ContainerStore::writeState(state); diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 9fd18c54b..7bd977e39 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -116,7 +116,7 @@ namespace MWWorld virtual int getSlot (const MWWorld::LiveCellRefBase& ref) const; ///< Return inventory slot that \a ref is in or -1 (if \a ref is not in a slot). - virtual void setSlot (const MWWorld::ContainerStoreIterator& iter, int slot); + virtual void setSlot (const MWWorld::ContainerStoreIterator& iter, int relativeSlot); ///< Set slot for \a iter. Ignored if \a iter is an end iterator or if slot==-1. public: @@ -209,7 +209,7 @@ namespace MWWorld virtual void clear(); ///< Empty container. - virtual void writeState (ESM::InventoryState& state) const; + virtual void writeState (ESM::InventoryState& state); virtual void readState (const ESM::InventoryState& state); }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 104605e65..f7d5d9616 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2031,7 +2031,7 @@ namespace MWWorld bool World::isOnGround(const MWWorld::Ptr &ptr) const { RefData &refdata = ptr.getRefData(); - const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); + OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); if(!physactor) return false; @@ -2049,7 +2049,7 @@ namespace MWWorld mPhysEngine); if(tracer.mFraction < 1.0f) // collision, must be close to something below { - const_cast (physactor)->setOnGround(true); + physactor->setOnGround(true); return true; } else diff --git a/components/esm/inventorystate.hpp b/components/esm/inventorystate.hpp index 3d4407e7b..13af28e30 100644 --- a/components/esm/inventorystate.hpp +++ b/components/esm/inventorystate.hpp @@ -15,6 +15,7 @@ namespace ESM /// \brief State for inventories and containers struct InventoryState { + /// std::vector > mItems; std::map mLevelledItemMap; From 7ead963075c0ef0ff036dec10531367548ae4a56 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Jan 2015 15:33:30 +0100 Subject: [PATCH 264/740] Revert "Revert "ESSImport: convert inventory equipment slots"" This reverts commit fe31ca0ac0649a0e34617a5821454e04863531ca. --- apps/essimporter/convertinventory.cpp | 2 +- apps/essimporter/importinventory.cpp | 12 +++++++++++- apps/essimporter/importinventory.hpp | 1 + 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/apps/essimporter/convertinventory.cpp b/apps/essimporter/convertinventory.cpp index 42535d946..6a31be6a3 100644 --- a/apps/essimporter/convertinventory.cpp +++ b/apps/essimporter/convertinventory.cpp @@ -16,7 +16,7 @@ namespace ESSImport objstate.mCount = std::abs(it->mCount); // restocking items have negative count in the savefile // openmw handles them differently, so no need to set any flags objstate.mRef.mCharge = it->mCondition; - state.mItems.push_back(std::make_pair(objstate, -1)); + state.mItems.push_back(std::make_pair(objstate, it->mRelativeEquipmentSlot)); } } diff --git a/apps/essimporter/importinventory.cpp b/apps/essimporter/importinventory.cpp index b4d193540..2f5c3c054 100644 --- a/apps/essimporter/importinventory.cpp +++ b/apps/essimporter/importinventory.cpp @@ -1,5 +1,7 @@ #include "importinventory.hpp" +#include + #include #include @@ -17,6 +19,7 @@ namespace ESSImport InventoryItem item; item.mId = contItem.mItem.toString(); item.mCount = contItem.mCount; + item.mRelativeEquipmentSlot = -1; // seems that a stack of items can have a set of subrecords for each item? rings0000.ess // doesn't make any sense to me, if the values were different then the items shouldn't stack in the first place? @@ -55,14 +58,21 @@ namespace ESSImport { // note: same item can be equipped 2 items (e.g. 2 rings) // and will be *stacked* in the NPCO list, unlike openmw! + // this is currently not handled properly. + esm.getSubHeader(); int itemIndex; // index of the item in the NPCO list esm.getT(itemIndex); + if (itemIndex < 0 || itemIndex >= int(mItems.size())) + esm.fail("equipment item index out of range"); + // appears to be a relative index for only the *possible* slots this item can be equipped in, - // i.e. 0 most of the time, unlike openmw slot enum index + // i.e. 0 most of the time int slotIndex; esm.getT(slotIndex); + + mItems[itemIndex].mRelativeEquipmentSlot = slotIndex; } } diff --git a/apps/essimporter/importinventory.hpp b/apps/essimporter/importinventory.hpp index 359e43fa6..8a1594465 100644 --- a/apps/essimporter/importinventory.hpp +++ b/apps/essimporter/importinventory.hpp @@ -21,6 +21,7 @@ namespace ESSImport std::string mId; int mCount; int mCondition; + int mRelativeEquipmentSlot; }; std::vector mItems; From c7d15e6f74a81e007b48ddeb5f3a077ac4812312 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Jan 2015 15:33:39 +0100 Subject: [PATCH 265/740] Revert "Revert "Light charge handling fix"" This reverts commit b95748d044a421c2e02fa54cdc7e8aa902039e6c. --- apps/esmtool/esmtool.cpp | 2 +- apps/essimporter/convertinventory.cpp | 2 +- apps/essimporter/importinventory.cpp | 6 +-- apps/essimporter/importinventory.hpp | 1 - apps/opencs/model/world/columnimp.hpp | 4 +- apps/openmw/mwclass/light.cpp | 56 +++------------------------ apps/openmw/mwclass/light.hpp | 10 ----- apps/openmw/mwworld/cellref.cpp | 20 ++++++++-- apps/openmw/mwworld/cellref.hpp | 3 ++ apps/openmw/mwworld/manualref.hpp | 2 +- components/esm/cellref.cpp | 10 ++--- components/esm/cellref.hpp | 6 ++- components/esm/objectstate.cpp | 10 ++--- components/esm/objectstate.hpp | 2 - 14 files changed, 47 insertions(+), 87 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index a18736bf2..b23ba72f9 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -261,7 +261,7 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info) std::cout << " Faction: '" << ref.mFaction << "'" << std::endl; std::cout << " Faction rank: '" << ref.mFactionRank << "'" << std::endl; std::cout << " Enchantment charge: '" << ref.mEnchantmentCharge << "'\n"; - std::cout << " Uses/health: '" << ref.mCharge << "'\n"; + std::cout << " Uses/health: '" << ref.mChargeInt << "'\n"; std::cout << " Gold value: '" << ref.mGoldValue << "'\n"; std::cout << " Blocked: '" << static_cast(ref.mReferenceBlocked) << "'" << std::endl; std::cout << " Deleted: " << deleted << std::endl; diff --git a/apps/essimporter/convertinventory.cpp b/apps/essimporter/convertinventory.cpp index 6a31be6a3..31272bf5a 100644 --- a/apps/essimporter/convertinventory.cpp +++ b/apps/essimporter/convertinventory.cpp @@ -12,10 +12,10 @@ namespace ESSImport { ESM::ObjectState objstate; objstate.blank(); + objstate.mRef = *it; objstate.mRef.mRefID = Misc::StringUtils::lowerCase(it->mId); objstate.mCount = std::abs(it->mCount); // restocking items have negative count in the savefile // openmw handles them differently, so no need to set any flags - objstate.mRef.mCharge = it->mCondition; state.mItems.push_back(std::make_pair(objstate, it->mRelativeEquipmentSlot)); } } diff --git a/apps/essimporter/importinventory.cpp b/apps/essimporter/importinventory.cpp index 2f5c3c054..a20584ff5 100644 --- a/apps/essimporter/importinventory.cpp +++ b/apps/essimporter/importinventory.cpp @@ -45,9 +45,9 @@ namespace ESSImport // for XSOL and XCHG seen so far, but probably others too item.ESM::CellRef::loadData(esm); - item.mCondition = -1; - // FIXME: for Lights, this is actually a float - esm.getHNOT(item.mCondition, "XHLT"); + int charge=-1; + esm.getHNOT(charge, "XHLT"); + item.mChargeInt = charge; } mItems.push_back(item); diff --git a/apps/essimporter/importinventory.hpp b/apps/essimporter/importinventory.hpp index 8a1594465..99fed9b20 100644 --- a/apps/essimporter/importinventory.hpp +++ b/apps/essimporter/importinventory.hpp @@ -20,7 +20,6 @@ namespace ESSImport { std::string mId; int mCount; - int mCondition; int mRelativeEquipmentSlot; }; std::vector mItems; diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index eba73cf0b..da14bb495 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -1053,13 +1053,13 @@ namespace CSMWorld virtual QVariant get (const Record& record) const { - return record.get().mCharge; + return record.get().mChargeInt; } virtual void set (Record& record, const QVariant& data) { ESXRecordT record2 = record.get(); - record2.mCharge = data.toInt(); + record2.mChargeInt = data.toInt(); record.setModified (record2); } diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index c50ad52d8..35a21b63e 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -26,27 +26,6 @@ #include "../mwrender/actors.hpp" #include "../mwrender/renderinginterface.hpp" -namespace -{ - struct LightCustomData : public MWWorld::CustomData - { - float mTime; - ///< Time remaining - - LightCustomData(MWWorld::Ptr ptr) - { - MWWorld::LiveCellRef *ref = ptr.get(); - mTime = ref->mBase->mData.mTime; - } - ///< Constructs this CustomData from the base values for Ptr. - - virtual MWWorld::CustomData *clone() const - { - return new LightCustomData (*this); - } - }; -} - namespace MWClass { std::string Light::getId (const MWWorld::Ptr& ptr) const @@ -219,17 +198,16 @@ namespace MWClass void Light::setRemainingUsageTime (const MWWorld::Ptr& ptr, float duration) const { - ensureCustomData(ptr); - - float &timeRemaining = dynamic_cast (*ptr.getRefData().getCustomData()).mTime; - timeRemaining = duration; + ptr.getCellRef().setChargeFloat(duration); } float Light::getRemainingUsageTime (const MWWorld::Ptr& ptr) const { - ensureCustomData(ptr); - - return dynamic_cast (*ptr.getRefData().getCustomData()).mTime; + MWWorld::LiveCellRef *ref = ptr.get(); + if (ptr.getCellRef().getCharge() == -1) + return ref->mBase->mData.mTime; + else + return ptr.getCellRef().getChargeFloat(); } MWWorld::Ptr @@ -241,12 +219,6 @@ namespace MWClass return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } - void Light::ensureCustomData (const MWWorld::Ptr& ptr) const - { - if (!ptr.getRefData().getCustomData()) - ptr.getRefData().setCustomData(new LightCustomData(ptr)); - } - bool Light::canSell (const MWWorld::Ptr& item, int npcServices) const { return npcServices & ESM::NPC::Lights; @@ -282,22 +254,6 @@ namespace MWClass return std::make_pair(1,""); } - void Light::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) - const - { - ensureCustomData (ptr); - - dynamic_cast (*ptr.getRefData().getCustomData()).mTime = state.mTime; - } - - void Light::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) - const - { - ensureCustomData (ptr); - - state.mTime = dynamic_cast (*ptr.getRefData().getCustomData()).mTime; - } - std::string Light::getSound(const MWWorld::Ptr& ptr) const { return ptr.get()->mBase->mSound; diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index bbca30113..8658375b7 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -10,8 +10,6 @@ namespace MWClass virtual MWWorld::Ptr copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; - void ensureCustomData (const MWWorld::Ptr& ptr) const; - public: /// Return ID of \a ptr @@ -75,14 +73,6 @@ namespace MWClass std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; - virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) - const; - ///< Read additional state from \a state into \a ptr. - - virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) - const; - ///< Write additional state from \a ptr into \a state. - virtual std::string getSound(const MWWorld::Ptr& ptr) const; }; } diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index aa6627de5..744e0e27a 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -81,15 +81,29 @@ namespace MWWorld int CellRef::getCharge() const { - return mCellRef.mCharge; + return mCellRef.mChargeInt; } void CellRef::setCharge(int charge) { - if (charge != mCellRef.mCharge) + if (charge != mCellRef.mChargeInt) { mChanged = true; - mCellRef.mCharge = charge; + mCellRef.mChargeInt = charge; + } + } + + float CellRef::getChargeFloat() const + { + return mCellRef.mChargeFloat; + } + + void CellRef::setChargeFloat(float charge) + { + if (charge != mCellRef.mChargeFloat) + { + mChanged = true; + mCellRef.mChargeFloat = charge; } } diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index a7ffbe08b..054fd7fc6 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -60,8 +60,11 @@ namespace MWWorld // For weapon or armor, this is the remaining item health. // For tools (lockpicks, probes, repair hammer) it is the remaining uses. + // If this returns int(-1) it means full health. int getCharge() const; + float getChargeFloat() const; // Implemented as union with int charge void setCharge(int charge); + void setChargeFloat(float charge); // The NPC that owns this object (and will get angry if you steal it) std::string getOwner() const; diff --git a/apps/openmw/mwworld/manualref.hpp b/apps/openmw/mwworld/manualref.hpp index 4eb93543b..f32b07471 100644 --- a/apps/openmw/mwworld/manualref.hpp +++ b/apps/openmw/mwworld/manualref.hpp @@ -28,7 +28,7 @@ namespace MWWorld cellRef.mRefID = name; cellRef.mScale = 1; cellRef.mFactionRank = 0; - cellRef.mCharge = -1; + cellRef.mChargeInt = -1; cellRef.mGoldValue = 1; cellRef.mEnchantmentCharge = -1; cellRef.mTeleport = false; diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index cd9fe8570..dfc3052ee 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -46,12 +46,12 @@ void ESM::CellRef::loadData(ESMReader &esm) esm.getHNOT (mFactionRank, "INDX"); mGoldValue = 1; - mCharge = -1; + mChargeInt = -1; mEnchantmentCharge = -1; esm.getHNOT (mEnchantmentCharge, "XCHG"); - esm.getHNOT (mCharge, "INTV"); + esm.getHNOT (mChargeInt, "INTV"); esm.getHNOT (mGoldValue, "NAM9"); @@ -106,8 +106,8 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) cons if (mEnchantmentCharge != -1) esm.writeHNT("XCHG", mEnchantmentCharge); - if (mCharge != -1) - esm.writeHNT("INTV", mCharge); + if (mChargeInt != -1) + esm.writeHNT("INTV", mChargeInt); if (mGoldValue != 1) { esm.writeHNT("NAM9", mGoldValue); @@ -146,7 +146,7 @@ void ESM::CellRef::blank() mSoul.clear(); mFaction.clear(); mFactionRank = -2; - mCharge = -1; + mChargeInt = -1; mEnchantmentCharge = -1; mGoldValue = 0; mDestCell.clear(); diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index 7aa0e4d44..56932aa4d 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -59,7 +59,11 @@ namespace ESM // For weapon or armor, this is the remaining item health. // For tools (lockpicks, probes, repair hammer) it is the remaining uses. - int mCharge; + union + { + int mChargeInt; + float mChargeFloat; + }; // Remaining enchantment charge. This could be -1 if the charge was not touched yet (i.e. full). float mEnchantmentCharge; diff --git a/components/esm/objectstate.cpp b/components/esm/objectstate.cpp index 66fd49663..9ef1ccf80 100644 --- a/components/esm/objectstate.cpp +++ b/components/esm/objectstate.cpp @@ -24,9 +24,9 @@ void ESM::ObjectState::load (ESMReader &esm) esm.getHNOT (mLocalRotation, "LROT", 12); - // used for lights only - mTime = 0; - esm.getHNOT (mTime, "LTIM"); + // obsolete + int unused; + esm.getHNOT(unused, "LTIM"); // FIXME: assuming "false" as default would make more sense, but also break compatibility with older save files mHasCustomState = true; @@ -55,9 +55,6 @@ void ESM::ObjectState::save (ESMWriter &esm, bool inInventory) const esm.writeHNT ("LROT", mLocalRotation, 12); } - if (mTime) - esm.writeHNT ("LTIM", mTime); - if (!mHasCustomState) esm.writeHNT ("HCUS", false); } @@ -74,7 +71,6 @@ void ESM::ObjectState::blank() mPosition.rot[i] = 0; mLocalRotation[i] = 0; } - mTime = 0; mHasCustomState = true; } diff --git a/components/esm/objectstate.hpp b/components/esm/objectstate.hpp index b03689653..d1077733a 100644 --- a/components/esm/objectstate.hpp +++ b/components/esm/objectstate.hpp @@ -26,8 +26,6 @@ namespace ESM ESM::Position mPosition; float mLocalRotation[3]; - float mTime; // Used for lights only. Overhead should not be so awful, besides CellRef isn't OO either - // Is there any class-specific state following the ObjectState bool mHasCustomState; From 69676906aef59e4179d8a194425e77a09cb5d812 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 21 Jan 2015 21:24:25 +0100 Subject: [PATCH 266/740] Don't clear known spells when reading from the savegame This is needed because the .ess format doesn't include the racial spells in the player's spell list. --- apps/essimporter/importplayer.cpp | 4 ++++ apps/openmw/mwmechanics/spells.cpp | 20 ++++++++------------ components/esm/spellstate.hpp | 1 + 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/apps/essimporter/importplayer.cpp b/apps/essimporter/importplayer.cpp index 285605068..ea9f1932c 100644 --- a/apps/essimporter/importplayer.cpp +++ b/apps/essimporter/importplayer.cpp @@ -23,6 +23,10 @@ namespace ESSImport mKnownDialogueTopics.push_back(esm.getHString()); } + if (esm.isNextSub("MNAM")) + esm.skipHSub(); // If this field is here it seems to specify the interior cell the player is in, + // but it's not always here, so it's kinda useless + esm.getHNT(mPNAM, "PNAM"); if (esm.isNextSub("SNAM")) diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index 1f8ada06d..dcbd3f09f 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -312,21 +312,17 @@ namespace MWMechanics void Spells::readState(const ESM::SpellState &state) { - mSpells = state.mSpells; - mSelectedSpell = state.mSelectedSpell; - - // Discard spells that are no longer available due to changed content files - for (TContainer::iterator iter = mSpells.begin(); iter!=mSpells.end();) + for (TContainer::const_iterator it = state.mSpells.begin(); it != state.mSpells.end(); ++it) { - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().search(iter->first); - if (!spell) + // Discard spells that are no longer available due to changed content files + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().search(it->first); + if (spell) { - if (iter->first == mSelectedSpell) - mSelectedSpell = ""; - mSpells.erase(iter++); + mSpells[it->first] = it->second; + + if (it->first == state.mSelectedSpell) + mSelectedSpell = it->first; } - else - ++iter; } // No need to discard spells here (doesn't really matter if non existent ids are kept) diff --git a/components/esm/spellstate.hpp b/components/esm/spellstate.hpp index 2ab27e908..028e6a387 100644 --- a/components/esm/spellstate.hpp +++ b/components/esm/spellstate.hpp @@ -12,6 +12,7 @@ namespace ESM class ESMReader; class ESMWriter; + // NOTE: spell ids must be lower case struct SpellState { struct CorprusStats From acf8461841546f5691f3c2e817af7a0d59116433 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 21 Jan 2015 22:25:37 +0100 Subject: [PATCH 267/740] ESSImport: some fixes --- apps/essimporter/converter.cpp | 22 ++++++++++------------ apps/essimporter/converter.hpp | 9 +++++++-- apps/essimporter/importacdt.cpp | 10 ++++------ apps/essimporter/importacdt.hpp | 4 +++- apps/essimporter/importcellref.cpp | 21 ++++++++++++++++----- apps/essimporter/importcellref.hpp | 10 +++------- apps/essimporter/importcrec.cpp | 10 ++++++++++ apps/essimporter/importnpcc.cpp | 3 +++ 8 files changed, 56 insertions(+), 33 deletions(-) diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 099987762..81521a028 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -27,6 +27,8 @@ namespace objstate.mEnabled = cellref.mEnabled; objstate.mPosition = cellref.mPos; objstate.mRef.mRefNum = cellref.mRefNum; + if (cellref.mDeleted) + objstate.mCount = 0; } bool isIndexedRefId(const std::string& indexedRefId) @@ -34,6 +36,10 @@ namespace if (indexedRefId.size() <= 8) return false; + if (indexedRefId.find_first_not_of("0123456789") == std::string::npos) + return false; // entirely numeric refid, this is a reference to + // a dynamically created record e.g. player-enchanted weapon + std::string index = indexedRefId.substr(indexedRefId.size()-8); if(index.find_first_not_of("0123456789ABCDEF") == std::string::npos ) return true; @@ -136,13 +142,6 @@ namespace ESSImport { CellRef ref; ref.load (esm); - if (esm.isNextSub("DELE")) - { - // TODO - // strangely this can be e.g. 52 instead of just 1, - //std::cout << "deleted ref " << ref.mIndexedRefId << std::endl; - esm.skipHSub(); - } cellrefs.push_back(ref); } @@ -201,8 +200,7 @@ namespace ESSImport for (std::vector::const_iterator refIt = cell.mRefs.begin(); refIt != cell.mRefs.end(); ++refIt) { const CellRef& cellref = *refIt; - ESM::CellRef out; - out.blank(); + ESM::CellRef out (cellref); if (!isIndexedRefId(cellref.mIndexedRefId)) { @@ -241,8 +239,8 @@ namespace ESSImport objstate.mRef.mRefID = idLower; // probably need more micromanagement here so we don't overwrite values // from the ESM with default values - convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats); - convertNpcData(cellref.mActorData, objstate.mNpcStats); + convertACDT(cellref.mACDT, objstate.mCreatureStats); + convertNpcData(cellref, objstate.mNpcStats); convertNPCC(npccIt->second, objstate); convertCellRef(cellref, objstate); esm.writeHNT ("OBJE", ESM::REC_NPC_); @@ -273,7 +271,7 @@ namespace ESSImport objstate.blank(); objstate.mRef = out; objstate.mRef.mRefID = idLower; - convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats); + convertACDT(cellref.mACDT, objstate.mCreatureStats); // probably need more micromanagement here so we don't overwrite values // from the ESM with default values convertCREC(crecIt->second, objstate); diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index b68f9a218..9f6ad49df 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -90,14 +90,19 @@ public: ESM::NPC npc; std::string id = esm.getHNString("NAME"); npc.load(esm); - if (id != "player") // seems to occur sometimes, with "chargen X" names + if (id != "player") + { + // this handles changes to the NPC struct, but since there is no index here + // it will apply to ALL instances of the class. seems to be the reason for the + // "feature" in MW where changing AI settings of one guard will change it for all guards of that refID. std::cerr << "non-player NPC record: " << id << std::endl; + } else { mContext->mPlayer.mObject.mCreatureStats.mLevel = npc.mNpdt52.mLevel; mContext->mPlayerBase = npc; std::map empty; - // FIXME: player start spells, racial spells and birthsign spells aren't listed here, + // FIXME: player start spells and birthsign spells aren't listed here, // need to fix openmw to account for this for (std::vector::const_iterator it = npc.mSpells.mList.begin(); it != npc.mSpells.mList.end(); ++it) mContext->mPlayer.mObject.mCreatureStats.mSpells.mSpells[*it] = empty; diff --git a/apps/essimporter/importacdt.cpp b/apps/essimporter/importacdt.cpp index 84c800897..4d4a87a35 100644 --- a/apps/essimporter/importacdt.cpp +++ b/apps/essimporter/importacdt.cpp @@ -9,18 +9,16 @@ namespace ESSImport void ActorData::load(ESM::ESMReader &esm) { - // unsure at which point between NAME and ESM::CellRef - if (esm.isNextSub("MNAM")) - esm.skipHSub(); - if (esm.isNextSub("ACTN")) esm.skipHSub(); if (esm.isNextSub("STPR")) esm.skipHSub(); - ESM::CellRef bla; - bla.ESM::CellRef::loadData(esm); + if (esm.isNextSub("MNAM")) + esm.skipHSub(); + + ESM::CellRef::loadData(esm); // FIXME: not all actors have this, add flag esm.getHNOT(mACDT, "ACDT"); diff --git a/apps/essimporter/importacdt.hpp b/apps/essimporter/importacdt.hpp index 79f67d2c2..271f6df74 100644 --- a/apps/essimporter/importacdt.hpp +++ b/apps/essimporter/importacdt.hpp @@ -3,6 +3,8 @@ #include +#include + namespace ESM { struct ESMReader; @@ -37,7 +39,7 @@ namespace ESSImport }; #pragma pack(pop) - struct ActorData + struct ActorData : public ESM::CellRef { ACDT mACDT; diff --git a/apps/essimporter/importcellref.cpp b/apps/essimporter/importcellref.cpp index fd58d5bc1..7c4af1e02 100644 --- a/apps/essimporter/importcellref.cpp +++ b/apps/essimporter/importcellref.cpp @@ -7,6 +7,8 @@ namespace ESSImport void CellRef::load(ESM::ESMReader &esm) { + blank(); + // (FRMR subrecord name is already read by the loop in ConvertCell) esm.getHT(mRefNum.mIndex); // FRMR @@ -25,17 +27,26 @@ namespace ESSImport esm.getHT(lvcr); //std::cout << "LVCR: " << (int)lvcr << std::endl; } - mActorData.load(esm); + ActorData::load(esm); mEnabled = true; esm.getHNOT(mEnabled, "ZNAM"); - // should occur for all references but not levelled creature spawners - esm.getHNOT(mPos, "DATA", 24); - - // i've seen DATA record TWICE on a creature record - and with the exact same content too! weird + // DATA should occur for all references, except leveled creature spawners + // I've seen DATA *twice* on a creature record, and with the exact same content too! weird // alarmvoi0000.ess esm.getHNOT(mPos, "DATA", 24); + esm.getHNOT(mPos, "DATA", 24); + + mDeleted = 0; + if (esm.isNextSub("DELE")) + { + int deleted; + esm.getHT(deleted); + // Neither of this seems to work right... + //mDeleted = (deleted != 0); + //mDeleted = (deleted&0x1); + } if (esm.isNextSub("MVRF")) { diff --git a/apps/essimporter/importcellref.hpp b/apps/essimporter/importcellref.hpp index 77763d434..556ed19bf 100644 --- a/apps/essimporter/importcellref.hpp +++ b/apps/essimporter/importcellref.hpp @@ -15,20 +15,16 @@ namespace ESM namespace ESSImport { - // Not sure if we can share any code with ESM::CellRef here - struct CellRef + struct CellRef : public ActorData { std::string mIndexedRefId; - ESM::RefNum mRefNum; - - ActorData mActorData; - - ESM::Position mPos; std::string mScript; bool mEnabled; + bool mDeleted; + void load(ESM::ESMReader& esm); }; diff --git a/apps/essimporter/importcrec.cpp b/apps/essimporter/importcrec.cpp index 9cf455588..28e5ac56f 100644 --- a/apps/essimporter/importcrec.cpp +++ b/apps/essimporter/importcrec.cpp @@ -14,6 +14,16 @@ namespace ESSImport float scale; esm.getHNOT(scale, "XSCL"); + // FIXME: use AiPackageList, need to fix getSubName() + if (esm.isNextSub("AI_W")) + esm.skipHSub(); + if (esm.isNextSub("AI_E")) + esm.skipHSub(); + if (esm.isNextSub("AI_T")) + esm.skipHSub(); + if (esm.isNextSub("AI_F")) + esm.skipHSub(); + mInventory.load(esm); } diff --git a/apps/essimporter/importnpcc.cpp b/apps/essimporter/importnpcc.cpp index c389ede7f..7b8dda371 100644 --- a/apps/essimporter/importnpcc.cpp +++ b/apps/essimporter/importnpcc.cpp @@ -9,6 +9,9 @@ namespace ESSImport { esm.getHNT(mNPDT, "NPDT"); + // FIXME: use AiPackageList, need to fix getSubName() + if (esm.isNextSub("AI_W")) + esm.skipHSub(); if (esm.isNextSub("AI_E")) esm.skipHSub(); if (esm.isNextSub("AI_T")) From 1e92cab3e76b9b258ae813eb43f020ecba2da754 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 21 Jan 2015 23:35:09 +0100 Subject: [PATCH 268/740] ESSImport: read dialogue/journal records, not converted yet --- apps/essimporter/CMakeLists.txt | 5 ++ apps/essimporter/converter.hpp | 81 +++++++++++++++++++++++++++++++-- apps/essimporter/importdial.cpp | 13 ++++++ apps/essimporter/importdial.hpp | 20 ++++++++ apps/essimporter/importer.cpp | 10 +++- apps/essimporter/importgame.cpp | 13 ++++++ apps/essimporter/importgame.hpp | 33 ++++++++++++++ apps/essimporter/importinfo.cpp | 14 ++++++ apps/essimporter/importinfo.hpp | 24 ++++++++++ apps/essimporter/importjour.cpp | 13 ++++++ apps/essimporter/importjour.hpp | 25 ++++++++++ apps/essimporter/importques.cpp | 14 ++++++ apps/essimporter/importques.hpp | 28 ++++++++++++ components/esm/defs.hpp | 2 +- components/esm/loadnpcc.hpp | 17 ------- 15 files changed, 290 insertions(+), 22 deletions(-) create mode 100644 apps/essimporter/importdial.cpp create mode 100644 apps/essimporter/importdial.hpp create mode 100644 apps/essimporter/importgame.cpp create mode 100644 apps/essimporter/importgame.hpp create mode 100644 apps/essimporter/importinfo.cpp create mode 100644 apps/essimporter/importinfo.hpp create mode 100644 apps/essimporter/importjour.cpp create mode 100644 apps/essimporter/importjour.hpp create mode 100644 apps/essimporter/importques.cpp create mode 100644 apps/essimporter/importques.hpp diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index 8d1af714d..70eaefe2c 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -9,6 +9,11 @@ set(ESSIMPORTER_FILES importinventory.cpp importklst.cpp importcntc.cpp + importgame.cpp + importinfo.cpp + importdial.cpp + importques.cpp + importjour.cpp importercontext.cpp converter.cpp convertacdt.cpp diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 9f6ad49df..4ca0e8386 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include "importcrec.hpp" #include "importcntc.hpp" @@ -19,6 +20,11 @@ #include "importercontext.hpp" #include "importcellref.hpp" #include "importklst.hpp" +#include "importgame.hpp" +#include "importinfo.hpp" +#include "importdial.hpp" +#include "importques.hpp" +#include "importjour.hpp" #include "convertacdt.hpp" #include "convertnpcc.hpp" @@ -86,16 +92,15 @@ class ConvertNPC : public Converter public: virtual void read(ESM::ESMReader &esm) { - // this is always the player ESM::NPC npc; std::string id = esm.getHNString("NAME"); npc.load(esm); if (id != "player") { - // this handles changes to the NPC struct, but since there is no index here + // TODO: + // this should handle changes to the NPC struct, but since there is no index here // it will apply to ALL instances of the class. seems to be the reason for the // "feature" in MW where changing AI settings of one guard will change it for all guards of that refID. - std::cerr << "non-player NPC record: " << id << std::endl; } else { @@ -110,6 +115,18 @@ public: } }; +class ConvertCREA : public Converter +{ +public: + virtual void read(ESM::ESMReader &esm) + { + // See comment in ConvertNPC + ESM::Creature creature; + std::string id = esm.getHNString("NAME"); + creature.load(esm); + } +}; + class ConvertGlobal : public DefaultConverter { public: @@ -350,6 +367,64 @@ private: std::multimap mFactionStolenItems; }; +/// Seen responses for a dialogue topic? +/// Each DIAL record is followed by a number of INFO records, I believe, just like in ESMs +/// Dialogue conversion problems (probably have to adjust OpenMW format) - +/// - Journal is stored in one continuous HTML markup rather than each entry separately with associated info ID. +/// - Seen dialogue responses only store the INFO id, rather than the fulltext. +/// - Quest stages only store the INFO id, rather than the journal entry fulltext. +class ConvertINFO : public Converter +{ +public: + virtual void read(ESM::ESMReader& esm) + { + INFO info; + info.load(esm); + } +}; + +class ConvertDIAL : public Converter +{ +public: + virtual void read(ESM::ESMReader& esm) + { + std::string id = esm.getHNString("NAME"); + DIAL dial; + dial.load(esm); + } +}; + +class ConvertQUES : public Converter +{ +public: + virtual void read(ESM::ESMReader& esm) + { + std::string id = esm.getHNString("NAME"); + QUES quest; + quest.load(esm); + } +}; + +class ConvertJOUR : public Converter +{ +public: + virtual void read(ESM::ESMReader& esm) + { + JOUR journal; + journal.load(esm); + } +}; + +class ConvertGAME : public Converter +{ +public: + virtual void read(ESM::ESMReader &esm) + { + GAME game; + game.load(esm); + } +}; + } #endif diff --git a/apps/essimporter/importdial.cpp b/apps/essimporter/importdial.cpp new file mode 100644 index 000000000..228d00a5a --- /dev/null +++ b/apps/essimporter/importdial.cpp @@ -0,0 +1,13 @@ +#include "importdial.hpp" + +#include + +namespace ESSImport +{ + + void DIAL::load(ESM::ESMReader &esm) + { + esm.getHNT(mIndex, "XIDX"); + } + +} diff --git a/apps/essimporter/importdial.hpp b/apps/essimporter/importdial.hpp new file mode 100644 index 000000000..fe4b0c5b4 --- /dev/null +++ b/apps/essimporter/importdial.hpp @@ -0,0 +1,20 @@ +#ifndef OPENMW_ESSIMPORT_IMPORTDIAL_H +#define OPENMW_ESSIMPORT_IMPORTDIAL_H +namespace ESM +{ + struct ESMReader; +} + +namespace ESSImport +{ + + struct DIAL + { + int mIndex; // Journal index + + void load(ESM::ESMReader& esm); + }; + +} + +#endif diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index c2092ea4d..8603200da 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -201,11 +201,14 @@ namespace ESSImport const unsigned int recFMAP = ESM::FourCC<'F','M','A','P'>::value; const unsigned int recKLST = ESM::FourCC<'K','L','S','T'>::value; 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; std::map > converters; converters[ESM::REC_GLOB] = boost::shared_ptr(new ConvertGlobal()); converters[ESM::REC_BOOK] = boost::shared_ptr(new ConvertBook()); converters[ESM::REC_NPC_] = boost::shared_ptr(new ConvertNPC()); + converters[ESM::REC_CREA] = boost::shared_ptr(new ConvertCREA()); converters[ESM::REC_NPCC] = boost::shared_ptr(new ConvertNPCC()); converters[ESM::REC_CREC] = boost::shared_ptr(new ConvertCREC()); converters[recREFR ] = boost::shared_ptr(new ConvertREFR()); @@ -213,6 +216,7 @@ namespace ESSImport converters[recFMAP ] = boost::shared_ptr(new ConvertFMAP()); converters[recKLST ] = boost::shared_ptr(new ConvertKLST()); converters[recSTLN ] = boost::shared_ptr(new ConvertSTLN()); + converters[recGAME ] = boost::shared_ptr(new ConvertGAME()); converters[ESM::REC_CELL] = boost::shared_ptr(new ConvertCell()); converters[ESM::REC_ALCH] = boost::shared_ptr(new DefaultConverter()); converters[ESM::REC_CLAS] = boost::shared_ptr(new ConvertClass()); @@ -226,6 +230,10 @@ namespace ESSImport converters[ESM::REC_LEVI] = boost::shared_ptr(new DefaultConverter()); converters[ESM::REC_CNTC] = boost::shared_ptr(new ConvertCNTC()); converters[ESM::REC_FACT] = boost::shared_ptr(new ConvertFACT()); + converters[ESM::REC_INFO] = boost::shared_ptr(new ConvertINFO()); + converters[ESM::REC_DIAL] = boost::shared_ptr(new ConvertDIAL()); + converters[ESM::REC_QUES] = boost::shared_ptr(new ConvertQUES()); + converters[recJOUR ] = boost::shared_ptr(new ConvertJOUR()); std::set unknownRecords; @@ -248,7 +256,7 @@ namespace ESSImport else { if (unknownRecords.insert(n.val).second) - std::cerr << "unknown record " << n.toString() << std::endl; + std::cerr << "unknown record " << n.toString() << " (0x" << std::hex << esm.getFileOffset() << ")" << std::endl; esm.skipRecord(); } diff --git a/apps/essimporter/importgame.cpp b/apps/essimporter/importgame.cpp new file mode 100644 index 000000000..0b3a4f1a7 --- /dev/null +++ b/apps/essimporter/importgame.cpp @@ -0,0 +1,13 @@ +#include "importgame.hpp" + +#include + +namespace ESSImport +{ + +void GAME::load(ESM::ESMReader &esm) +{ + esm.getHNT(mGMDT, "GMDT"); +} + +} diff --git a/apps/essimporter/importgame.hpp b/apps/essimporter/importgame.hpp new file mode 100644 index 000000000..7bb814320 --- /dev/null +++ b/apps/essimporter/importgame.hpp @@ -0,0 +1,33 @@ +#ifndef OPENMW_ESSIMPORT_GAME_H +#define OPENMW_ESSIMPORT_GAME_H + +namespace ESM +{ + class ESMReader; +} + +namespace ESSImport +{ + + /// Weather data + struct GAME + { + struct GMDT + { + char mCellName[64]; + int mFogColour; + float mFogDensity; + int mCurrentWeather, mNextWeather; + int mWeatherTransition; // 0-100 transition between weathers, top 3 bytes may be garbage + float mTimeOfNextTransition; // weather changes when gamehour == timeOfNextTransition + int masserPhase, secundaPhase; // top 3 bytes may be garbage + }; + + GMDT mGMDT; + + void load(ESM::ESMReader& esm); + }; + +} + +#endif diff --git a/apps/essimporter/importinfo.cpp b/apps/essimporter/importinfo.cpp new file mode 100644 index 000000000..113155370 --- /dev/null +++ b/apps/essimporter/importinfo.cpp @@ -0,0 +1,14 @@ +#include "importinfo.hpp" + +#include + +namespace ESSImport +{ + + void INFO::load(ESM::ESMReader &esm) + { + mInfo = esm.getHNString("INAM"); + mActorRefId = esm.getHNString("ACDT"); + } + +} diff --git a/apps/essimporter/importinfo.hpp b/apps/essimporter/importinfo.hpp new file mode 100644 index 000000000..08f588f8d --- /dev/null +++ b/apps/essimporter/importinfo.hpp @@ -0,0 +1,24 @@ +#ifndef OPENMW_ESSIMPORT_IMPORTINFO_H +#define OPENMW_ESSIMPORT_IMPORTINFO_H + +#include + +namespace ESM +{ + struct ESMReader; +} + +namespace ESSImport +{ + + struct INFO + { + std::string mInfo; + std::string mActorRefId; + + void load(ESM::ESMReader& esm); + }; + +} + +#endif diff --git a/apps/essimporter/importjour.cpp b/apps/essimporter/importjour.cpp new file mode 100644 index 000000000..e5d24e113 --- /dev/null +++ b/apps/essimporter/importjour.cpp @@ -0,0 +1,13 @@ +#include "importjour.hpp" + +#include + +namespace ESSImport +{ + + void JOUR::load(ESM::ESMReader &esm) + { + mText = esm.getHNString("NAME"); + } + +} diff --git a/apps/essimporter/importjour.hpp b/apps/essimporter/importjour.hpp new file mode 100644 index 000000000..fe8775a93 --- /dev/null +++ b/apps/essimporter/importjour.hpp @@ -0,0 +1,25 @@ +#ifndef OPENMW_ESSIMPORT_IMPORTJOUR_H +#define OPENMW_ESSIMPORT_IMPORTJOUR_H + +#include + +namespace ESM +{ + struct ESMReader; +} + +namespace ESSImport +{ + + /// Journal + struct JOUR + { + // The entire journal, in HTML + std::string mText; + + void load(ESM::ESMReader& esm); + }; + +} + +#endif diff --git a/apps/essimporter/importques.cpp b/apps/essimporter/importques.cpp new file mode 100644 index 000000000..78b779e43 --- /dev/null +++ b/apps/essimporter/importques.cpp @@ -0,0 +1,14 @@ +#include "importques.hpp" + +#include + +namespace ESSImport +{ + + void QUES::load(ESM::ESMReader &esm) + { + while (esm.isNextSub("DATA")) + mInfo.push_back(esm.getHString()); + } + +} diff --git a/apps/essimporter/importques.hpp b/apps/essimporter/importques.hpp new file mode 100644 index 000000000..d7e718b92 --- /dev/null +++ b/apps/essimporter/importques.hpp @@ -0,0 +1,28 @@ +#ifndef OPENMW_ESSIMPORT_IMPORTQUES_H +#define OPENMW_ESSIMPORT_IMPORTQUES_H + +#include +#include + +namespace ESM +{ + struct ESMReader; +} + +namespace ESSImport +{ + + /// State for a quest + /// Presumably this record only exists when Tribunal is installed, + /// since pre-Tribunal there weren't any quest names in the data files. + struct QUES + { + std::string mName; // NAME, should be assigned from outside as usual + std::vector mInfo; // list of journal entries for the quest + + void load(ESM::ESMReader& esm); + }; + +} + +#endif diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index fe45d6914..effe9a3f1 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -97,7 +97,7 @@ enum RecNameInts // format 0 - saved games REC_SAVE = 0x45564153, - REC_JOUR = 0x524f55a4, + REC_JOUR = 0x524f55a4, // TODO: this is actually "\nOUR" rather than "JOUR", fix REC_QUES = 0x53455551, REC_GSCR = 0x52435347, REC_PLAY = 0x59414c50, diff --git a/components/esm/loadnpcc.hpp b/components/esm/loadnpcc.hpp index 6c087fd01..6b3cd533f 100644 --- a/components/esm/loadnpcc.hpp +++ b/components/esm/loadnpcc.hpp @@ -20,24 +20,7 @@ class ESMWriter; * SCPT records do not define new scripts, but assign values to the * variables of existing ones. * - * STLN - stolen items, ONAM is the owner - * - * GAME - weather data - * struct GMDT - { - char mCellName[64]; - int mFogColour; - float mFogDensity; - int mCurrentWeather, mNextWeather; - int mWeatherTransition; // 0-100 transition between weathers, top 3 bytes may be garbage - float mTimeOfNextTransition; // weather changes when gamehour == timeOfNextTransition - int masserPhase, secundaPhase; // top 3 bytes may be garbage - }; - * * VFXM, SPLM - no clue - * KLST - kill counter - * - * PCDT - seems to contain a lot of DNAMs, strings? * * FMAP - MAPH and MAPD, global map image. * From 5ce8a931a55fb74041d3690eb1ac4cffe4c73970 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 03:34:44 +0100 Subject: [PATCH 269/740] ESSImport: fix a subrecord ordering issue --- apps/essimporter/importcellref.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/essimporter/importcellref.cpp b/apps/essimporter/importcellref.cpp index 7c4af1e02..845c574e4 100644 --- a/apps/essimporter/importcellref.cpp +++ b/apps/essimporter/importcellref.cpp @@ -19,6 +19,7 @@ namespace ESSImport mIndexedRefId = esm.getHNString("NAME"); + ActorData::load(esm); if (esm.isNextSub("LVCR")) { // occurs on leveled creature spawner references @@ -27,7 +28,6 @@ namespace ESSImport esm.getHT(lvcr); //std::cout << "LVCR: " << (int)lvcr << std::endl; } - ActorData::load(esm); mEnabled = true; esm.getHNOT(mEnabled, "ZNAM"); From cc7be1600d7491f8d23081ab6e7a413c943454fc Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 03:36:12 +0100 Subject: [PATCH 270/740] Make missing hair/head in NpcAnimation non-fatal for consistency with addOrReplaceIndividualPart --- apps/openmw/mwrender/npcanimation.cpp | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 5e73a95f2..a8ba1abf5 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -263,17 +263,27 @@ void NpcAnimation::updateNpcBase() } else { - if (isVampire) + mHeadModel = ""; + if (isVampire) // FIXME: fall back to regular head when getVampireHead fails? mHeadModel = getVampireHead(mNpc->mRace, mNpc->mFlags & ESM::NPC::Female); else if (!mNpc->mHead.empty()) - mHeadModel = "meshes\\" + store.get().find(mNpc->mHead)->mModel; - else - mHeadModel = ""; + { + const ESM::BodyPart* bp = store.get().search(mNpc->mHead); + if (bp) + mHeadModel = "meshes\\" + bp->mModel; + else + std::cerr << "Failed to load body part '" << mNpc->mHead << "'" << std::endl; + } + mHairModel = ""; if (!mNpc->mHair.empty()) - mHairModel = "meshes\\" + store.get().find(mNpc->mHair)->mModel; - else - mHairModel = ""; + { + const ESM::BodyPart* bp = store.get().search(mNpc->mHair); + if (bp) + mHairModel = "meshes\\" + bp->mModel; + else + std::cerr << "Failed to load body part '" << mNpc->mHair << "'" << std::endl; + } } bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0; From 0fd5575efee6495d0fa2eb4322457e543b2d69de Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 03:39:00 +0100 Subject: [PATCH 271/740] Improve warning message in ContainerStore::readState --- apps/openmw/mwworld/containerstore.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index ba70e2f8f..57621b7a4 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -688,8 +688,11 @@ void MWWorld::ContainerStore::readState (const ESM::InventoryState& state) case ESM::REC_REPA: getState (repairs, iter->first); break; case ESM::REC_WEAP: setSlot (getState (weapons, iter->first), slot); break; case ESM::REC_LIGH: setSlot (getState (lights, iter->first), slot); break; + case 0: + std::cerr << "Dropping reference to '" << state.mRef.mRefID << "' (object no longer exists)" << std::endl; + break; default: - std::cerr << "invalid item type in inventory state, refid " << state.mRef.mRefID << std::endl; + std::cerr << "Invalid item type in inventory state, refid " << state.mRef.mRefID << std::endl; break; } } From 98402e579de14b6e203e4073481ef0fb689e2553 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 03:39:37 +0100 Subject: [PATCH 272/740] ESSImport: fix non-existing items in player record causing load failure in OpenMW --- apps/essimporter/converter.hpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 4ca0e8386..a88a364d2 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -111,6 +111,14 @@ public: // need to fix openmw to account for this for (std::vector::const_iterator it = npc.mSpells.mList.begin(); it != npc.mSpells.mList.end(); ++it) mContext->mPlayer.mObject.mCreatureStats.mSpells.mSpells[*it] = empty; + + // Clear the list now that we've written it, this prevents issues cropping up with + // ensureCustomData() in OpenMW tripping over no longer existing spells, where an error would be fatal. + mContext->mPlayerBase.mSpells.mList.clear(); + + // Same with inventory. Actually it's strange this would contain something, since there's already an + // inventory list in NPCC. There seems to be a fair amount of redundancy in this format. + mContext->mPlayerBase.mInventory.mList.clear(); } } }; @@ -127,6 +135,10 @@ public: } }; +// Do we need ConvertCONT? +// I've seen a CONT record in a certain save file, but the container contents in it +// were identical to a corresponding CNTC record. See previous comment about redundancy... + class ConvertGlobal : public DefaultConverter { public: From e2031279520aefbe00f053bd9dd75e2f842e2198 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 03:54:33 +0100 Subject: [PATCH 273/740] ESSImport: read script variables (not converted yet) --- apps/essimporter/CMakeLists.txt | 2 + apps/essimporter/converter.hpp | 12 ++++++ apps/essimporter/importacdt.cpp | 13 +------ apps/essimporter/importacdt.hpp | 4 +- apps/essimporter/importer.cpp | 1 + apps/essimporter/importinventory.cpp | 13 +------ apps/essimporter/importinventory.hpp | 2 + apps/essimporter/importscpt.cpp | 20 ++++++++++ apps/essimporter/importscpt.hpp | 32 ++++++++++++++++ apps/essimporter/importscri.cpp | 55 ++++++++++++++++++++++++++++ apps/essimporter/importscri.hpp | 30 +++++++++++++++ components/esm/loadscpt.cpp | 32 ---------------- components/esm/loadscpt.hpp | 5 +++ 13 files changed, 164 insertions(+), 57 deletions(-) create mode 100644 apps/essimporter/importscpt.cpp create mode 100644 apps/essimporter/importscpt.hpp create mode 100644 apps/essimporter/importscri.cpp create mode 100644 apps/essimporter/importscri.hpp diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index 70eaefe2c..5db3a86dc 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -14,6 +14,8 @@ set(ESSIMPORTER_FILES importdial.cpp importques.cpp importjour.cpp + importscri.cpp + importscpt.cpp importercontext.cpp converter.cpp convertacdt.cpp diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index a88a364d2..9894de299 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -25,6 +25,7 @@ #include "importdial.hpp" #include "importques.hpp" #include "importjour.hpp" +#include "importscpt.hpp" #include "convertacdt.hpp" #include "convertnpcc.hpp" @@ -437,6 +438,17 @@ public: } }; +/// Running global script +class ConvertSCPT : public Converter +{ +public: + virtual void read(ESM::ESMReader &esm) + { + SCPT script; + script.load(esm); + } +}; + } #endif diff --git a/apps/essimporter/importacdt.cpp b/apps/essimporter/importacdt.cpp index 4d4a87a35..e590e2826 100644 --- a/apps/essimporter/importacdt.cpp +++ b/apps/essimporter/importacdt.cpp @@ -81,18 +81,7 @@ namespace ESSImport if (esm.isNextSub("CRED")) // creature only esm.getHExact(mCombatStats, 3*2*sizeof(int)); - mScript = esm.getHNOString("SCRI"); - - // script variables? - if (!mScript.empty()) - { - if (esm.isNextSub("SLCS")) - esm.skipHSub(); - if (esm.isNextSub("SLSD")) // Short Data? - esm.skipHSub(); - if (esm.isNextSub("SLFD")) // Float Data? - esm.skipHSub(); - } + mSCRI.load(esm); if (esm.isNextSub("ND3D")) esm.skipHSub(); diff --git a/apps/essimporter/importacdt.hpp b/apps/essimporter/importacdt.hpp index 271f6df74..3e3003f58 100644 --- a/apps/essimporter/importacdt.hpp +++ b/apps/essimporter/importacdt.hpp @@ -5,6 +5,8 @@ #include +#include "importscri.hpp" + namespace ESM { struct ESMReader; @@ -50,7 +52,7 @@ namespace ESSImport // to change them ingame int mCombatStats[3][2]; - std::string mScript; + SCRI mSCRI; void load(ESM::ESMReader& esm); }; diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 8603200da..a29d26e2a 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -234,6 +234,7 @@ namespace ESSImport converters[ESM::REC_DIAL] = boost::shared_ptr(new ConvertDIAL()); converters[ESM::REC_QUES] = boost::shared_ptr(new ConvertQUES()); converters[recJOUR ] = boost::shared_ptr(new ConvertJOUR()); + converters[ESM::REC_SCPT] = boost::shared_ptr(new ConvertSCPT()); std::set unknownRecords; diff --git a/apps/essimporter/importinventory.cpp b/apps/essimporter/importinventory.cpp index a20584ff5..d27cd5c8c 100644 --- a/apps/essimporter/importinventory.cpp +++ b/apps/essimporter/importinventory.cpp @@ -29,18 +29,7 @@ namespace ESSImport if (esm.isNextSub("XIDX")) // index in the stack? esm.skipHSub(); - std::string script = esm.getHNOString("SCRI"); - // script variables? - // unsure if before or after ESM::CellRef - if (!script.empty()) - { - if (esm.isNextSub("SLCS")) - esm.skipHSub(); - if (esm.isNextSub("SLSD")) // Short Data? - esm.skipHSub(); - if (esm.isNextSub("SLFD")) // Float Data? - esm.skipHSub(); - } + item.mSCRI.load(esm); // for XSOL and XCHG seen so far, but probably others too item.ESM::CellRef::loadData(esm); diff --git a/apps/essimporter/importinventory.hpp b/apps/essimporter/importinventory.hpp index 99fed9b20..0b5405d96 100644 --- a/apps/essimporter/importinventory.hpp +++ b/apps/essimporter/importinventory.hpp @@ -5,6 +5,7 @@ #include #include +#include "importscri.hpp" namespace ESM { @@ -21,6 +22,7 @@ namespace ESSImport std::string mId; int mCount; int mRelativeEquipmentSlot; + SCRI mSCRI; }; std::vector mItems; diff --git a/apps/essimporter/importscpt.cpp b/apps/essimporter/importscpt.cpp new file mode 100644 index 000000000..374fd05fa --- /dev/null +++ b/apps/essimporter/importscpt.cpp @@ -0,0 +1,20 @@ +#include "importscpt.hpp" + +#include + + + +namespace ESSImport +{ + + void SCPT::load(ESM::ESMReader &esm) + { + esm.getHNT(mSCHD, "SCHD"); + + mSCRI.load(esm); + + mRNAM = -1; + esm.getHNOT(mRNAM, "RNAM"); + } + +} diff --git a/apps/essimporter/importscpt.hpp b/apps/essimporter/importscpt.hpp new file mode 100644 index 000000000..ca2439dda --- /dev/null +++ b/apps/essimporter/importscpt.hpp @@ -0,0 +1,32 @@ +#ifndef OPENMW_ESSIMPORT_IMPORTSCPT_H +#define OPENMW_ESSIMPORT_IMPORTSCPT_H + +#include "importscri.hpp" + +#include + +namespace ESM +{ + class ESMReader; +} + +namespace ESSImport +{ + + // A running global script + // TODO: test how targeted scripts are saved + struct SCPT + { + ESM::Script::SCHD mSCHD; + + // values of local variables + SCRI mSCRI; + + int mRNAM; // unknown, seems to be -1 for some scripts, some huge integer for others + + void load(ESM::ESMReader& esm); + }; + +} + +#endif diff --git a/apps/essimporter/importscri.cpp b/apps/essimporter/importscri.cpp new file mode 100644 index 000000000..de0b35c86 --- /dev/null +++ b/apps/essimporter/importscri.cpp @@ -0,0 +1,55 @@ +#include "importscri.hpp" + +#include + +namespace ESSImport +{ + + void SCRI::load(ESM::ESMReader &esm) + { + mScript = esm.getHNOString("SCRI"); + + int numShorts = 0, numLongs = 0, numFloats = 0; + if (esm.isNextSub("SLCS")) + { + esm.getSubHeader(); + esm.getT(numShorts); + esm.getT(numLongs); + esm.getT(numFloats); + } + + if (esm.isNextSub("SLSD")) + { + esm.getSubHeader(); + for (int i=0; i + +#include + +namespace ESM +{ + class ESMReader; +} + +namespace ESSImport +{ + + /// Local variable assigments for a running script + struct SCRI + { + std::string mScript; + + std::vector mShorts; + std::vector mLongs; + std::vector mFloats; + + void load(ESM::ESMReader& esm); + }; + +} + +#endif diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index f2f13d086..2df8e66ce 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -7,12 +7,6 @@ namespace ESM { -struct SCHD -{ - NAME32 mName; - Script::SCHDstruct mData; -}; - unsigned int Script::sRecordId = REC_SCPT; void Script::load(ESMReader &esm) @@ -92,32 +86,6 @@ void Script::load(ESMReader &esm) if (esm.isNextSub("SCVR")) { esm.skipHSub(); } - - // ESS only, TODO: move - if (esm.isNextSub("SLCS")) - { - esm.getSubHeader(); - char unknown[12]; - esm.getExact(unknown, 12); - } - if (esm.isNextSub("SLSD")) - { - float read; - esm.getSubHeader(); - // values of variables? - for (int i=0; i Date: Thu, 22 Jan 2015 04:12:08 +0100 Subject: [PATCH 274/740] Fix Tribunal/BM summon effects not working --- apps/essimporter/importcellref.cpp | 2 +- apps/openmw/mwmechanics/spellcasting.cpp | 13 ++++++++++--- apps/openmw/mwmechanics/spellcasting.hpp | 2 ++ apps/openmw/mwmechanics/summoning.cpp | 5 +++-- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/apps/essimporter/importcellref.cpp b/apps/essimporter/importcellref.cpp index 845c574e4..1894b0023 100644 --- a/apps/essimporter/importcellref.cpp +++ b/apps/essimporter/importcellref.cpp @@ -23,7 +23,7 @@ namespace ESSImport if (esm.isNextSub("LVCR")) { // occurs on leveled creature spawner references - // probably some identifier for the the creature that has been spawned? + // probably some identifier for the creature that has been spawned? unsigned char lvcr; esm.getHT(lvcr); //std::cout << "LVCR: " << (int)lvcr << std::endl; diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index ff27ac5f6..49887e560 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -472,9 +472,7 @@ namespace MWMechanics applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude); // Re-casting a summon effect will remove the creature from previous castings of that effect. - if (effectIt->mEffectID >= ESM::MagicEffect::SummonScamp - && effectIt->mEffectID <= ESM::MagicEffect::SummonStormAtronach - && !target.isEmpty() && target.getClass().isActor()) + if (isSummoningEffect(effectIt->mEffectID) && !target.isEmpty() && target.getClass().isActor()) { CreatureStats& targetStats = target.getClass().getCreatureStats(target); std::map::iterator found = targetStats.getSummonedCreatureMap().find(std::make_pair(effectIt->mEffectID, mId)); @@ -956,4 +954,13 @@ namespace MWMechanics return static_cast((result < 1) ? 1 : result); } + + bool isSummoningEffect(int effectId) + { + return ((effectId >= ESM::MagicEffect::SummonScamp + && effectId <= ESM::MagicEffect::SummonStormAtronach) + || effectId == ESM::MagicEffect::SummonCenturionSphere + || (effectId >= ESM::MagicEffect::SummonFabricant + && effectId <= ESM::MagicEffect::SummonCreature05)); + } } diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 00fae847f..2d550e085 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -22,6 +22,8 @@ namespace MWMechanics ESM::Skill::SkillEnum spellSchoolToSkill(int school); + bool isSummoningEffect(int effectId); + /** * @param spell spell to cast * @param actor calculate spell success chance for this actor (depends on actor's skills) diff --git a/apps/openmw/mwmechanics/summoning.cpp b/apps/openmw/mwmechanics/summoning.cpp index 356cb422f..ec9bd0ea0 100644 --- a/apps/openmw/mwmechanics/summoning.cpp +++ b/apps/openmw/mwmechanics/summoning.cpp @@ -5,6 +5,8 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwmechanics/spellcasting.hpp" + #include "../mwworld/esmstore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/manualref.hpp" @@ -51,8 +53,7 @@ namespace MWMechanics void UpdateSummonedCreatures::visit(EffectKey key, const std::string &sourceName, const std::string &sourceId, int casterActorId, float magnitude, float remainingTime, float totalTime) { - if (key.mId >= ESM::MagicEffect::SummonScamp - && key.mId <= ESM::MagicEffect::SummonStormAtronach && magnitude > 0) + if (isSummoningEffect(key.mId) && magnitude > 0) { mActiveEffects.insert(std::make_pair(key.mId, sourceId)); } From af0e91c2d348b93d65a8db36582db27dac6de971 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 15:21:03 +0100 Subject: [PATCH 275/740] ESSImport: stolen items reading fix --- apps/essimporter/converter.hpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 9894de299..7565b78d4 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -364,15 +364,18 @@ public: { std::string itemid = esm.getHNString("NAME"); - while (esm.isNextSub("ONAM")) + while (esm.isNextSub("FNAM") || esm.isNextSub("ONAM")) { - std::string ownerid = esm.getHString(); - mStolenItems.insert(std::make_pair(itemid, ownerid)); - } - while (esm.isNextSub("FNAM")) - { - std::string factionid = esm.getHString(); - mFactionStolenItems.insert(std::make_pair(itemid, factionid)); + if (esm.retSubName().toString() == "FNAM") + { + std::string factionid = esm.getHString(); + mFactionStolenItems.insert(std::make_pair(itemid, factionid)); + } + else + { + std::string ownerid = esm.getHString(); + mStolenItems.insert(std::make_pair(itemid, ownerid)); + } } } private: From 8b5effe3e06eb628ac3c12f6fec39052ef26a79b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 17:47:00 +0100 Subject: [PATCH 276/740] Fix wrong magic number for JOUR in openmw savegames --- apps/openmw/mwdialogue/journalimp.cpp | 2 +- apps/openmw/mwstate/statemanagerimp.cpp | 1 + components/esm/defs.hpp | 22 ++++++++++++---------- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwdialogue/journalimp.cpp b/apps/openmw/mwdialogue/journalimp.cpp index 1d17134df..597a908e8 100644 --- a/apps/openmw/mwdialogue/journalimp.cpp +++ b/apps/openmw/mwdialogue/journalimp.cpp @@ -229,7 +229,7 @@ namespace MWDialogue void Journal::readRecord (ESM::ESMReader& reader, int32_t type) { - if (type==ESM::REC_JOUR) + if (type==ESM::REC_JOUR || type==ESM::REC_JOUR_LEGACY) { ESM::JournalEntry record; record.load (reader); diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 87b303b6f..a282f152a 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -368,6 +368,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::str break; case ESM::REC_JOUR: + case ESM::REC_JOUR_LEGACY: case ESM::REC_QUES: MWBase::Environment::get().getJournal()->readRecord (reader, n.val); diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index effe9a3f1..60926d562 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -96,15 +96,17 @@ enum RecNameInts REC_WEAP = 0x50414557, // format 0 - saved games - REC_SAVE = 0x45564153, - REC_JOUR = 0x524f55a4, // TODO: this is actually "\nOUR" rather than "JOUR", fix - REC_QUES = 0x53455551, - REC_GSCR = 0x52435347, - REC_PLAY = 0x59414c50, - REC_CSTA = 0x41545343, - REC_GMAP = 0x50414d47, - REC_DIAS = 0x53414944, - REC_WTHR = 0x52485457, + REC_SAVE = FourCC<'S','A','V','E'>::value, + REC_JOUR_LEGACY = FourCC<0xa4,'U','O','R'>::value, // "\xa4UOR", rather than "JOUR", little oversight when magic numbers were + // calculated by hand, needs to be supported for older files now + REC_JOUR = FourCC<'J','O','U','R'>::value, + REC_QUES = FourCC<'Q','U','E','S'>::value, + REC_GSCR = FourCC<'G','S','C','R'>::value, + REC_PLAY = FourCC<'P','L','A','Y'>::value, + REC_CSTA = FourCC<'C','S','T','A'>::value, + REC_GMAP = FourCC<'G','M','A','P'>::value, + REC_DIAS = FourCC<'D','I','A','S'>::value, + REC_WTHR = FourCC<'W','T','H','R'>::value, REC_KEYS = FourCC<'K','E','Y','S'>::value, REC_DYNA = FourCC<'D','Y','N','A'>::value, REC_ASPL = FourCC<'A','S','P','L'>::value, @@ -117,7 +119,7 @@ enum RecNameInts REC_CAM_ = FourCC<'C','A','M','_'>::value, // format 1 - REC_FILT = 0x544C4946, + REC_FILT = FourCC<'F','I','L','T'>::value, REC_DBGP = FourCC<'D','B','G','P'>::value ///< only used in project files }; From c883a73d30adc988738c6c577f5c4ae67d8da8a0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 19:04:59 +0100 Subject: [PATCH 277/740] Several warning fixes --- apps/bsatool/bsatool.cpp | 8 +++---- apps/esmtool/esmtool.cpp | 24 +++++++++---------- apps/esmtool/labels.cpp | 21 ++++++++-------- apps/esmtool/record.cpp | 22 +++++++++-------- apps/esmtool/record.hpp | 10 +++----- apps/essimporter/main.cpp | 2 +- apps/openmw/mwbase/dialoguemanager.hpp | 2 +- apps/openmw/mwbase/journal.hpp | 2 +- apps/openmw/mwbase/mechanicsmanager.hpp | 2 +- apps/openmw/mwbase/windowmanager.hpp | 2 +- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 2 +- apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 2 +- apps/openmw/mwdialogue/journalimp.cpp | 2 +- apps/openmw/mwdialogue/journalimp.hpp | 2 +- apps/openmw/mwgui/mapwindow.cpp | 2 +- apps/openmw/mwgui/mapwindow.hpp | 2 +- apps/openmw/mwgui/quickkeysmenu.cpp | 2 +- apps/openmw/mwgui/quickkeysmenu.hpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.hpp | 2 +- apps/openmw/mwmechanics/actors.cpp | 2 +- apps/openmw/mwmechanics/actors.hpp | 2 +- .../mwmechanics/mechanicsmanagerimp.cpp | 2 +- .../mwmechanics/mechanicsmanagerimp.hpp | 2 +- apps/openmw/mwscript/globalscripts.cpp | 2 +- apps/openmw/mwscript/globalscripts.hpp | 2 +- apps/openmw/mwworld/cells.cpp | 2 +- apps/openmw/mwworld/cells.hpp | 2 +- apps/openmw/mwworld/esmstore.cpp | 2 +- apps/openmw/mwworld/esmstore.hpp | 2 +- apps/openmw/mwworld/globals.cpp | 2 +- apps/openmw/mwworld/globals.hpp | 2 +- apps/openmw/mwworld/player.cpp | 2 +- apps/openmw/mwworld/player.hpp | 2 +- apps/openmw/mwworld/projectilemanager.cpp | 2 +- apps/openmw/mwworld/projectilemanager.hpp | 2 +- apps/openmw/mwworld/weather.cpp | 2 +- apps/openmw/mwworld/weather.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 2 +- apps/openmw/mwworld/worldimp.hpp | 2 +- components/esm/esmcommon.hpp | 2 +- 42 files changed, 78 insertions(+), 81 deletions(-) diff --git a/apps/bsatool/bsatool.cpp b/apps/bsatool/bsatool.cpp index 5b1f7d6bb..c0a6dcc81 100644 --- a/apps/bsatool/bsatool.cpp +++ b/apps/bsatool/bsatool.cpp @@ -27,8 +27,8 @@ struct Arguments void replaceAll(std::string& str, const std::string& needle, const std::string& substitute) { - int pos = str.find(needle); - while(pos != -1) + size_t pos = str.find(needle); + while(pos != std::string::npos) { str.replace(pos, needle.size(), substitute); pos = str.find(needle); @@ -138,8 +138,8 @@ bool parseOptions (int argc, char** argv, Arguments &info) else if (variables["input-file"].as< std::vector >().size() > 1) info.outdir = variables["input-file"].as< std::vector >()[1]; - info.longformat = variables.count("long"); - info.fullpath = variables.count("full-path"); + info.longformat = variables.count("long") != 0; + info.fullpath = variables.count("full-path") != 0; return true; } diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index b23ba72f9..9bbf20266 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -22,7 +22,7 @@ struct ESMData { std::string author; std::string description; - int version; + unsigned int version; std::vector masters; std::deque mRecords; @@ -48,9 +48,9 @@ const std::set ESMData::sLabeledRec = // Based on the legacy struct struct Arguments { - unsigned int raw_given; - unsigned int quiet_given; - unsigned int loadcells_given; + bool raw_given; + bool quiet_given; + bool loadcells_given; bool plain_given; std::string mode; @@ -177,10 +177,10 @@ bool parseOptions (int argc, char** argv, Arguments &info) if (variables["input-file"].as< std::vector >().size() > 1) info.outname = variables["input-file"].as< std::vector >()[1]; - info.raw_given = variables.count ("raw"); - info.quiet_given = variables.count ("quiet"); - info.loadcells_given = variables.count ("loadcells"); - info.plain_given = (variables.count("plain") > 0); + info.raw_given = variables.count ("raw") != 0; + info.quiet_given = variables.count ("quiet") != 0; + info.loadcells_given = variables.count ("loadcells") != 0; + info.plain_given = variables.count("plain") != 0; // Font encoding settings info.encoding = variables["encoding"].as(); @@ -430,7 +430,7 @@ int clone(Arguments& info) return 1; } - int recordCount = info.data.mRecords.size(); + size_t recordCount = info.data.mRecords.size(); int digitCount = 1; // For a nicer output if (recordCount > 9) ++digitCount; @@ -501,9 +501,9 @@ int clone(Arguments& info) if (!info.data.mCellRefs[ptr].empty()) { typedef std::deque RefList; RefList &refs = info.data.mCellRefs[ptr]; - for (RefList::iterator it = refs.begin(); it != refs.end(); ++it) + for (RefList::iterator refIt = refs.begin(); refIt != refs.end(); ++refIt) { - it->save(esm); + refIt->save(esm); } } } @@ -511,7 +511,7 @@ int clone(Arguments& info) esm.endRecord(name.toString()); saved++; - int perc = (saved / (float)recordCount)*100; + int perc = (int)((saved / (float)recordCount)*100); if (perc % 10 == 0) { std::cerr << "\r" << perc << "%"; diff --git a/apps/esmtool/labels.cpp b/apps/esmtool/labels.cpp index 9543628f5..88e188df0 100644 --- a/apps/esmtool/labels.cpp +++ b/apps/esmtool/labels.cpp @@ -13,14 +13,13 @@ #include #include -#include #include std::string bodyPartLabel(int idx) { if (idx >= 0 && idx <= 26) { - const char *bodyPartLabels[] = { + static const char *bodyPartLabels[] = { "Head", "Hair", "Neck", @@ -59,7 +58,7 @@ std::string meshPartLabel(int idx) { if (idx >= 0 && idx <= ESM::BodyPart::MP_Tail) { - const char *meshPartLabels[] = { + static const char *meshPartLabels[] = { "Head", "Hair", "Neck", @@ -86,7 +85,7 @@ std::string meshTypeLabel(int idx) { if (idx >= 0 && idx <= ESM::BodyPart::MT_Armor) { - const char *meshTypeLabels[] = { + static const char *meshTypeLabels[] = { "Skin", "Clothing", "Armor" @@ -101,7 +100,7 @@ std::string clothingTypeLabel(int idx) { if (idx >= 0 && idx <= 9) { - const char *clothingTypeLabels[] = { + static const char *clothingTypeLabels[] = { "Pants", "Shoes", "Shirt", @@ -123,7 +122,7 @@ std::string armorTypeLabel(int idx) { if (idx >= 0 && idx <= 10) { - const char *armorTypeLabels[] = { + static const char *armorTypeLabels[] = { "Helmet", "Cuirass", "Left Pauldron", @@ -146,7 +145,7 @@ std::string dialogTypeLabel(int idx) { if (idx >= 0 && idx <= 4) { - const char *dialogTypeLabels[] = { + static const char *dialogTypeLabels[] = { "Topic", "Voice", "Greeting", @@ -165,7 +164,7 @@ std::string questStatusLabel(int idx) { if (idx >= 0 && idx <= 4) { - const char *questStatusLabels[] = { + static const char *questStatusLabels[] = { "None", "Name", "Finished", @@ -182,7 +181,7 @@ std::string creatureTypeLabel(int idx) { if (idx >= 0 && idx <= 3) { - const char *creatureTypeLabels[] = { + static const char *creatureTypeLabels[] = { "Creature", "Daedra", "Undead", @@ -198,7 +197,7 @@ std::string soundTypeLabel(int idx) { if (idx >= 0 && idx <= 7) { - const char *soundTypeLabels[] = { + static const char *soundTypeLabels[] = { "Left Foot", "Right Foot", "Swim Left", @@ -218,7 +217,7 @@ std::string weaponTypeLabel(int idx) { if (idx >= 0 && idx <= 13) { - const char *weaponTypeLabels[] = { + static const char *weaponTypeLabels[] = { "Short Blade One Hand", "Long Blade One Hand", "Long Blade Two Hand", diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 3f2ebc2ba..2f07a5f08 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -25,7 +25,7 @@ void printAIPackage(ESM::AIPackage p) { std::cout << " Travel Coordinates: (" << p.mTravel.mX << "," << p.mTravel.mY << "," << p.mTravel.mZ << ")" << std::endl; - std::cout << " Travel Unknown: " << (int)p.mTravel.mUnk << std::endl; + std::cout << " Travel Unknown: " << p.mTravel.mUnk << std::endl; } else if (p.mType == ESM::AI_Follow || p.mType == ESM::AI_Escort) { @@ -33,12 +33,12 @@ void printAIPackage(ESM::AIPackage p) << p.mTarget.mY << "," << p.mTarget.mZ << ")" << std::endl; std::cout << " Duration: " << p.mTarget.mDuration << std::endl; std::cout << " Target ID: " << p.mTarget.mId.toString() << std::endl; - std::cout << " Unknown: " << (int)p.mTarget.mUnk << std::endl; + std::cout << " Unknown: " << p.mTarget.mUnk << std::endl; } else if (p.mType == ESM::AI_Activate) { std::cout << " Name: " << p.mActivate.mName.toString() << std::endl; - std::cout << " Activate Unknown: " << (int)p.mActivate.mUnk << std::endl; + std::cout << " Activate Unknown: " << p.mActivate.mUnk << std::endl; } else { std::cout << " BadPackage: " << boost::format("0x%08x") % p.mType << std::endl; @@ -89,6 +89,7 @@ std::string ruleString(ESM::DialInfo::SelectStruct ss) case 'A': if (indicator == 'R') type_str = "Not Race"; break; case 'B': if (indicator == 'L') type_str = "Not Cell"; break; case 'C': if (indicator == 's') type_str = "Not Local"; break; + default: break; } // Append the variable name to the function string if any. @@ -110,6 +111,7 @@ std::string ruleString(ESM::DialInfo::SelectStruct ss) case '3': oper_str = ">="; break; case '4': oper_str = "< "; break; case '5': oper_str = "<="; break; + default: break; } std::ostringstream stream; @@ -430,7 +432,7 @@ void Record::print() std::cout << " Icon: " << mData.mIcon << std::endl; std::cout << " Script: " << mData.mScript << std::endl; std::cout << " Type: " << apparatusTypeLabel(mData.mData.mType) - << " (" << (int)mData.mData.mType << ")" << std::endl; + << " (" << mData.mData.mType << ")" << std::endl; std::cout << " Weight: " << mData.mData.mWeight << std::endl; std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Quality: " << mData.mData.mQuality << std::endl; @@ -816,7 +818,7 @@ void Record::print() // Seems like this should done with reference counting in the // loader to me. But I'm not really knowledgable about this // record type yet. --Cory - bool wasLoaded = mData.mDataLoaded; + bool wasLoaded = (mData.mDataLoaded != 0); if (mData.mDataTypes) mData.loadData(mData.mDataTypes); if (mData.mDataLoaded) { @@ -999,7 +1001,7 @@ void Record::print() << (unsigned int)((unsigned char)mData.mNpdt12.mUnknown2) << std::endl; std::cout << " Unknown3: " << (unsigned int)((unsigned char)mData.mNpdt12.mUnknown3) << std::endl; - std::cout << " Gold: " << (int)mData.mNpdt12.mGold << std::endl; + std::cout << " Gold: " << mData.mNpdt12.mGold << std::endl; } else { std::cout << " Level: " << mData.mNpdt52.mLevel << std::endl; @@ -1021,7 +1023,7 @@ void Record::print() std::cout << " Skills:" << std::endl; for (int i = 0; i != ESM::Skill::Length; i++) std::cout << " " << skillLabel(i) << ": " - << (int)((unsigned char)mData.mNpdt52.mSkills[i]) << std::endl; + << (int)(mData.mNpdt52.mSkills[i]) << std::endl; std::cout << " Health: " << mData.mNpdt52.mHealth << std::endl; std::cout << " Magicka: " << mData.mNpdt52.mMana << std::endl; @@ -1123,9 +1125,9 @@ void Record::print() std::cout << (male ? " Male:" : " Female:") << std::endl; - for (int i=0; i<8; ++i) - std::cout << " " << sAttributeNames[i] << ": " - << mData.mData.mAttributeValues[i].getValue (male) << std::endl; + for (int j=0; j<8; ++j) + std::cout << " " << sAttributeNames[j] << ": " + << mData.mData.mAttributeValues[j].getValue (male) << std::endl; std::cout << " Height: " << mData.mData.mHeight.getValue (male) << std::endl; std::cout << " Weight: " << mData.mData.mWeight.getValue (male) << std::endl; diff --git a/apps/esmtool/record.hpp b/apps/esmtool/record.hpp index 45b6d0426..c1b90ac2b 100644 --- a/apps/esmtool/record.hpp +++ b/apps/esmtool/record.hpp @@ -19,7 +19,7 @@ namespace EsmTool { protected: std::string mId; - int mFlags; + uint32_t mFlags; ESM::NAME mType; bool mPrintPlain; @@ -40,11 +40,11 @@ namespace EsmTool mId = id; } - int getFlags() const { + uint32_t getFlags() const { return mFlags; } - void setFlags(int flags) { + void setFlags(uint32_t flags) { mFlags = flags; } @@ -52,10 +52,6 @@ namespace EsmTool return mType; } - bool getPrintPlain() const { - return mPrintPlain; - } - void setPrintPlain(bool plain) { mPrintPlain = plain; } diff --git a/apps/essimporter/main.cpp b/apps/essimporter/main.cpp index 1c7d51116..5a9e0c77d 100644 --- a/apps/essimporter/main.cpp +++ b/apps/essimporter/main.cpp @@ -12,7 +12,7 @@ namespace bfs = boost::filesystem; -int main(int argc, const char** argv) +int main(int argc, char** argv) { try { diff --git a/apps/openmw/mwbase/dialoguemanager.hpp b/apps/openmw/mwbase/dialoguemanager.hpp index d35b5950f..1fe63e633 100644 --- a/apps/openmw/mwbase/dialoguemanager.hpp +++ b/apps/openmw/mwbase/dialoguemanager.hpp @@ -69,7 +69,7 @@ namespace MWBase virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const = 0; - virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0; + virtual void readRecord (ESM::ESMReader& reader, uint32_t type) = 0; /// Changes faction1's opinion of faction2 by \a diff. virtual void modFactionReaction (const std::string& faction1, const std::string& faction2, int diff) = 0; diff --git a/apps/openmw/mwbase/journal.hpp b/apps/openmw/mwbase/journal.hpp index 938cec74b..738014ba6 100644 --- a/apps/openmw/mwbase/journal.hpp +++ b/apps/openmw/mwbase/journal.hpp @@ -92,7 +92,7 @@ namespace MWBase virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const = 0; - virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0; + virtual void readRecord (ESM::ESMReader& reader, uint32_t type) = 0; }; } diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index a51e3a301..33a2ef1ea 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -193,7 +193,7 @@ namespace MWBase virtual void write (ESM::ESMWriter& writer, Loading::Listener& listener) const = 0; - virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0; + virtual void readRecord (ESM::ESMReader& reader, uint32_t type) = 0; virtual void clear() = 0; diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 3e957ef14..02cbc69e9 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -310,7 +310,7 @@ namespace MWBase virtual void clear() = 0; virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) = 0; - virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0; + virtual void readRecord (ESM::ESMReader& reader, uint32_t type) = 0; virtual int countSavedGameRecords() const = 0; /// Does the current stack of GUI-windows permit saving? diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index db0f0a763..f58ef0809 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -108,7 +108,7 @@ namespace MWBase virtual void write (ESM::ESMWriter& writer, Loading::Listener& listener) const = 0; - virtual void readRecord (ESM::ESMReader& reader, int32_t type, + virtual void readRecord (ESM::ESMReader& reader, uint32_t type, const std::map& contentFileMap) = 0; virtual MWWorld::CellStore *getExterior (int x, int y) = 0; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 0ee7dfe94..d2534cd82 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -647,7 +647,7 @@ namespace MWDialogue writer.endRecord (ESM::REC_DIAS); } - void DialogueManager::readRecord (ESM::ESMReader& reader, int32_t type) + void DialogueManager::readRecord (ESM::ESMReader& reader, uint32_t type) { if (type==ESM::REC_DIAS) { diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index c06299736..77035bc60 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -92,7 +92,7 @@ namespace MWDialogue virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; - virtual void readRecord (ESM::ESMReader& reader, int32_t type); + virtual void readRecord (ESM::ESMReader& reader, uint32_t type); /// Changes faction1's opinion of faction2 by \a diff. virtual void modFactionReaction (const std::string& faction1, const std::string& faction2, int diff); diff --git a/apps/openmw/mwdialogue/journalimp.cpp b/apps/openmw/mwdialogue/journalimp.cpp index 597a908e8..3b57912da 100644 --- a/apps/openmw/mwdialogue/journalimp.cpp +++ b/apps/openmw/mwdialogue/journalimp.cpp @@ -227,7 +227,7 @@ namespace MWDialogue } } - void Journal::readRecord (ESM::ESMReader& reader, int32_t type) + void Journal::readRecord (ESM::ESMReader& reader, uint32_t type) { if (type==ESM::REC_JOUR || type==ESM::REC_JOUR_LEGACY) { diff --git a/apps/openmw/mwdialogue/journalimp.hpp b/apps/openmw/mwdialogue/journalimp.hpp index d15b909fa..7f26a5bb9 100644 --- a/apps/openmw/mwdialogue/journalimp.hpp +++ b/apps/openmw/mwdialogue/journalimp.hpp @@ -71,7 +71,7 @@ namespace MWDialogue virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; - virtual void readRecord (ESM::ESMReader& reader, int32_t type); + virtual void readRecord (ESM::ESMReader& reader, uint32_t type); }; } diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index abd1256d7..00d60f23b 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -886,7 +886,7 @@ namespace MWGui writer.endRecord(ESM::REC_GMAP); } - void MapWindow::readRecord(ESM::ESMReader &reader, int32_t type) + void MapWindow::readRecord(ESM::ESMReader &reader, uint32_t type) { if (type == ESM::REC_GMAP) { diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 684069467..7b6c1f205 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -177,7 +177,7 @@ namespace MWGui void clear(); void write (ESM::ESMWriter& writer, Loading::Listener& progress); - void readRecord (ESM::ESMReader& reader, int32_t type); + void readRecord (ESM::ESMReader& reader, uint32_t type); private: void onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index deba64434..a102de1e5 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -431,7 +431,7 @@ namespace MWGui writer.endRecord(ESM::REC_KEYS); } - void QuickKeysMenu::readRecord(ESM::ESMReader &reader, int32_t type) + void QuickKeysMenu::readRecord(ESM::ESMReader &reader, uint32_t type) { if (type != ESM::REC_KEYS) return; diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index 30e672891..00afa4561 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -47,7 +47,7 @@ namespace MWGui void write (ESM::ESMWriter& writer); - void readRecord (ESM::ESMReader& reader, int32_t type); + void readRecord (ESM::ESMReader& reader, uint32_t type); void clear(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 5b2bbee90..e976b984f 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1620,7 +1620,7 @@ namespace MWGui } } - void WindowManager::readRecord(ESM::ESMReader &reader, int32_t type) + void WindowManager::readRecord(ESM::ESMReader &reader, uint32_t type) { if (type == ESM::REC_GMAP) mMap->readRecord(reader, type); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 44d5819c2..a08c59a2f 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -306,7 +306,7 @@ namespace MWGui virtual void clear(); virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress); - virtual void readRecord (ESM::ESMReader& reader, int32_t type); + virtual void readRecord (ESM::ESMReader& reader, uint32_t type); virtual int countSavedGameRecords() const; /// Does the current stack of GUI-windows permit saving? diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 64434a304..f8068e800 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1468,7 +1468,7 @@ namespace MWMechanics writer.endRecord(ESM::REC_DCOU); } - void Actors::readRecord (ESM::ESMReader& reader, int32_t type) + void Actors::readRecord (ESM::ESMReader& reader, uint32_t type) { if (type == ESM::REC_DCOU) { diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 39fe38208..39598b2a2 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -128,7 +128,7 @@ namespace MWMechanics void write (ESM::ESMWriter& writer, Loading::Listener& listener) const; - void readRecord (ESM::ESMReader& reader, int32_t type); + void readRecord (ESM::ESMReader& reader, uint32_t type); void clear(); // Clear death counter diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 3d757bde6..0a2c3cfff 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1360,7 +1360,7 @@ namespace MWMechanics mActors.write(writer, listener); } - void MechanicsManager::readRecord(ESM::ESMReader &reader, int32_t type) + void MechanicsManager::readRecord(ESM::ESMReader &reader, uint32_t type) { mActors.readRecord(reader, type); } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index fc9c58974..2f443ad59 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -158,7 +158,7 @@ namespace MWMechanics virtual void write (ESM::ESMWriter& writer, Loading::Listener& listener) const; - virtual void readRecord (ESM::ESMReader& reader, int32_t type); + virtual void readRecord (ESM::ESMReader& reader, uint32_t type); virtual void clear(); diff --git a/apps/openmw/mwscript/globalscripts.cpp b/apps/openmw/mwscript/globalscripts.cpp index c7371100f..6c4bb3be5 100644 --- a/apps/openmw/mwscript/globalscripts.cpp +++ b/apps/openmw/mwscript/globalscripts.cpp @@ -145,7 +145,7 @@ namespace MWScript } } - bool GlobalScripts::readRecord (ESM::ESMReader& reader, int32_t type) + bool GlobalScripts::readRecord (ESM::ESMReader& reader, uint32_t type) { if (type==ESM::REC_GSCR) { diff --git a/apps/openmw/mwscript/globalscripts.hpp b/apps/openmw/mwscript/globalscripts.hpp index 55c2e9321..9f009db98 100644 --- a/apps/openmw/mwscript/globalscripts.hpp +++ b/apps/openmw/mwscript/globalscripts.hpp @@ -62,7 +62,7 @@ namespace MWScript void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; - bool readRecord (ESM::ESMReader& reader, int32_t type); + bool readRecord (ESM::ESMReader& reader, uint32_t type); ///< Records for variables that do not exist are dropped silently. /// /// \return Known type? diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 3a8b7d5c4..fd5ec20dc 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -299,7 +299,7 @@ void MWWorld::Cells::write (ESM::ESMWriter& writer, Loading::Listener& progress) } } -bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, int32_t type, +bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, uint32_t type, const std::map& contentFileMap) { if (type==ESM::REC_CSTA) diff --git a/apps/openmw/mwworld/cells.hpp b/apps/openmw/mwworld/cells.hpp index a9c17fa93..0b7d9444f 100644 --- a/apps/openmw/mwworld/cells.hpp +++ b/apps/openmw/mwworld/cells.hpp @@ -76,7 +76,7 @@ namespace MWWorld void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; - bool readRecord (ESM::ESMReader& reader, int32_t type, + bool readRecord (ESM::ESMReader& reader, uint32_t type, const std::map& contentFileMap); }; } diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index b096f4b90..caa88d751 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -175,7 +175,7 @@ void ESMStore::setUp() mCreatureLists.write (writer, progress); } - bool ESMStore::readRecord (ESM::ESMReader& reader, int32_t type) + bool ESMStore::readRecord (ESM::ESMReader& reader, uint32_t type) { switch (type) { diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index 01770e6b3..05b633956 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -233,7 +233,7 @@ namespace MWWorld void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; - bool readRecord (ESM::ESMReader& reader, int32_t type); + bool readRecord (ESM::ESMReader& reader, uint32_t type); ///< \return Known type? }; diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index 302a05824..e7cb04590 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -88,7 +88,7 @@ namespace MWWorld } } - bool Globals::readRecord (ESM::ESMReader& reader, int32_t type) + bool Globals::readRecord (ESM::ESMReader& reader, uint32_t type) { if (type==ESM::REC_GLOB) { diff --git a/apps/openmw/mwworld/globals.hpp b/apps/openmw/mwworld/globals.hpp index 3ff4a5d6e..bb4ab13d9 100644 --- a/apps/openmw/mwworld/globals.hpp +++ b/apps/openmw/mwworld/globals.hpp @@ -53,7 +53,7 @@ namespace MWWorld void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; - bool readRecord (ESM::ESMReader& reader, int32_t type); + bool readRecord (ESM::ESMReader& reader, uint32_t type); ///< Records for variables that do not exist are dropped silently. /// /// \return Known type? diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index a57934bd3..c1e176b91 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -227,7 +227,7 @@ namespace MWWorld writer.endRecord (ESM::REC_PLAY); } - bool Player::readRecord (ESM::ESMReader& reader, int32_t type) + bool Player::readRecord (ESM::ESMReader& reader, uint32_t type) { if (type==ESM::REC_PLAY) { diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index d8cde5952..25d8981cd 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -102,7 +102,7 @@ namespace MWWorld void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; - bool readRecord (ESM::ESMReader& reader, int32_t type); + bool readRecord (ESM::ESMReader& reader, uint32_t type); int getNewCrimeId(); // get new id for witnesses void recordCrimeId(); // record the paid crime id when bounty is 0 diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index e4b2d5a1e..41fbfea9f 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -343,7 +343,7 @@ namespace MWWorld } } - bool ProjectileManager::readRecord(ESM::ESMReader &reader, int32_t type) + bool ProjectileManager::readRecord(ESM::ESMReader &reader, uint32_t type) { if (type == ESM::REC_PROJ) { diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index 6e84b9efb..93f54c008 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -53,7 +53,7 @@ namespace MWWorld void clear(); void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; - bool readRecord (ESM::ESMReader& reader, int32_t type); + bool readRecord (ESM::ESMReader& reader, uint32_t type); int countSavedGameRecords() const; private: diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index cd05cb798..6532c5969 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -762,7 +762,7 @@ void WeatherManager::write(ESM::ESMWriter& writer, Loading::Listener& progress) writer.endRecord(ESM::REC_WTHR); } -bool WeatherManager::readRecord(ESM::ESMReader& reader, int32_t type) +bool WeatherManager::readRecord(ESM::ESMReader& reader, uint32_t type) { if(ESM::REC_WTHR == type) { diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index dee9fc52a..830b5c376 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -199,7 +199,7 @@ namespace MWWorld void write(ESM::ESMWriter& writer, Loading::Listener& progress); - bool readRecord(ESM::ESMReader& reader, int32_t type); + bool readRecord(ESM::ESMReader& reader, uint32_t type); private: float mHour; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f7d5d9616..ceac85bca 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -345,7 +345,7 @@ namespace MWWorld writer.endRecord(ESM::REC_CAM_); } - void World::readRecord (ESM::ESMReader& reader, int32_t type, + void World::readRecord (ESM::ESMReader& reader, uint32_t type, const std::map& contentFileMap) { switch (type) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index f050c498d..9834015ac 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -170,7 +170,7 @@ namespace MWWorld virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; - virtual void readRecord (ESM::ESMReader& reader, int32_t type, + virtual void readRecord (ESM::ESMReader& reader, uint32_t type, const std::map& contentFileMap); virtual CellStore *getExterior (int x, int y); diff --git a/components/esm/esmcommon.hpp b/components/esm/esmcommon.hpp index d3e6e7fea..1bdadead2 100644 --- a/components/esm/esmcommon.hpp +++ b/components/esm/esmcommon.hpp @@ -23,7 +23,7 @@ template union NAME_T { char name[LEN]; - int32_t val; + uint32_t val; bool operator==(const char *str) const { From a619cff615f011beb2ed89fc2d1900671f3107d3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 21:39:07 +0100 Subject: [PATCH 278/740] Implement EnableLevelupMenu to trigger level-up --- apps/openmw/mwscript/docs/vmformat.txt | 3 ++- apps/openmw/mwscript/guiextensions.cpp | 2 ++ components/compiler/extensions0.cpp | 2 +- components/compiler/opcodes.hpp | 1 + 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index b139d6138..41cc6b88a 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -443,5 +443,6 @@ op 0x20002fc: RemoveFromLevCreature op 0x20002fd: AddToLevItem op 0x20002fe: RemoveFromLevItem op 0x20002ff: SetFactionReaction +op 0x2000300: EnableLevelupMenu -opcodes 0x2000300-0x3ffffff unused +opcodes 0x2000301-0x3ffffff unused diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index 1d34adbca..f5549a172 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -231,6 +231,8 @@ namespace MWScript new OpShowDialogue (MWGui::GM_Race)); interpreter.installSegment5 (Compiler::Gui::opcodeEnableStatsReviewMenu, new OpShowDialogue (MWGui::GM_Review)); + interpreter.installSegment5 (Compiler::Gui::opcodeEnableLevelupMenu, + new OpShowDialogue (MWGui::GM_Levelup)); interpreter.installSegment5 (Compiler::Gui::opcodeEnableInventoryMenu, new OpEnableWindow (MWGui::GW_Inventory)); diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index a5cc0da62..70338669e 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -215,7 +215,7 @@ namespace Compiler extensions.registerInstruction ("enablestatsmenu", "", opcodeEnableStatsMenu); extensions.registerInstruction ("enablerest", "", opcodeEnableRest); - extensions.registerInstruction ("enablelevelupmenu", "", opcodeEnableRest); + extensions.registerInstruction ("enablelevelupmenu", "", opcodeEnableLevelupMenu); extensions.registerInstruction ("showrestmenu", "", opcodeShowRestMenu, opcodeShowRestMenuExplicit); diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index 04666e976..e5cf2e965 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -185,6 +185,7 @@ namespace Compiler const int opcodeEnableMapMenu = 0x2000015; const int opcodeEnableStatsMenu = 0x2000016; const int opcodeEnableRest = 0x2000017; + const int opcodeEnableLevelupMenu = 0x2000300; const int opcodeShowRestMenu = 0x2000018; const int opcodeShowRestMenuExplicit = 0x2000234; const int opcodeGetButtonPressed = 0x2000137; From ba7cd04ff7ac7546ef71ebd999e97dd4ef36028f Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 23:28:31 +0100 Subject: [PATCH 279/740] ESSImport: prevent accidental overwriting of file --- apps/essimporter/main.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/essimporter/main.cpp b/apps/essimporter/main.cpp index 5a9e0c77d..d467e053e 100644 --- a/apps/essimporter/main.cpp +++ b/apps/essimporter/main.cpp @@ -50,7 +50,15 @@ int main(int argc, char** argv) if (vm.count("compare")) importer.compare(); else + { + const std::string& ext = ".omwsave"; + if (boost::filesystem::exists(boost::filesystem::path(outputFile)) + && (outputFile.size() < ext.size() || outputFile.substr(outputFile.size()-ext.size()) != ext)) + { + throw std::runtime_error("Output file already exists and does not end in .omwsave. Did you mean to use --compare?"); + } importer.run(); + } } catch (std::exception& e) { From 1d29180e003f00406b5dafef6364534ef84dac07 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 23:28:43 +0100 Subject: [PATCH 280/740] ESSImport: handle deleted cell references --- apps/essimporter/importcellref.cpp | 6 ++---- apps/essimporter/importer.cpp | 1 + 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/essimporter/importcellref.cpp b/apps/essimporter/importcellref.cpp index 1894b0023..906b2ed24 100644 --- a/apps/essimporter/importcellref.cpp +++ b/apps/essimporter/importcellref.cpp @@ -41,11 +41,9 @@ namespace ESSImport mDeleted = 0; if (esm.isNextSub("DELE")) { - int deleted; + unsigned int deleted; esm.getHT(deleted); - // Neither of this seems to work right... - //mDeleted = (deleted != 0); - //mDeleted = (deleted&0x1); + mDeleted = (deleted >> 24) & 0x2; // the other 3 bytes seem to be uninitialized garbage } if (esm.isNextSub("MVRF")) diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index a29d26e2a..9fd2903d8 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -105,6 +105,7 @@ namespace ESSImport blacklist.insert(std::make_pair("REFR", "DATA")); // player position blacklist.insert(std::make_pair("CELL", "NAM8")); // fog of war blacklist.insert(std::make_pair("GAME", "GMDT")); // weather data, current time always changes + blacklist.insert(std::make_pair("CELL", "DELE")); // first 3 bytes are uninitialized // this changes way too often, name suggests some renderer internal data? blacklist.insert(std::make_pair("CELL", "ND3D")); From c354f48a07080a08e713d4114ede4c13ca869996 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 23:42:43 +0100 Subject: [PATCH 281/740] ESSImport: some fixes --- apps/essimporter/importcrec.cpp | 9 ++------- apps/essimporter/importdial.cpp | 12 +++++++++++- apps/essimporter/importnpcc.cpp | 9 ++------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/apps/essimporter/importcrec.cpp b/apps/essimporter/importcrec.cpp index 28e5ac56f..7a8a3eb00 100644 --- a/apps/essimporter/importcrec.cpp +++ b/apps/essimporter/importcrec.cpp @@ -15,13 +15,8 @@ namespace ESSImport esm.getHNOT(scale, "XSCL"); // FIXME: use AiPackageList, need to fix getSubName() - if (esm.isNextSub("AI_W")) - esm.skipHSub(); - if (esm.isNextSub("AI_E")) - esm.skipHSub(); - if (esm.isNextSub("AI_T")) - esm.skipHSub(); - if (esm.isNextSub("AI_F")) + while (esm.isNextSub("AI_W") || esm.isNextSub("AI_E") || esm.isNextSub("AI_T") || esm.isNextSub("AI_F") + || esm.isNextSub("AI_A")) esm.skipHSub(); mInventory.load(esm); diff --git a/apps/essimporter/importdial.cpp b/apps/essimporter/importdial.cpp index 228d00a5a..5797a708a 100644 --- a/apps/essimporter/importdial.cpp +++ b/apps/essimporter/importdial.cpp @@ -7,7 +7,17 @@ namespace ESSImport void DIAL::load(ESM::ESMReader &esm) { - esm.getHNT(mIndex, "XIDX"); + // See ESM::Dialogue::Type enum, not sure why we would need this here though + int type = 0; + esm.getHNOT(type, "DATA"); + + // Deleted dialogue in a savefile. No clue what this means... + int deleted = 0; + esm.getHNOT(deleted, "DELE"); + + mIndex = 0; + // *should* always occur except when the dialogue is deleted, but leaving it optional just in case... + esm.getHNOT(mIndex, "XIDX"); } } diff --git a/apps/essimporter/importnpcc.cpp b/apps/essimporter/importnpcc.cpp index 7b8dda371..547b01441 100644 --- a/apps/essimporter/importnpcc.cpp +++ b/apps/essimporter/importnpcc.cpp @@ -10,13 +10,8 @@ namespace ESSImport esm.getHNT(mNPDT, "NPDT"); // FIXME: use AiPackageList, need to fix getSubName() - if (esm.isNextSub("AI_W")) - esm.skipHSub(); - if (esm.isNextSub("AI_E")) - esm.skipHSub(); - if (esm.isNextSub("AI_T")) - esm.skipHSub(); - if (esm.isNextSub("AI_F")) + while (esm.isNextSub("AI_W") || esm.isNextSub("AI_E") || esm.isNextSub("AI_T") || esm.isNextSub("AI_F") + || esm.isNextSub("AI_A")) esm.skipHSub(); mInventory.load(esm); From e484a91708683c5f6f0d26ea4c46ad73fce2bdd3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Jan 2015 00:15:57 +0100 Subject: [PATCH 282/740] ESSImport: convert global map markers --- apps/essimporter/converter.cpp | 10 ++++++++++ apps/essimporter/importer.cpp | 4 ++-- apps/essimporter/importercontext.hpp | 8 ++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 81521a028..75c2911fd 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -76,6 +76,12 @@ namespace ESSImport cell.mName = id; cell.load(esm, false); + // I wonder what 0x40 does? + if (cell.isExterior() && cell.mData.mFlags & 0x20) + { + mContext->mGlobalMapState.mMarkers.insert(std::make_pair(cell.mData.mX, cell.mData.mY)); + } + // note if the player is in a nameless exterior cell, we will assign the cellId later based on player position if (id == mContext->mPlayerCellName) { @@ -304,6 +310,10 @@ namespace ESSImport it->save(esm); esm.endRecord(ESM::REC_MARK); } + + esm.startRecord(ESM::REC_GMAP); + mContext->mGlobalMapState.save(esm); + esm.endRecord(ESM::REC_GMAP); } } diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 9fd2903d8..ed149b023 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -123,7 +123,7 @@ namespace ESSImport if (i >= file2.mRecords.size()) { - std::cout << "Record in file1 not present in file2: (1) 0x" << std::hex << rec.mFileOffset; + std::cout << "Record in file1 not present in file2: (1) 0x" << std::hex << rec.mFileOffset << std::endl; return; } @@ -142,7 +142,7 @@ namespace ESSImport if (j >= rec2.mSubrecords.size()) { - std::cout << "Subrecord in file1 not present in file2: (1) 0x" << std::hex << sub.mFileOffset; + std::cout << "Subrecord in file1 not present in file2: (1) 0x" << std::hex << sub.mFileOffset << std::endl; return; } diff --git a/apps/essimporter/importercontext.hpp b/apps/essimporter/importercontext.hpp index 02585799a..211195d3f 100644 --- a/apps/essimporter/importercontext.hpp +++ b/apps/essimporter/importercontext.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "importnpcc.hpp" #include "importcrec.hpp" @@ -28,6 +29,8 @@ namespace ESSImport ESM::DialogueState mDialogueState; + ESM::GlobalMap mGlobalMapState; + int mDay, mMonth, mYear; float mHour; @@ -48,6 +51,11 @@ namespace ESSImport mPlayer.mCurrentCrimeId = 0; // TODO mPlayer.mObject.blank(); mPlayer.mObject.mRef.mRefID = "player"; // REFR.mRefID would be PlayerSaveGame + + mGlobalMapState.mBounds.mMinX = 0; + mGlobalMapState.mBounds.mMaxX = 0; + mGlobalMapState.mBounds.mMinY = 0; + mGlobalMapState.mBounds.mMaxY = 0; } }; From 0c1d76279049155fa9f6d3f1a44fa28585091e2f Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Fri, 23 Jan 2015 15:37:32 +0100 Subject: [PATCH 283/740] Fix build when using new boost with Ogre. This fixes a [Parse error at "BOOST_JOIN"] if you're using - for instance - Boost 1.57.0 --- apps/launcher/graphicspage.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/launcher/graphicspage.hpp b/apps/launcher/graphicspage.hpp index da4cb9fb3..a96d9b732 100644 --- a/apps/launcher/graphicspage.hpp +++ b/apps/launcher/graphicspage.hpp @@ -3,8 +3,10 @@ #include +#ifndef Q_MOC_RUN #include #include +#endif #include From 7a903b7100d85838033177a5b15520f9afd146d2 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Fri, 23 Jan 2015 16:05:36 +0100 Subject: [PATCH 284/740] Doing forward declaration instead --- apps/launcher/graphicspage.hpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/apps/launcher/graphicspage.hpp b/apps/launcher/graphicspage.hpp index a96d9b732..213b6bccb 100644 --- a/apps/launcher/graphicspage.hpp +++ b/apps/launcher/graphicspage.hpp @@ -3,16 +3,11 @@ #include -#ifndef Q_MOC_RUN -#include -#include -#endif - #include - #include "ui_graphicspage.h" +namespace Ogre { class Root; class RenderSystem; } namespace Files { struct ConfigurationManager; } From 942cf26eeed3b92cb7ee5c7dccee35fc6fe4c8e0 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Fri, 23 Jan 2015 16:06:19 +0100 Subject: [PATCH 285/740] And the missing includes --- apps/launcher/graphicspage.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index da707b005..1f85bb5e7 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -12,6 +12,9 @@ #include +#include +#include + #include #include From 79d2eebe5435b9e1e92acbec2c191dc416b12a7b Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Jan 2015 16:45:47 +0100 Subject: [PATCH 286/740] Store selected enchant item in savegame (Fixes #1702) --- apps/essimporter/convertinventory.cpp | 9 ++- apps/openmw/mwworld/containerstore.cpp | 87 ++++++++++++++------------ apps/openmw/mwworld/containerstore.hpp | 9 +-- apps/openmw/mwworld/inventorystore.cpp | 48 +++++++++----- apps/openmw/mwworld/inventorystore.hpp | 7 +-- components/esm/inventorystate.cpp | 76 +++++++++++++--------- components/esm/inventorystate.hpp | 9 ++- 7 files changed, 145 insertions(+), 100 deletions(-) diff --git a/apps/essimporter/convertinventory.cpp b/apps/essimporter/convertinventory.cpp index 31272bf5a..f476fe1ee 100644 --- a/apps/essimporter/convertinventory.cpp +++ b/apps/essimporter/convertinventory.cpp @@ -7,6 +7,7 @@ namespace ESSImport void convertInventory(const Inventory &inventory, ESM::InventoryState &state) { + int index = 0; for (std::vector::const_iterator it = inventory.mItems.begin(); it != inventory.mItems.end(); ++it) { @@ -16,7 +17,13 @@ namespace ESSImport objstate.mRef.mRefID = Misc::StringUtils::lowerCase(it->mId); objstate.mCount = std::abs(it->mCount); // restocking items have negative count in the savefile // openmw handles them differently, so no need to set any flags - state.mItems.push_back(std::make_pair(objstate, it->mRelativeEquipmentSlot)); + state.mItems.push_back(objstate); + if (it->mRelativeEquipmentSlot != -1) + // Note we should really write the absolute slot here, which we do not know about + // Not a big deal, OpenMW will auto-correct to a valid slot, the only problem is when + // an item could be equipped in two different slots (e.g. equipped two rings) + state.mEquipmentSlots[index] = it->mRelativeEquipmentSlot; + ++index; } } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 57621b7a4..b21486c2c 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -79,6 +79,14 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::getState (CellRefList void MWWorld::ContainerStore::storeState (const LiveCellRef& ref, ESM::ObjectState& state) const { @@ -87,7 +95,7 @@ void MWWorld::ContainerStore::storeState (const LiveCellRef& ref, ESM::Object template void MWWorld::ContainerStore::storeStates (CellRefList& collection, - std::vector >& states, bool equipable) const + ESM::InventoryState& inventory, int& index, bool equipable) const { for (typename CellRefList::List::const_iterator iter (collection.mList.begin()); iter!=collection.mList.end(); ++iter) @@ -96,18 +104,13 @@ void MWWorld::ContainerStore::storeStates (CellRefList& collection, continue; ESM::ObjectState state; storeState (*iter, state); - int slot = equipable ? getSlot (*iter) : -1; - states.push_back (std::make_pair (state, slot)); + if (equipable) + storeEquipmentState(*iter, index, inventory); + inventory.mItems.push_back (state); + ++index; } } -int MWWorld::ContainerStore::getSlot (const MWWorld::LiveCellRefBase& ref) const -{ - return -1; -} - -void MWWorld::ContainerStore::setSlot (const MWWorld::ContainerStoreIterator& iter, int slot) {} - const std::string MWWorld::ContainerStore::sGoldId = "gold_001"; MWWorld::ContainerStore::ContainerStore() : mCachedWeight (0), mWeightUpToDate (false) {} @@ -645,49 +648,51 @@ void MWWorld::ContainerStore::writeState (ESM::InventoryState& state) { state.mItems.clear(); - storeStates (potions, state.mItems); - storeStates (appas, state.mItems); - storeStates (armors, state.mItems, true); - storeStates (books, state.mItems); - storeStates (clothes, state.mItems, true); - storeStates (ingreds, state.mItems); - storeStates (lockpicks, state.mItems, true); - storeStates (miscItems, state.mItems); - storeStates (probes, state.mItems, true); - storeStates (repairs, state.mItems); - storeStates (weapons, state.mItems, true); - storeStates (lights, state.mItems, true); + int index = 0; + storeStates (potions, state, index); + storeStates (appas, state, index); + storeStates (armors, state, index, true); + storeStates (books, state, index, true); // not equipable as such, but for selectedEnchantItem + storeStates (clothes, state, index, true); + storeStates (ingreds, state, index); + storeStates (lockpicks, state, index, true); + storeStates (miscItems, state, index); + storeStates (probes, state, index, true); + storeStates (repairs, state, index); + storeStates (weapons, state, index, true); + storeStates (lights, state, index, true); state.mLevelledItemMap = mLevelledItemMap; } -void MWWorld::ContainerStore::readState (const ESM::InventoryState& state) +void MWWorld::ContainerStore::readState (const ESM::InventoryState& inventory) { clear(); - for (std::vector >::const_iterator - iter (state.mItems.begin()); iter!=state.mItems.end(); ++iter) + int index = 0; + for (std::vector::const_iterator + iter (inventory.mItems.begin()); iter!=inventory.mItems.end(); ++iter) { - int slot = iter->second; - - const ESM::ObjectState& state = iter->first; + const ESM::ObjectState& state = *iter; int type = MWBase::Environment::get().getWorld()->getStore().find(state.mRef.mRefID); + int thisIndex = index++; + switch (type) { - case ESM::REC_ALCH: getState (potions, iter->first); break; - case ESM::REC_APPA: getState (appas, iter->first); break; - case ESM::REC_ARMO: setSlot (getState (armors, iter->first), slot); break; - case ESM::REC_BOOK: getState (books, iter->first); break; - case ESM::REC_CLOT: setSlot (getState (clothes, iter->first), slot); break; - case ESM::REC_INGR: getState (ingreds, iter->first); break; - case ESM::REC_LOCK: setSlot (getState (lockpicks, iter->first), slot); break; - case ESM::REC_MISC: getState (miscItems, iter->first); break; - case ESM::REC_PROB: setSlot (getState (probes, iter->first), slot); break; - case ESM::REC_REPA: getState (repairs, iter->first); break; - case ESM::REC_WEAP: setSlot (getState (weapons, iter->first), slot); break; - case ESM::REC_LIGH: setSlot (getState (lights, iter->first), slot); break; + case ESM::REC_ALCH: getState (potions, state); break; + case ESM::REC_APPA: getState (appas, state); break; + case ESM::REC_ARMO: readEquipmentState (getState (armors, state), thisIndex, inventory); break; + case ESM::REC_BOOK: readEquipmentState (getState (books, state), thisIndex, inventory); break; // not equipable as such, but for selectedEnchantItem + case ESM::REC_CLOT: readEquipmentState (getState (clothes, state), thisIndex, inventory); break; + case ESM::REC_INGR: getState (ingreds, state); break; + case ESM::REC_LOCK: readEquipmentState (getState (lockpicks, state), thisIndex, inventory); break; + case ESM::REC_MISC: getState (miscItems, state); break; + case ESM::REC_PROB: readEquipmentState (getState (probes, state), thisIndex, inventory); break; + case ESM::REC_REPA: getState (repairs, state); break; + 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 << "Dropping reference to '" << state.mRef.mRefID << "' (object no longer exists)" << std::endl; break; @@ -698,7 +703,7 @@ void MWWorld::ContainerStore::readState (const ESM::InventoryState& state) } - mLevelledItemMap = state.mLevelledItemMap; + mLevelledItemMap = inventory.mLevelledItemMap; } diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index f7c8a369c..d909a98cc 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -86,15 +86,12 @@ namespace MWWorld template void storeStates (CellRefList& collection, - std::vector >& states, + ESM::InventoryState& inventory, int& index, bool equipable = false) const; - virtual int getSlot (const MWWorld::LiveCellRefBase& ref) const; - ///< Return inventory slot that \a ref is in or -1 (if \a ref is not in a slot). - - virtual void setSlot (const MWWorld::ContainerStoreIterator& iter, int slot); - ///< Set slot for \a iter. Ignored if \a iter is an end iterator or if slot==-1. + virtual void storeEquipmentState (const MWWorld::LiveCellRefBase& ref, int index, ESM::InventoryState& inventory) const; + virtual void readEquipmentState (const MWWorld::ContainerStoreIterator& iter, int index, const ESM::InventoryState& inventory); public: ContainerStore(); diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index be93824e5..4950be912 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -49,33 +49,47 @@ void MWWorld::InventoryStore::initSlots (TSlots& slots_) slots_.push_back (end()); } -int MWWorld::InventoryStore::getSlot (const MWWorld::LiveCellRefBase& ref) const +void MWWorld::InventoryStore::storeEquipmentState(const MWWorld::LiveCellRefBase &ref, int index, ESM::InventoryState &inventory) const { for (int i = 0; i (mSlots.size()); ++i) if (mSlots[i].getType()!=-1 && mSlots[i]->getBase()==&ref) - return i; + { + inventory.mEquipmentSlots[index] = i; + } - return -1; + if (mSelectedEnchantItem.getType()!=-1 && mSelectedEnchantItem->getBase() == &ref) + inventory.mSelectedEnchantItem = index; } -void MWWorld::InventoryStore::setSlot (const MWWorld::ContainerStoreIterator& iter, int relativeSlot) +void MWWorld::InventoryStore::readEquipmentState(const MWWorld::ContainerStoreIterator &iter, int index, const ESM::InventoryState &inventory) { - if (relativeSlot < 0 || iter == end()) - return; - - // make sure the item can actually be equipped in this slot - std::pair, bool> allowedSlots = iter->getClass().getEquipmentSlots(*iter); - relativeSlot = std::min(int(allowedSlots.first.size()-1), relativeSlot); + if (index == inventory.mSelectedEnchantItem) + mSelectedEnchantItem = iter; - // unstack if required - if (!allowedSlots.second && iter->getRefData().getCount() > 1) + std::map::const_iterator found = inventory.mEquipmentSlots.find(index); + if (found != inventory.mEquipmentSlots.end()) { - MWWorld::ContainerStoreIterator newIter = addNewStack(*iter, 1); - iter->getRefData().setCount(iter->getRefData().getCount()-1); - mSlots[allowedSlots.first[relativeSlot]] = newIter; + if (found->second < 0 || found->second >= MWWorld::InventoryStore::Slots) + throw std::runtime_error("Invalid slot index in inventory state"); + + // make sure the item can actually be equipped in this slot + int slot = found->second; + std::pair, bool> allowedSlots = iter->getClass().getEquipmentSlots(*iter); + if (!allowedSlots.first.size()) + return; + if (std::find(allowedSlots.first.begin(), allowedSlots.first.end(), slot) == allowedSlots.first.end()) + slot = allowedSlots.first.front(); + + // unstack if required + if (!allowedSlots.second && iter->getRefData().getCount() > 1) + { + MWWorld::ContainerStoreIterator newIter = addNewStack(*iter, 1); + iter->getRefData().setCount(iter->getRefData().getCount()-1); + mSlots[slot] = newIter; + } + else + mSlots[slot] = iter; } - else - mSlots[allowedSlots.first[relativeSlot]] = iter; } MWWorld::InventoryStore::InventoryStore() diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 7bd977e39..9a154373a 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -113,11 +113,8 @@ namespace MWWorld void fireEquipmentChangedEvent(); - virtual int getSlot (const MWWorld::LiveCellRefBase& ref) const; - ///< Return inventory slot that \a ref is in or -1 (if \a ref is not in a slot). - - virtual void setSlot (const MWWorld::ContainerStoreIterator& iter, int relativeSlot); - ///< Set slot for \a iter. Ignored if \a iter is an end iterator or if slot==-1. + virtual void storeEquipmentState (const MWWorld::LiveCellRefBase& ref, int index, ESM::InventoryState& inventory) const; + virtual void readEquipmentState (const MWWorld::ContainerStoreIterator& iter, int index, const ESM::InventoryState& inventory); public: diff --git a/components/esm/inventorystate.cpp b/components/esm/inventorystate.cpp index b946f9501..4eaaa9f9f 100644 --- a/components/esm/inventorystate.cpp +++ b/components/esm/inventorystate.cpp @@ -4,42 +4,33 @@ #include "esmreader.hpp" #include "esmwriter.hpp" -namespace -{ - void read (ESM::ESMReader &esm, ESM::ObjectState& state, int& slot) - { - slot = -1; - esm.getHNOT (slot, "SLOT"); - - state.mRef.loadId(esm, true); - state.load (esm); - } - - void write (ESM::ESMWriter &esm, const ESM::ObjectState& state, int slot) - { - int unused = 0; - esm.writeHNT ("IOBJ", unused); - - if (slot!=-1) - esm.writeHNT ("SLOT", slot); - - state.save (esm, true); - } -} - void ESM::InventoryState::load (ESMReader &esm) { + int index = 0; while (esm.isNextSub ("IOBJ")) { int unused; // no longer used esm.getHT(unused); ObjectState state; - int slot; - read (esm, state, slot); + + // obsolete + if (esm.isNextSub("SLOT")) + { + int slot; + esm.getHT(slot); + mEquipmentSlots[index] = slot; + } + + state.mRef.loadId(esm, true); + state.load (esm); + if (state.mCount == 0) continue; - mItems.push_back (std::make_pair (state, slot)); + + mItems.push_back (state); + + ++index; } while (esm.isNextSub("LEVM")) @@ -64,12 +55,30 @@ void ESM::InventoryState::load (ESMReader &esm) } mPermanentMagicEffectMagnitudes[id] = params; } + + while (esm.isNextSub("EQUI")) + { + esm.getSubHeader(); + int index; + esm.getT(index); + int slot; + esm.getT(slot); + mEquipmentSlots[index] = slot; + } + + mSelectedEnchantItem = -1; + esm.getHNOT(mSelectedEnchantItem, "SELE"); } void ESM::InventoryState::save (ESMWriter &esm) const { - for (std::vector >::const_iterator iter (mItems.begin()); iter!=mItems.end(); ++iter) - write (esm, iter->first, iter->second); + for (std::vector::const_iterator iter (mItems.begin()); iter!=mItems.end(); ++iter) + { + int unused = 0; + esm.writeHNT ("IOBJ", unused); + + iter->save (esm, true); + } for (std::map::const_iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it) { @@ -88,4 +97,15 @@ void ESM::InventoryState::save (ESMWriter &esm) const esm.writeHNT ("MULT", pIt->second); } } + + for (std::map::const_iterator it = mEquipmentSlots.begin(); it != mEquipmentSlots.end(); ++it) + { + esm.startSubRecord("EQUI"); + esm.writeT(it->first); + esm.writeT(it->second); + esm.endRecord("EQUI"); + } + + if (mSelectedEnchantItem != -1) + esm.writeHNT ("SELE", mSelectedEnchantItem); } diff --git a/components/esm/inventorystate.hpp b/components/esm/inventorystate.hpp index 13af28e30..d5c317beb 100644 --- a/components/esm/inventorystate.hpp +++ b/components/esm/inventorystate.hpp @@ -15,14 +15,19 @@ namespace ESM /// \brief State for inventories and containers struct InventoryState { - /// - std::vector > mItems; + std::vector mItems; + + // + std::map mEquipmentSlots; std::map mLevelledItemMap; typedef std::map > > TEffectMagnitudes; TEffectMagnitudes mPermanentMagicEffectMagnitudes; + int mSelectedEnchantItem; // For inventories only + + InventoryState() : mSelectedEnchantItem(-1) {} virtual ~InventoryState() {} virtual void load (ESMReader &esm); From b0c2aec374e7faddbcc9927c537457f63de6a6be Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Jan 2015 17:29:03 +0100 Subject: [PATCH 287/740] Add warning for missing body parts --- apps/openmw/mwrender/npcanimation.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index a8ba1abf5..9b05ce0a2 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -811,6 +811,8 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vectormData.mPart == ESM::BodyPart::MP_Upperarm)) bodypart = NULL; } + else if (!bodypart) + std::cerr << "Failed to find body part '" << part->mFemale << "'" << std::endl; } if(!bodypart && !part->mMale.empty()) { @@ -824,6 +826,8 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vectormData.mPart == ESM::BodyPart::MP_Upperarm)) bodypart = NULL; } + else if (!bodypart) + std::cerr << "Failed to find body part '" << part->mMale << "'" << std::endl; } if(bodypart) From bf90b86f73d47a95442865b9254b46d8e350c0ae Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Jan 2015 20:09:30 +0100 Subject: [PATCH 288/740] ESSImport: add some missing subrecords --- apps/essimporter/importacdt.cpp | 4 ++++ apps/essimporter/importplayer.cpp | 9 ++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/apps/essimporter/importacdt.cpp b/apps/essimporter/importacdt.cpp index e590e2826..00bd4ad80 100644 --- a/apps/essimporter/importacdt.cpp +++ b/apps/essimporter/importacdt.cpp @@ -60,6 +60,10 @@ namespace ESSImport if (esm.isNextSub("PWPS")) esm.skipHSub(); + // unsure at which point between LSTN and CHRD + if (esm.isNextSub("APUD")) + esm.skipHSub(); // 40 bytes, starts with string "ancestor guardian"... + if (esm.isNextSub("WNAM")) { esm.skipHSub(); // seen values: "ancestor guardian", "bound dagger_en". Summoned creature / bound weapons? diff --git a/apps/essimporter/importplayer.cpp b/apps/essimporter/importplayer.cpp index ea9f1932c..9845ab072 100644 --- a/apps/essimporter/importplayer.cpp +++ b/apps/essimporter/importplayer.cpp @@ -63,8 +63,11 @@ namespace ESSImport mFactions.push_back(fnam); } + if (esm.isNextSub("AADT")) + esm.skipHSub(); // 44 bytes, no clue + if (esm.isNextSub("KNAM")) - esm.skipHSub(); + esm.skipHSub(); // assigned Quick Keys, I think if (esm.isNextSub("WERE")) { @@ -73,6 +76,10 @@ namespace ESSImport esm.getSubHeader(); esm.skip(152); } + + // unsure if before or after WERE + if (esm.isNextSub("ANIS")) + esm.skipHSub(); } } From 8e5c8aa562ba4d03c112bf78ee3a840d0c05c12d Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Jan 2015 23:57:00 +0100 Subject: [PATCH 289/740] Add support for passing in Ogre plugin directory via CMake --- CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7ceee29e6..c3def1381 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,6 +51,8 @@ option(OGRE_STATIC "Link static build of Ogre and Ogre Plugins into the binarie option(BOOST_STATIC "Link static build of Boost into the binaries" FALSE) option(SDL2_STATIC "Link static build of SDL into the binaries" FALSE) +set(CUSTOM_OGRE_PLUGIN_DIR "" CACHE PATH "Specify a custom directory for Ogre plugins (autodetected by default)") + option(OPENMW_UNITY_BUILD "Use fewer compilation units to speed up compile time" FALSE) # Apps and tools @@ -323,8 +325,10 @@ if (APPLE AND OPENMW_OSX_DEPLOYMENT) # make it empty so plugin loading code can check this and try to find plugins inside app bundle add_definitions(-DOGRE_PLUGIN_DIR="") else() - if (NOT DEFINED ${OGRE_PLUGIN_DIR}) + if (CUSTOM_OGRE_PLUGIN_DIR STREQUAL "") set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_REL}) + else() + set(OGRE_PLUGIN_DIR ${CUSTOM_OGRE_PLUGIN_DIR}) endif() add_definitions(-DOGRE_PLUGIN_DIR="${OGRE_PLUGIN_DIR}") From 09f11fbff224b0c5c364629d56bd2929d0956875 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 24 Jan 2015 00:18:17 +0100 Subject: [PATCH 290/740] ESSImport: convert selected spell / selected enchant item --- apps/essimporter/converter.hpp | 21 +++++++++++++++++++++ apps/essimporter/importacdt.cpp | 11 +++++------ apps/essimporter/importacdt.hpp | 3 +++ 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 7565b78d4..6f85b01cf 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -226,7 +226,28 @@ public: ESM::NpcStats& npcStats = mContext->mPlayer.mObject.mNpcStats; convertNpcData(refr.mActorData, npcStats); + + mSelectedSpell = refr.mActorData.mSelectedSpell; + if (!refr.mActorData.mSelectedEnchantItem.empty()) + { + ESM::InventoryState& invState = mContext->mPlayer.mObject.mInventory; + + for (unsigned int i=0; i Date: Sat, 24 Jan 2015 14:32:02 +0100 Subject: [PATCH 291/740] Fix loading faction reactions for older savegames (Fixes #2301) --- components/esm/dialoguestate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/dialoguestate.cpp b/components/esm/dialoguestate.cpp index f546462a3..f302e36dc 100644 --- a/components/esm/dialoguestate.cpp +++ b/components/esm/dialoguestate.cpp @@ -25,7 +25,7 @@ void ESM::DialogueState::load (ESMReader &esm) while (esm.isNextSub ("REAC")) { esm.skipHSub(); - esm.getSubHeader(); + esm.getSubName(); esm.skipHSub(); } } From b1bd236345fbe4fbd84f9855c958c02d323a9863 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 24 Jan 2015 16:15:52 +0100 Subject: [PATCH 292/740] ESSImport: convert script local variables Had to add special reading code to openmw, because the variable names are not stored. --- apps/essimporter/CMakeLists.txt | 1 + apps/essimporter/converter.cpp | 3 ++ apps/essimporter/convertscri.cpp | 32 ++++++++++++++++ apps/essimporter/convertscri.hpp | 16 ++++++++ apps/essimporter/importer.cpp | 6 +++ apps/openmw/mwscript/locals.cpp | 63 +++++++++++++++++++++++++------- components/esm/locals.cpp | 6 +-- components/esm/variant.cpp | 26 ++++++++++++- components/esm/variant.hpp | 3 +- components/esm/variantimp.cpp | 33 +++++++++++++++-- 10 files changed, 167 insertions(+), 22 deletions(-) create mode 100644 apps/essimporter/convertscri.cpp create mode 100644 apps/essimporter/convertscri.hpp diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index 5db3a86dc..409b8bcff 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -23,6 +23,7 @@ set(ESSIMPORTER_FILES convertinventory.cpp convertcrec.cpp convertcntc.cpp + convertscri.cpp ) add_executable(openmw-essimporter diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 75c2911fd..3b82988b8 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -9,6 +9,7 @@ #include "convertcrec.hpp" #include "convertcntc.hpp" +#include "convertscri.hpp" namespace { @@ -29,6 +30,8 @@ namespace objstate.mRef.mRefNum = cellref.mRefNum; if (cellref.mDeleted) objstate.mCount = 0; + convertSCRI(cellref.mSCRI, objstate.mLocals); + objstate.mHasLocals = !objstate.mLocals.mVariables.empty(); } bool isIndexedRefId(const std::string& indexedRefId) diff --git a/apps/essimporter/convertscri.cpp b/apps/essimporter/convertscri.cpp new file mode 100644 index 000000000..dbe35a010 --- /dev/null +++ b/apps/essimporter/convertscri.cpp @@ -0,0 +1,32 @@ +#include "convertscri.hpp" + +#include + +namespace +{ + + template + void storeVariables(const std::vector& variables, ESM::Locals& locals, const std::string& scriptname) + { + for (typename std::vector::const_iterator it = variables.begin(); it != variables.end(); ++it) + { + ESM::Variant val(*it); + val.setType(VariantType); + locals.mVariables.push_back(std::make_pair(std::string(), val)); + } + } + +} + +namespace ESSImport +{ + + void convertSCRI(const SCRI &scri, ESM::Locals &locals) + { + // order *is* important, as we do not have variable names available in this format + storeVariables (scri.mShorts, locals, scri.mScript); + storeVariables (scri.mLongs, locals, scri.mScript); + storeVariables (scri.mFloats, locals, scri.mScript); + } + +} diff --git a/apps/essimporter/convertscri.hpp b/apps/essimporter/convertscri.hpp new file mode 100644 index 000000000..2d8945666 --- /dev/null +++ b/apps/essimporter/convertscri.hpp @@ -0,0 +1,16 @@ +#ifndef OPENMW_ESSIMPORT_CONVERTSCRI_H +#define OPENMW_ESSIMPORT_CONVERTSCRI_H + +#include "importscri.hpp" + +#include + +namespace ESSImport +{ + + /// Convert script variable assignments + void convertSCRI (const SCRI& scri, ESM::Locals& locals); + +} + +#endif diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index ed149b023..73a12769a 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -237,6 +237,12 @@ namespace ESSImport converters[recJOUR ] = boost::shared_ptr(new ConvertJOUR()); converters[ESM::REC_SCPT] = boost::shared_ptr(new ConvertSCPT()); + // TODO: + // - REGN (weather in certain regions?) + // - VFXM + // - SPLM (active spell effects) + // - PROJ (magic projectiles in air) + std::set unknownRecords; for (std::map >::const_iterator it = converters.begin(); diff --git a/apps/openmw/mwscript/locals.cpp b/apps/openmw/mwscript/locals.cpp index a1ee48ae6..fe3e49827 100644 --- a/apps/openmw/mwscript/locals.cpp +++ b/apps/openmw/mwscript/locals.cpp @@ -10,6 +10,8 @@ #include "../mwbase/environment.hpp" #include "../mwbase/scriptmanager.hpp" +#include + namespace MWScript { void Locals::configure (const ESM::Script& script) @@ -124,27 +126,60 @@ namespace MWScript const Compiler::Locals& declarations = MWBase::Environment::get().getScriptManager()->getLocals(script); - for (std::vector >::const_iterator iter - = locals.mVariables.begin(); iter!=locals.mVariables.end(); ++iter) + int index = 0, numshorts = 0, numlongs = 0; + for (unsigned int v=0; vfirst); - char index = declarations.getIndex (iter->first); + ESM::VarType type = locals.mVariables[v].second.getType(); + if (type == ESM::VT_Short) + ++numshorts; + else if (type == ESM::VT_Int) + ++numlongs; + } - try + for (std::vector >::const_iterator iter + = locals.mVariables.begin(); iter!=locals.mVariables.end(); ++iter,++index) + { + if (iter->first.empty()) { - switch (type) + // no variable names available (this will happen for legacy, i.e. ESS-imported savegames only) + try { - case 's': mShorts.at (index) = iter->second.getInteger(); break; - case 'l': mLongs.at (index) = iter->second.getInteger(); break; - case 'f': mFloats.at (index) = iter->second.getFloat(); break; - - // silently ignore locals that don't exist anymore + if (index >= numshorts+numlongs) + mFloats.at(index - (numshorts+numlongs)) = iter->second.getFloat(); + else if (index >= numshorts) + mLongs.at(index - numshorts) = iter->second.getInteger(); + else + mShorts.at(index) = iter->second.getInteger(); + } + catch (std::exception& e) + { + std::cerr << "Failed to read local variable state for script '" + << script << "' (legacy format): " << e.what() + << "\nNum shorts: " << numshorts << " / " << mShorts.size() + << " Num longs: " << numlongs << " / " << mLongs.size() << std::endl; } } - catch (...) + else { - // ignore type changes - /// \todo write to log + char type = declarations.getType (iter->first); + char index = declarations.getIndex (iter->first); + + try + { + switch (type) + { + case 's': mShorts.at (index) = iter->second.getInteger(); break; + case 'l': mLongs.at (index) = iter->second.getInteger(); break; + case 'f': mFloats.at (index) = iter->second.getFloat(); break; + + // silently ignore locals that don't exist anymore + } + } + catch (...) + { + // ignore type changes + /// \todo write to log + } } } } diff --git a/components/esm/locals.cpp b/components/esm/locals.cpp index 9c470a025..f0cfd49f0 100644 --- a/components/esm/locals.cpp +++ b/components/esm/locals.cpp @@ -11,7 +11,7 @@ void ESM::Locals::load (ESMReader &esm) std::string id = esm.getHString(); Variant value; - value.read (esm, Variant::Format_Info); + value.read (esm, Variant::Format_Local); mVariables.push_back (std::make_pair (id, value)); } @@ -23,6 +23,6 @@ void ESM::Locals::save (ESMWriter &esm) const iter!=mVariables.end(); ++iter) { esm.writeHNString ("LOCA", iter->first); - iter->second.write (esm, Variant::Format_Info); + iter->second.write (esm, Variant::Format_Local); } -} \ No newline at end of file +} diff --git a/components/esm/variant.cpp b/components/esm/variant.cpp index 4127a9d62..c65eed5e0 100644 --- a/components/esm/variant.cpp +++ b/components/esm/variant.cpp @@ -13,6 +13,7 @@ namespace const uint32_t STRV = ESM::FourCC<'S','T','R','V'>::value; const uint32_t INTV = ESM::FourCC<'I','N','T','V'>::value; const uint32_t FLTV = ESM::FourCC<'F','L','T','V'>::value; + const uint32_t STTV = ESM::FourCC<'S','T','T','V'>::value; } ESM::Variant::Variant() : mType (VT_None), mData (0) {} @@ -141,7 +142,7 @@ void ESM::Variant::read (ESMReader& esm, Format format) esm.fail ("invalid subrecord: " + name.toString()); } } - else // info + else if (format == Format_Info) { esm.getSubName(); NAME name = esm.retSubName(); @@ -157,6 +158,26 @@ void ESM::Variant::read (ESMReader& esm, Format format) else esm.fail ("invalid subrecord: " + name.toString()); } + else if (format == Format_Local) + { + esm.getSubName(); + NAME name = esm.retSubName(); + + if (name==INTV) + { + type = VT_Int; + } + else if (name==FLTV) + { + type = VT_Float; + } + else if (name==STTV) + { + type = VT_Short; + } + else + esm.fail ("invalid subrecord: " + name.toString()); + } setType (type); @@ -179,6 +200,9 @@ void ESM::Variant::write (ESMWriter& esm, Format format) const if (format==Format_Info) throw std::runtime_error ("can not serialise variant of type none to info format"); + if (format==Format_Local) + throw std::runtime_error ("can not serialise variant of type none to local format"); + // nothing to do here for GMST format } else diff --git a/components/esm/variant.hpp b/components/esm/variant.hpp index d6c1a5489..5f179a7bd 100644 --- a/components/esm/variant.hpp +++ b/components/esm/variant.hpp @@ -33,7 +33,8 @@ namespace ESM { Format_Global, Format_Gmst, - Format_Info // also used for local variables in saved game files + Format_Info, + Format_Local // local script variables in save game files }; Variant(); diff --git a/components/esm/variantimp.cpp b/components/esm/variantimp.cpp index 1bacdc077..fd068fc19 100644 --- a/components/esm/variantimp.cpp +++ b/components/esm/variantimp.cpp @@ -81,6 +81,9 @@ void ESM::VariantStringData::read (ESMReader& esm, Variant::Format format, VarTy if (format==Variant::Format_Info) esm.fail ("info variables of type string not supported"); + if (format==Variant::Format_Local) + esm.fail ("local variables of type string not supported"); + // GMST mValue = esm.getHString(); } @@ -173,6 +176,21 @@ void ESM::VariantIntegerData::read (ESMReader& esm, Variant::Format format, VarT esm.getHT (mValue); } + else if (format==Variant::Format_Local) + { + if (type==VT_Short) + { + short value; + esm.getHT(value); + mValue = value; + } + else if (type==VT_Int) + { + esm.getHT(mValue); + } + else + esm.fail("unsupported local variable integer type"); + } } void ESM::VariantIntegerData::write (ESMWriter& esm, Variant::Format format, VarType type) const @@ -204,6 +222,15 @@ void ESM::VariantIntegerData::write (ESMWriter& esm, Variant::Format format, Var esm.writeHNT ("INTV", mValue); } + else if (format==Variant::Format_Local) + { + if (type==VT_Short) + esm.writeHNT ("STTV", (short)mValue); + else if (type == VT_Int) + esm.writeHNT ("INTV", mValue); + else + throw std::runtime_error("unsupported local variable integer type"); + } } bool ESM::VariantIntegerData::isEqual (const VariantDataBase& value) const @@ -252,7 +279,7 @@ void ESM::VariantFloatData::read (ESMReader& esm, Variant::Format format, VarTyp { esm.getHNT (mValue, "FLTV"); } - else if (format==Variant::Format_Gmst || format==Variant::Format_Info) + else if (format==Variant::Format_Gmst || format==Variant::Format_Info || format==Variant::Format_Local) { esm.getHT (mValue); } @@ -268,7 +295,7 @@ void ESM::VariantFloatData::write (ESMWriter& esm, Variant::Format format, VarTy esm.writeHNString ("FNAM", "f"); esm.writeHNT ("FLTV", mValue); } - else if (format==Variant::Format_Gmst || format==Variant::Format_Info) + else if (format==Variant::Format_Gmst || format==Variant::Format_Info || format==Variant::Format_Local) { esm.writeHNT ("FLTV", mValue); } @@ -277,4 +304,4 @@ void ESM::VariantFloatData::write (ESMWriter& esm, Variant::Format format, VarTy bool ESM::VariantFloatData::isEqual (const VariantDataBase& value) const { return dynamic_cast (value).mValue==mValue; -} \ No newline at end of file +} From 72f7c2e555222120b870765758ab41e0ff29245c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 24 Jan 2015 16:26:43 +0100 Subject: [PATCH 293/740] Move weather reset to clear() method --- apps/openmw/mwworld/weather.cpp | 18 ++++++++++-------- apps/openmw/mwworld/weather.hpp | 2 ++ apps/openmw/mwworld/worldimp.cpp | 1 + 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 6532c5969..a74c24768 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -770,14 +770,6 @@ bool WeatherManager::readRecord(ESM::ESMReader& reader, uint32_t type) ESM::WeatherState state; state.load(reader); - // reset other temporary state, now that we loaded successfully - stopSounds(); // let's hope this never throws - mRegionOverrides.clear(); - mRegionMods.clear(); - mThunderFlash = 0.0; - mThunderChance = 0.0; - mThunderChanceNeeded = 50.0; - // swap in the loaded values now that we can't fail mHour = state.mHour; mWindSpeed = state.mWindSpeed; @@ -794,6 +786,16 @@ bool WeatherManager::readRecord(ESM::ESMReader& reader, uint32_t type) return false; } +void WeatherManager::clear() +{ + stopSounds(); + mRegionOverrides.clear(); + mRegionMods.clear(); + mThunderFlash = 0.0; + mThunderChance = 0.0; + mThunderChanceNeeded = 50.0; +} + void WeatherManager::switchToNextWeather(bool instantly) { MWBase::World* world = MWBase::Environment::get().getWorld(); diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 830b5c376..a2e668159 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -201,6 +201,8 @@ namespace MWWorld bool readRecord(ESM::ESMReader& reader, uint32_t type); + void clear(); + private: float mHour; float mWindSpeed; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ceac85bca..8bcfcb421 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -265,6 +265,7 @@ namespace MWWorld void World::clear() { + mWeatherManager->clear(); mRendering->clear(); mProjectileManager->clear(); From 33ce03dfc597dd4d2f08356bfb0f3fbf1364eb0c Mon Sep 17 00:00:00 2001 From: Nathan Aclander Date: Sat, 24 Jan 2015 17:17:05 -0800 Subject: [PATCH 294/740] Should be compared against uint only --- components/esm/esmcommon.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esm/esmcommon.hpp b/components/esm/esmcommon.hpp index 1bdadead2..80706793a 100644 --- a/components/esm/esmcommon.hpp +++ b/components/esm/esmcommon.hpp @@ -40,8 +40,8 @@ union NAME_T } bool operator!=(const std::string &str) const { return !((*this)==str); } - bool operator==(int v) const { return v == val; } - bool operator!=(int v) const { return v != val; } + bool operator==(uint32_t v) const { return v == val; } + bool operator!=(uint32_t v) const { return v != val; } std::string toString() const { return std::string(name, strnlen(name, LEN)); } From f7f593b1436d59b41a52e6e0dbec934b9d8e92af Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 25 Jan 2015 18:30:33 +0100 Subject: [PATCH 295/740] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index d2c5cdc04..f261ea423 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -75,6 +75,7 @@ Programmers Michał Bień (Glorf) Miroslav Puda (pakanek) MiroslavR + naclander Narmo Nathan Jeffords (blunted2night) Nikolay Kasyanov (corristo) From b0b275a936a815de94eed2ee1391df2a6062137b Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 26 Jan 2015 12:53:01 +1300 Subject: [PATCH 296/740] Fix for MSVC 2013 compiler issues. Fixes: C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\utility(199): error C2079: 'std::pair::second' uses undefined class 'boost::shared_ptr' Which cascades to 36 more errors. --- apps/essimporter/importer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 73a12769a..10fad37b0 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -1,4 +1,5 @@ #include "importer.hpp" +#include #include From e02bab67ba67dffc133f0583cc0f593709af90c5 Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 26 Jan 2015 13:17:16 +1300 Subject: [PATCH 297/740] Fixed MSVC warnings. warning C4099: 'ESM::ESMReader' : type name first seen using 'class' now seen using 'struct' warning C4099: 'ESM::CellId' : type name first seen using 'struct' now seen using 'class' --- apps/essimporter/importacdt.hpp | 2 +- apps/essimporter/importdial.hpp | 2 +- apps/essimporter/importinfo.hpp | 2 +- apps/essimporter/importjour.hpp | 2 +- apps/essimporter/importklst.hpp | 2 +- apps/essimporter/importques.hpp | 2 +- components/esm/loadcell.hpp | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/essimporter/importacdt.hpp b/apps/essimporter/importacdt.hpp index 4eb5edb73..53783a364 100644 --- a/apps/essimporter/importacdt.hpp +++ b/apps/essimporter/importacdt.hpp @@ -9,7 +9,7 @@ namespace ESM { - struct ESMReader; + class ESMReader; } namespace ESSImport diff --git a/apps/essimporter/importdial.hpp b/apps/essimporter/importdial.hpp index fe4b0c5b4..9a1e88233 100644 --- a/apps/essimporter/importdial.hpp +++ b/apps/essimporter/importdial.hpp @@ -2,7 +2,7 @@ #define OPENMW_ESSIMPORT_IMPORTDIAL_H namespace ESM { - struct ESMReader; + class ESMReader; } namespace ESSImport diff --git a/apps/essimporter/importinfo.hpp b/apps/essimporter/importinfo.hpp index 08f588f8d..f4d616786 100644 --- a/apps/essimporter/importinfo.hpp +++ b/apps/essimporter/importinfo.hpp @@ -5,7 +5,7 @@ namespace ESM { - struct ESMReader; + class ESMReader; } namespace ESSImport diff --git a/apps/essimporter/importjour.hpp b/apps/essimporter/importjour.hpp index fe8775a93..1b2d094f6 100644 --- a/apps/essimporter/importjour.hpp +++ b/apps/essimporter/importjour.hpp @@ -5,7 +5,7 @@ namespace ESM { - struct ESMReader; + class ESMReader; } namespace ESSImport diff --git a/apps/essimporter/importklst.hpp b/apps/essimporter/importklst.hpp index e333e7150..d07332600 100644 --- a/apps/essimporter/importklst.hpp +++ b/apps/essimporter/importklst.hpp @@ -6,7 +6,7 @@ namespace ESM { - struct ESMReader; + class ESMReader; } namespace ESSImport diff --git a/apps/essimporter/importques.hpp b/apps/essimporter/importques.hpp index d7e718b92..51fe22434 100644 --- a/apps/essimporter/importques.hpp +++ b/apps/essimporter/importques.hpp @@ -6,7 +6,7 @@ namespace ESM { - struct ESMReader; + class ESMReader; } namespace ESSImport diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index e1a6eee1a..4c2ac68dc 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -18,7 +18,7 @@ namespace ESM { class ESMReader; class ESMWriter; - class CellId; +struct CellId; /* Moved cell reference tracking object. This mainly stores the target cell of the reference, so we can easily know where it has been moved when another From f95743ccc3646aa22f36f250a75daeac14f0a6a6 Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 26 Jan 2015 13:18:21 +1300 Subject: [PATCH 298/740] Fixed MSVC warning. warning C4305: 'return' : truncation from 'double' to 'float' --- components/esm/esmreader.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index e7721bb8f..ebbc935f6 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -32,7 +32,7 @@ public: int getVer() const { return mHeader.mData.version; } int getRecordCount() const { return mHeader.mData.records; } - float getFVer() const { if(mHeader.mData.version == VER_12) return 1.2; else return 1.3; } + float getFVer() const { return (mHeader.mData.version == VER_12) ? 1.2f : 1.3f; } const std::string getAuthor() const { return mHeader.mData.author.toString(); } const std::string getDesc() const { return mHeader.mData.desc.toString(); } const std::vector &getGameFiles() const { return mHeader.mMaster; } From 946dd16696761a8e87565ed1bd93826b05b0e6b8 Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 26 Jan 2015 13:57:22 +1300 Subject: [PATCH 299/740] Fixed Windows warning. warning C4800: 'int' : forcing value to bool 'true' or 'false' (performance warning) --- apps/essimporter/converter.hpp | 2 +- components/esm/loadcell.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 6f85b01cf..90b75fee1 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -263,7 +263,7 @@ public: for (std::vector::const_iterator it = pcdt.mFactions.begin(); it != pcdt.mFactions.end(); ++it) { ESM::NpcStats::Faction faction; - faction.mExpelled = it->mFlags & 0x2; + faction.mExpelled = (it->mFlags & 0x2) != 0; faction.mRank = it->mRank; faction.mReputation = it->mReputation; mContext->mPlayer.mObject.mNpcStats.mFactions[it->mFactionName.toString()] = faction; diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 4c2ac68dc..d982bbfd4 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -137,7 +137,7 @@ struct Cell bool hasWater() const { - return (mData.mFlags&HasWater); + return (mData.mFlags&HasWater) != 0; } // Restore the given reader to the stored position. Will try to open From 70e4f821ba394840554199f1f84066a8711e454a Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 26 Jan 2015 13:58:13 +1300 Subject: [PATCH 300/740] Fix Windows warning warning C4244: 'initializing' : conversion from 'float' to 'int', possible loss of data --- apps/essimporter/importer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 10fad37b0..8f6563dee 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -342,8 +342,8 @@ namespace ESSImport { // exterior cell -> determine cell coordinates based on position const int cellSize = 8192; - int cellX = std::floor(context.mPlayer.mObject.mPosition.pos[0]/cellSize); - int cellY = std::floor(context.mPlayer.mObject.mPosition.pos[1]/cellSize); + int cellX = static_cast(std::floor(context.mPlayer.mObject.mPosition.pos[0]/cellSize)); + int cellY = static_cast(std::floor(context.mPlayer.mObject.mPosition.pos[1] / cellSize)); context.mPlayer.mCellId.mIndex.mX = cellX; context.mPlayer.mCellId.mIndex.mY = cellY; } From 1410819e20308b09bdab02c04308ea12c1fdfcb6 Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Sun, 25 Jan 2015 22:23:38 -0600 Subject: [PATCH 301/740] Dialog fix for line breaks in the middle of words. Issue 1049 Adjust the TypesetBookImpl::Typesetter to not assume a word break at the end of write() calls. A word break is assumed if any of the other content insertion methods are used (section break, add/select content, etc). --- apps/openmw/mwgui/bookpage.cpp | 88 ++++++++++++++++++++++++++++------ 1 file changed, 74 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index 3b1d40fc3..c9cfc8c2c 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -195,8 +195,20 @@ struct TypesetBookImpl : TypesetBook struct TypesetBookImpl::Typesetter : BookTypesetter { + struct PartialText { + StyleImpl *mStyle; + Utf8Stream::Point mBegin; + Utf8Stream::Point mEnd; + int mWidth; + + PartialText( StyleImpl *style, Utf8Stream::Point begin, Utf8Stream::Point end, int width) : + mStyle(style), mBegin(begin), mEnd(end), mWidth(width) + {} + }; + typedef TypesetBookImpl Book; typedef boost::shared_ptr BookPtr; + typedef std::vector::const_iterator PartialTextConstIterator; int mPageWidth; int mPageHeight; @@ -207,6 +219,8 @@ struct TypesetBookImpl::Typesetter : BookTypesetter Run * mRun; std::vector mSectionAlignment; + std::vector mPartialWhitespace; + std::vector mPartialWord; Book::Content const * mCurrentContent; Alignment mCurrentAlignment; @@ -273,6 +287,8 @@ struct TypesetBookImpl::Typesetter : BookTypesetter intptr_t addContent (Utf8Span text, bool select) { + add_partial_text(); + Contents::iterator i = mBook->mContents.insert (mBook->mContents.end (), Content (text.first, text.second)); if (select) @@ -283,6 +299,8 @@ struct TypesetBookImpl::Typesetter : BookTypesetter void selectContent (intptr_t contentHandle) { + add_partial_text(); + mCurrentContent = reinterpret_cast (contentHandle); } @@ -302,12 +320,16 @@ struct TypesetBookImpl::Typesetter : BookTypesetter { assert (margin == 0); //TODO: figure out proper behavior here... + add_partial_text(); + mRun = NULL; mLine = NULL; } void sectionBreak (float margin) { + add_partial_text(); + if (mBook->mSections.size () > 0) { mRun = NULL; @@ -321,6 +343,8 @@ struct TypesetBookImpl::Typesetter : BookTypesetter void setSectionAlignment (Alignment sectionAlignment) { + add_partial_text(); + if (mSection != NULL) mSectionAlignment.back () = sectionAlignment; mCurrentAlignment = sectionAlignment; @@ -331,6 +355,8 @@ struct TypesetBookImpl::Typesetter : BookTypesetter int curPageStart = 0; int curPageStop = 0; + add_partial_text(); + std::vector ::iterator sa = mSectionAlignment.begin (); for (Sections::iterator i = mBook->mSections.begin (); i != mBook->mSections.end (); ++i, ++sa) { @@ -415,23 +441,23 @@ struct TypesetBookImpl::Typesetter : BookTypesetter void writeImpl (StyleImpl * style, Utf8Stream::Point _begin, Utf8Stream::Point _end) { - int line_height = style->mFont->getDefaultHeight (); - Utf8Stream stream (_begin, _end); while (!stream.eof ()) { if (ucsLineBreak (stream.peek ())) { + add_partial_text(); stream.consume (); mLine = NULL, mRun = NULL; continue; } + if (ucsBreakingSpace (stream.peek ()) && !mPartialWord.empty()) + add_partial_text(); + int word_width = 0; - int word_height = 0; int space_width = 0; - int character_count = 0; Utf8Stream::Point lead = stream.current (); @@ -450,8 +476,6 @@ struct TypesetBookImpl::Typesetter : BookTypesetter MyGUI::GlyphInfo* gi = style->mFont->getGlyphInfo (stream.peek ()); if (gi) word_width += gi->advance + gi->bearingX; - word_height = line_height; - ++character_count; stream.consume (); } @@ -460,21 +484,57 @@ struct TypesetBookImpl::Typesetter : BookTypesetter if (lead == extent) break; - int left = mLine ? mLine->mRect.right : 0; + if ( lead != origin ) + mPartialWhitespace.push_back (PartialText (style, lead, origin, space_width)); + if ( origin != extent ) + mPartialWord.push_back (PartialText (style, origin, extent, word_width)); + } + } - if (left + space_width + word_width > mPageWidth) - { - mLine = NULL, mRun = NULL; + void add_partial_text () + { + if (mPartialWhitespace.empty() && mPartialWord.empty()) + return; - append_run (style, origin, extent, extent - origin, word_width, mBook->mRect.bottom + word_height); - } - else + int space_width = 0; + int word_width = 0; + + for (PartialTextConstIterator i = mPartialWhitespace.begin (); i != mPartialWhitespace.end (); ++i) + space_width += i->mWidth; + for (PartialTextConstIterator i = mPartialWord.begin (); i != mPartialWord.end (); ++i) + word_width += i->mWidth; + + int left = mLine ? mLine->mRect.right : 0; + + if (left + space_width + word_width > mPageWidth) + { + mLine = NULL, mRun = NULL, left = 0; + } + else + { + for (PartialTextConstIterator i = mPartialWhitespace.begin (); i != mPartialWhitespace.end (); ++i) { int top = mLine ? mLine->mRect.top : mBook->mRect.bottom; + int line_height = i->mStyle->mFont->getDefaultHeight (); + + append_run ( i->mStyle, i->mBegin, i->mEnd, 0, left + i->mWidth, top + line_height); - append_run (style, lead, extent, extent - origin, left + space_width + word_width, top + word_height); + left = mLine->mRect.right; } } + + for (PartialTextConstIterator i = mPartialWord.begin (); i != mPartialWord.end (); ++i) + { + int top = mLine ? mLine->mRect.top : mBook->mRect.bottom; + int line_height = i->mStyle->mFont->getDefaultHeight (); + + append_run (i->mStyle, i->mBegin, i->mEnd, i->mEnd - i->mBegin, left + i->mWidth, top + line_height); + + left = mLine->mRect.right; + } + + mPartialWhitespace.clear(); + mPartialWord.clear(); } void append_run (StyleImpl * style, Utf8Stream::Point begin, Utf8Stream::Point end, int pc, int right, int bottom) From e298589e7fc3641abd5a20b2da3fd6400d272d5c Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 26 Jan 2015 18:46:18 +1300 Subject: [PATCH 302/740] Reorganised DataFilesPage.cpp code. Removed some recursive calling of saveSettings() and loadSettings(). --- apps/launcher/datafilespage.cpp | 48 +++++++++++++++------------------ apps/launcher/datafilespage.hpp | 1 + 2 files changed, 22 insertions(+), 27 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 245665421..ff1364b08 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -69,19 +69,6 @@ void Launcher::DataFilesPage::buildView() bool Launcher::DataFilesPage::loadSettings() { - QStringList paths = mGameSettings.getDataDirs(); - - foreach (const QString &path, paths) - mSelector->addFiles(path); - - mDataLocal = mGameSettings.getDataLocal(); - - if (!mDataLocal.isEmpty()) - mSelector->addFiles(mDataLocal); - - paths.insert (0, mDataLocal); - PathIterator pathIterator (paths); - QStringList profiles = mLauncherSettings.getContentLists(); QString currentProfile = mLauncherSettings.getCurrentContentListName(); @@ -94,11 +81,27 @@ bool Launcher::DataFilesPage::loadSettings() if (!currentProfile.isEmpty()) addProfile(currentProfile, true); - mSelector->setProfileContent(filesInProfile(currentProfile, pathIterator)); - return true; } +void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName) +{ + QStringList paths = mGameSettings.getDataDirs(); + + foreach(const QString &path, paths) + mSelector->addFiles(path); + + mDataLocal = mGameSettings.getDataLocal(); + + if (!mDataLocal.isEmpty()) + mSelector->addFiles(mDataLocal); + + paths.insert(0, mDataLocal); + PathIterator pathIterator(paths); + + mSelector->setProfileContent(filesInProfile(contentModelName, pathIterator)); +} + QStringList Launcher::DataFilesPage::filesInProfile(const QString& profileName, PathIterator& pathIterator) { QStringList files = mLauncherSettings.getContentListFiles(profileName); @@ -175,7 +178,7 @@ void Launcher::DataFilesPage::setProfile (const QString &previous, const QString ui.profilesComboBox->setCurrentProfile (ui.profilesComboBox->findText (current)); - loadSettings(); + populateFileViews(current); checkForDefaultProfile(); } @@ -229,13 +232,6 @@ void Launcher::DataFilesPage::on_newProfileAction_triggered() mLauncherSettings.setCurrentContentListName(profile); addProfile(profile, true); - mSelector->clearCheckStates(); - - mSelector->setGameFile(); - - saveSettings(); - - emit signalProfileChanged (ui.profilesComboBox->findText(profile)); } void Launcher::DataFilesPage::addProfile (const QString &profile, bool setAsCurrent) @@ -262,15 +258,13 @@ void Launcher::DataFilesPage::on_deleteProfileAction_triggered() // this should work since the Default profile can't be deleted and is always index 0 int next = ui.profilesComboBox->currentIndex()-1; + + // changing the profile forces a reload of plugin file views. ui.profilesComboBox->setCurrentIndex(next); removeProfile(profile); ui.profilesComboBox->removeItem(ui.profilesComboBox->findText(profile)); - saveSettings(); - - loadSettings(); - checkForDefaultProfile(); } diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index c2fc22461..73b840c5c 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -82,6 +82,7 @@ namespace Launcher bool showDeleteMessageBox (const QString &text); void addProfile (const QString &profile, bool setAsCurrent); void checkForDefaultProfile(); + void populateFileViews(const QString& contentModelName); class PathIterator { From 697ab16ec5b3ed0502e47b71ea7aa7a883320bd8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 27 Jan 2015 19:00:26 +0100 Subject: [PATCH 303/740] Fix for coverity defects --- apps/openmw/mwdialogue/keywordsearch.hpp | 2 +- apps/openmw/mwworld/esmstore.cpp | 2 +- apps/wizard/unshield/unshieldworker.cpp | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwdialogue/keywordsearch.hpp b/apps/openmw/mwdialogue/keywordsearch.hpp index 0bb3616d9..c4e1d7553 100644 --- a/apps/openmw/mwdialogue/keywordsearch.hpp +++ b/apps/openmw/mwdialogue/keywordsearch.hpp @@ -161,7 +161,7 @@ public: while (matches.size()) { int longestKeywordSize = 0; - typename std::vector::iterator longestKeyword; + typename std::vector::iterator longestKeyword = matches.begin(); for (typename std::vector::iterator it = matches.begin(); it != matches.end(); ++it) { int size = it->mEnd - it->mBeg; diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index caa88d751..12e02f938 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -82,7 +82,7 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener) } else if (n.val == ESM::REC_SKIL) { mSkills.load (esm); } - else if (n.val==ESM::REC_FILT || ESM::REC_DBGP) + else if (n.val==ESM::REC_FILT || n.val == ESM::REC_DBGP) { // ignore project file only records esm.skipRecord(); diff --git a/apps/wizard/unshield/unshieldworker.cpp b/apps/wizard/unshield/unshieldworker.cpp index 5fa043347..11e090ed1 100644 --- a/apps/wizard/unshield/unshieldworker.cpp +++ b/apps/wizard/unshield/unshieldworker.cpp @@ -739,7 +739,8 @@ bool Wizard::UnshieldWorker::extractFile(Unshield *unshield, const QString &dest // Ensure the target path exists QDir dir; - dir.mkpath(path); + if (!dir.mkpath(path)) + return false; QString fileName(path); fileName.append(QString::fromUtf8(unshield_file_name(unshield, index))); From 62acb0373519d310799967ce7b0f556e27ddd1c4 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 27 Jan 2015 21:07:26 +0100 Subject: [PATCH 304/740] More Ogre + recent Boost build fixes --- apps/opencs/view/render/cell.hpp | 2 ++ apps/opencs/view/render/object.hpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 9f38b0d9f..73d794948 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -9,7 +9,9 @@ #include +#ifndef Q_MOC_RUN #include +#endif #include "object.hpp" diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index 05a32fbea..3ed4fa793 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -3,7 +3,9 @@ #include +#ifndef Q_MOC_RUN #include +#endif class QModelIndex; From 9b3728d87856d1c515882c8ccd6bd08e6a96e5d7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 24 Jan 2015 17:15:25 +0100 Subject: [PATCH 305/740] ESSImport: convert weather state --- apps/essimporter/converter.hpp | 63 +++++++++++++++++++++++++++++++-- apps/essimporter/importgame.cpp | 3 ++ apps/essimporter/importgame.hpp | 2 +- 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 90b75fee1..28d904d3c 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include "importcrec.hpp" #include "importcntc.hpp" @@ -455,11 +456,69 @@ public: class ConvertGAME : public Converter { public: + ConvertGAME() : mHasGame(false) {} + + std::string toString(int weatherId) + { + switch (weatherId) + { + case 0: + return "clear"; + case 1: + return "cloudy"; + case 2: + return "foggy"; + case 3: + return "overcast"; + case 4: + return "rain"; + case 5: + return "thunderstorm"; + case 6: + return "ashstorm"; + case 7: + return "blight"; + case 8: + return "snow"; + case 9: + return "blizzard"; + case -1: + return ""; + default: + { + std::stringstream error; + error << "unknown weather id: " << weatherId; + throw std::runtime_error(error.str()); + } + } + } + virtual void read(ESM::ESMReader &esm) { - GAME game; - game.load(esm); + mGame.load(esm); + mHasGame = true; } + + virtual void write(ESM::ESMWriter &esm) + { + if (!mHasGame) + return; + esm.startRecord(ESM::REC_WTHR); + ESM::WeatherState weather; + weather.mCurrentWeather = toString(mGame.mGMDT.mCurrentWeather); + weather.mNextWeather = toString(mGame.mGMDT.mNextWeather); + weather.mRemainingTransitionTime = mGame.mGMDT.mWeatherTransition/100.f*(0.015*24*3600); + weather.mHour = mContext->mHour; + weather.mWindSpeed = 0.f; + weather.mTimePassed = 0.0; + weather.mFirstUpdate = false; + weather.save(esm); + esm.endRecord(ESM::REC_WTHR); + } + +private: + bool mHasGame; + GAME mGame; }; /// Running global script diff --git a/apps/essimporter/importgame.cpp b/apps/essimporter/importgame.cpp index 0b3a4f1a7..c9da71e0c 100644 --- a/apps/essimporter/importgame.cpp +++ b/apps/essimporter/importgame.cpp @@ -8,6 +8,9 @@ namespace ESSImport void GAME::load(ESM::ESMReader &esm) { esm.getHNT(mGMDT, "GMDT"); + mGMDT.mWeatherTransition &= (0x000000ff); + mGMDT.mSecundaPhase &= (0x000000ff); + mGMDT.mMasserPhase &= (0x000000ff); } } diff --git a/apps/essimporter/importgame.hpp b/apps/essimporter/importgame.hpp index 7bb814320..fca7d72a0 100644 --- a/apps/essimporter/importgame.hpp +++ b/apps/essimporter/importgame.hpp @@ -20,7 +20,7 @@ namespace ESSImport int mCurrentWeather, mNextWeather; int mWeatherTransition; // 0-100 transition between weathers, top 3 bytes may be garbage float mTimeOfNextTransition; // weather changes when gamehour == timeOfNextTransition - int masserPhase, secundaPhase; // top 3 bytes may be garbage + int mMasserPhase, mSecundaPhase; // top 3 bytes may be garbage }; GMDT mGMDT; From 60f722b0a9bca552475e2d721c23287e5457994a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 24 Jan 2015 17:28:05 +0100 Subject: [PATCH 306/740] Treat the first mouse motion event as non-relative This fixes incorrect starting camera orientation when using --skip-menu or --load-savegame. --- extern/sdl4ogre/sdlinputwrapper.cpp | 10 +++++++++- extern/sdl4ogre/sdlinputwrapper.hpp | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index 0c29be939..a6c7d3e5c 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -30,7 +30,8 @@ namespace SFO mWantMouseVisible(false), mAllowGrab(grab), mWarpX(0), - mWarpY(0) + mWarpY(0), + mFirstMouseMove(true) { _setupOISKeys(); } @@ -316,6 +317,13 @@ namespace SFO pack_evt.y = mMouseY = evt.motion.y; pack_evt.xrel = evt.motion.xrel; pack_evt.yrel = evt.motion.yrel; + if (mFirstMouseMove) + { + // first event should be treated as non-relative, since there's no point of reference + // SDL then (incorrectly) uses (0,0) as point of reference, on Linux at least... + pack_evt.xrel = pack_evt.yrel = 0; + mFirstMouseMove = false; + } } else if(evt.type == SDL_MOUSEWHEEL) { diff --git a/extern/sdl4ogre/sdlinputwrapper.hpp b/extern/sdl4ogre/sdlinputwrapper.hpp index 339e99de1..af16ab68d 100644 --- a/extern/sdl4ogre/sdlinputwrapper.hpp +++ b/extern/sdl4ogre/sdlinputwrapper.hpp @@ -71,6 +71,8 @@ namespace SFO bool mGrabPointer; bool mMouseRelative; + bool mFirstMouseMove; + Sint32 mMouseZ; Sint32 mMouseX; Sint32 mMouseY; From 4921c6ef9eb5b0ee52097cd6bca40b3a0634d391 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 24 Jan 2015 19:26:31 +0100 Subject: [PATCH 307/740] Split window caption bars so that the caption can be transparent (Fixes #531) Fix transparent window background not applying to the header bar (Fixes #2294) --- apps/openmw/mwgui/container.cpp | 2 - apps/openmw/mwgui/statswindow.cpp | 1 - apps/openmw/mwgui/tradewindow.cpp | 2 - components/CMakeLists.txt | 2 +- components/widgets/widgets.cpp | 2 + components/widgets/windowcaption.cpp | 58 ++++++++++++++++++++++++++++ components/widgets/windowcaption.hpp | 32 +++++++++++++++ files/mygui/openmw_hud_box.skin.xml | 16 ++++---- files/mygui/openmw_windows.skin.xml | 37 ++++++------------ libs/openengine/gui/layout.cpp | 22 ----------- libs/openengine/gui/layout.hpp | 4 -- 11 files changed, 112 insertions(+), 66 deletions(-) create mode 100644 components/widgets/windowcaption.cpp create mode 100644 components/widgets/windowcaption.hpp diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 49e641aed..53b1e679a 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -154,8 +154,6 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCloseButton); - // Careful here. setTitle may cause size updates, causing itemview redraw, so make sure to do it last - // or we end up using a possibly invalid model. setTitle(container.getClass().getName(container)); } diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index 19f9c749c..a407aedc7 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -108,7 +108,6 @@ namespace MWGui void StatsWindow::setPlayerName(const std::string& playerName) { mMainWidget->castType()->setCaption(playerName); - adjustWindowCaption(); } void StatsWindow::setValue (const std::string& id, const MWMechanics::AttributeValue& value) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index bafa89d5b..fab7c63a6 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -133,8 +133,6 @@ namespace MWGui updateLabels(); - // Careful here. setTitle may cause size updates, causing itemview redraw, so make sure to do it last - // or we end up using a possibly invalid model. setTitle(actor.getClass().getName(actor)); onFilterChanged(mFilterAll); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a0500127c..2126c5ca5 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -113,7 +113,7 @@ add_component_dir (ogreinit ) add_component_dir (widgets - box imagebutton tags list numericeditbox sharedstatebutton widgets + box imagebutton tags list numericeditbox sharedstatebutton windowcaption widgets ) add_component_dir (fontloader diff --git a/components/widgets/widgets.cpp b/components/widgets/widgets.cpp index 82839c6c9..3b6361cf8 100644 --- a/components/widgets/widgets.cpp +++ b/components/widgets/widgets.cpp @@ -7,6 +7,7 @@ #include "box.hpp" #include "imagebutton.hpp" #include "sharedstatebutton.hpp" +#include "windowcaption.hpp" namespace Gui { @@ -22,6 +23,7 @@ namespace Gui MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); } } diff --git a/components/widgets/windowcaption.cpp b/components/widgets/windowcaption.cpp new file mode 100644 index 000000000..bcb0a7c12 --- /dev/null +++ b/components/widgets/windowcaption.cpp @@ -0,0 +1,58 @@ +#include "windowcaption.hpp" + +#include + +namespace Gui +{ + + WindowCaption::WindowCaption() + : mLeft(NULL) + , mRight(NULL) + { + } + + void WindowCaption::initialiseOverride() + { + Base::initialiseOverride(); + + assignWidget(mLeft, "Left"); + assignWidget(mRight, "Right"); + + assignWidget(mClient, "Client"); + if (!mClient) + throw std::runtime_error("WindowCaption needs an EditBox Client widget in its skin"); + } + + void WindowCaption::setCaption(const MyGUI::UString &_value) + { + EditBox::setCaption(_value); + align(); + } + + void WindowCaption::setSize(const MyGUI::IntSize& _value) + { + Base::setSize(_value); + align(); + } + + void WindowCaption::setCoord(const MyGUI::IntCoord& _value) + { + Base::setCoord(_value); + align(); + } + + void WindowCaption::align() + { + MyGUI::IntSize textSize = getTextSize(); + MyGUI::Widget* caption = mClient; + caption->setSize(textSize.width + 24, caption->getHeight()); + + int barwidth = (getWidth()-caption->getWidth())/2; + caption->setPosition(barwidth, caption->getTop()); + if (mLeft) + mLeft->setCoord(0, mLeft->getTop(), barwidth, mLeft->getHeight()); + if (mRight) + mRight->setCoord(barwidth + caption->getWidth(), mRight->getTop(), barwidth, mRight->getHeight()); + } + +} diff --git a/components/widgets/windowcaption.hpp b/components/widgets/windowcaption.hpp new file mode 100644 index 000000000..bdd4c0a2e --- /dev/null +++ b/components/widgets/windowcaption.hpp @@ -0,0 +1,32 @@ +#ifndef OPENMW_WIDGETS_WINDOWCAPTION_H +#define OPENMW_WIDGETS_WINDOWCAPTION_H + +#include + +namespace Gui +{ + + /// Window caption that automatically adjusts "Left" and "Right" widgets in its skin + /// based on the text size of the caption in the middle + class WindowCaption : public MyGUI::EditBox + { + MYGUI_RTTI_DERIVED(WindowCaption) + public: + WindowCaption(); + + virtual void setCaption(const MyGUI::UString &_value); + virtual void initialiseOverride(); + + virtual void setSize(const MyGUI::IntSize& _value); + virtual void setCoord(const MyGUI::IntCoord& _value); + + private: + MyGUI::Widget* mLeft; + MyGUI::Widget* mRight; + + void align(); + }; + +} + +#endif diff --git a/files/mygui/openmw_hud_box.skin.xml b/files/mygui/openmw_hud_box.skin.xml index e7457e7d2..4e6349768 100644 --- a/files/mygui/openmw_hud_box.skin.xml +++ b/files/mygui/openmw_hud_box.skin.xml @@ -6,13 +6,13 @@ - + - + - + - + @@ -22,13 +22,13 @@ - + - + - + - + diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index d01bd8ef2..57d50fe74 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -395,17 +395,9 @@ - - - - - - - - - - - + + + @@ -538,12 +531,7 @@ - - - - - - + @@ -695,7 +684,8 @@ - + + @@ -814,12 +804,7 @@ - - - - - - + - + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index ebbc77bef..2854401c8 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -804,7 +804,7 @@ - +
+
diff --git a/files/mygui/openmw_trainingwindow.layout b/files/mygui/openmw_trainingwindow.layout index c58bd0ab3..d6cea8727 100644 --- a/files/mygui/openmw_trainingwindow.layout +++ b/files/mygui/openmw_trainingwindow.layout @@ -1,26 +1,22 @@ - + + + + - - - - - + + - - - - - + - + diff --git a/files/mygui/openmw_travel_window.layout b/files/mygui/openmw_travel_window.layout index 30b470e08..4b383ee7c 100644 --- a/files/mygui/openmw_travel_window.layout +++ b/files/mygui/openmw_travel_window.layout @@ -1,31 +1,28 @@ - + + + - - - + + - - - - + - - - + + + - - - + + - + From 0557d45bd156844772a5be5cdc602cdf22781eb5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 3 Feb 2015 13:18:03 +0100 Subject: [PATCH 373/740] renamed opencs into openmw-cs --- CMakeLists.txt | 14 +++++++------- apps/opencs/CMakeLists.txt | 14 +++++++------- apps/opencs/editor.cpp | 4 ++-- apps/opencs/main.cpp | 2 +- files/mac/{opencs.icns => openmw-cs.icns} | Bin files/opencs/{opencs.png => openmw-cs.png} | Bin files/opencs/resources.qrc | 2 +- files/{opencs.desktop => openmw-cs.desktop} | 6 +++--- files/windows/opencs.rc | 2 +- files/windows/{opencs.ico => openmw-cs.ico} | Bin 10 files changed, 22 insertions(+), 22 deletions(-) rename files/mac/{opencs.icns => openmw-cs.icns} (100%) rename files/opencs/{opencs.png => openmw-cs.png} (100%) rename files/{opencs.desktop => openmw-cs.desktop} (83%) rename files/windows/{opencs.ico => openmw-cs.ico} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index f31603460..019d53c4e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -373,8 +373,8 @@ if (NOT WIN32 AND NOT APPLE) "${OpenMW_BINARY_DIR}/openmw.desktop") configure_file(${OpenMW_SOURCE_DIR}/files/openmw-mimeinfo.xml "${OpenMW_BINARY_DIR}/openmw-mimeinfo.xml") - configure_file(${OpenMW_SOURCE_DIR}/files/opencs.desktop - "${OpenMW_BINARY_DIR}/opencs.desktop") + configure_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.desktop + "${OpenMW_BINARY_DIR}/openmw-cs.desktop") endif() # Compiler settings @@ -423,7 +423,7 @@ IF(NOT WIN32 AND NOT APPLE) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-essimporter" DESTINATION "${BINDIR}" ) ENDIF(BUILD_ESSIMPORTER) IF(BUILD_OPENCS) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/opencs" DESTINATION "${BINDIR}" ) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-cs" DESTINATION "${BINDIR}" ) ENDIF(BUILD_OPENCS) IF(BUILD_NIFTEST) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/niftest" DESTINATION "${BINDIR}" ) @@ -444,8 +444,8 @@ IF(NOT WIN32 AND NOT APPLE) INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-mimeinfo.xml" DESTINATION "${DATAROOTDIR}/mime/packages" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.png" DESTINATION "${ICONDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") IF(BUILD_OPENCS) - INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.desktop" DESTINATION "${DATAROOTDIR}/applications" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs") - INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/opencs/opencs.png" DESTINATION "${ICONDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs") + INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.desktop" DESTINATION "${DATAROOTDIR}/applications" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs") + INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/opencs/openmw-cs.png" DESTINATION "${ICONDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs") ENDIF(BUILD_OPENCS) # Install global configuration files @@ -485,7 +485,7 @@ if(WIN32) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-essimporter.exe" DESTINATION ".") ENDIF(BUILD_ESSIMPORTER) IF(BUILD_OPENCS) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/opencs.exe" DESTINATION ".") + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-cs.exe" DESTINATION ".") INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION ".") ENDIF(BUILD_OPENCS) IF(BUILD_WIZARD) @@ -509,7 +509,7 @@ if(WIN32) SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};openmw-launcher;OpenMW Launcher") ENDIF(BUILD_LAUNCHER) IF(BUILD_OPENCS) - SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};opencs;OpenMW Construction Set") + SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};openmw-cs;OpenMW Construction Set") ENDIF(BUILD_OPENCS) IF(BUILD_WIZARD) SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};openmw-wizard;OpenMW Wizard") diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 468e172cd..be30431df 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -146,7 +146,7 @@ set (OPENCS_UI ${CMAKE_SOURCE_DIR}/files/ui/filedialog.ui ) -source_group (opencs FILES ${OPENCS_SRC} ${OPENCS_HDR}) +source_group (openmw-cs FILES ${OPENCS_SRC} ${OPENCS_HDR}) if(WIN32) set(QT_USE_QTMAIN TRUE) @@ -169,12 +169,12 @@ qt4_add_resources(OPENCS_RES_SRC ${OPENCS_RES}) include_directories(${CMAKE_CURRENT_BINARY_DIR} ${BULLET_INCLUDE_DIRS}) if(APPLE) - set (OPENCS_MAC_ICON ${CMAKE_SOURCE_DIR}/files/mac/opencs.icns) + set (OPENCS_MAC_ICON ${CMAKE_SOURCE_DIR}/files/mac/openmw-cs.icns) else() set (OPENCS_MAC_ICON "") endif(APPLE) -add_executable(opencs +add_executable(openmw-cs MACOSX_BUNDLE ${OENGINE_BULLET} ${OPENCS_SRC} @@ -187,8 +187,8 @@ add_executable(opencs if(APPLE) set_target_properties(opencs PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}" - OUTPUT_NAME "OpenCS" - MACOSX_BUNDLE_ICON_FILE "opencs.icns" + OUTPUT_NAME "OpenMW-CS" + MACOSX_BUNDLE_ICON_FILE "openmw-cs.icns" MACOSX_BUNDLE_BUNDLE_NAME "OpenCS" MACOSX_BUNDLE_GUI_IDENTIFIER "org.openmw.opencs" MACOSX_BUNDLE_SHORT_VERSION_STRING ${OPENMW_VERSION} @@ -199,7 +199,7 @@ if(APPLE) MACOSX_PACKAGE_LOCATION Resources) endif(APPLE) -target_link_libraries(opencs +target_link_libraries(openmw-cs ${OGRE_LIBRARIES} ${OGRE_Overlay_LIBRARIES} ${OGRE_STATIC_PLUGINS} @@ -211,5 +211,5 @@ target_link_libraries(opencs ) if(APPLE) - INSTALL(TARGETS opencs BUNDLE DESTINATION OpenMW COMPONENT BUNDLE) + INSTALL(TARGETS opencs BUNDLE DESTINATION OpenMW-CS COMPONENT BUNDLE) endif() diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 58614ec5f..1d31c8396 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -96,7 +96,7 @@ void CS::Editor::setupDataFiles (const Files::PathContainer& dataDirs) std::pair > CS::Editor::readConfig() { boost::program_options::variables_map variables; - boost::program_options::options_description desc("Syntax: opencs \nAllowed options"); + boost::program_options::options_description desc("Syntax: openmw-cs \nAllowed options"); desc.add_options() ("data", boost::program_options::value()->default_value(Files::PathContainer(), "data")->multitoken()->composing()) @@ -249,7 +249,7 @@ bool CS::Editor::makeIPCServer() try { mPid = boost::filesystem::temp_directory_path(); - mPid /= "opencs.pid"; + mPid /= "openmw-cs.pid"; bool pidExists = boost::filesystem::exists(mPid); mPidFile.open(mPid); diff --git a/apps/opencs/main.cpp b/apps/opencs/main.cpp index 0b8da61ef..b11561c13 100644 --- a/apps/opencs/main.cpp +++ b/apps/opencs/main.cpp @@ -78,7 +78,7 @@ int main(int argc, char *argv[]) application.setLibraryPaths(libraryPaths); #endif - application.setWindowIcon (QIcon (":./opencs.png")); + application.setWindowIcon (QIcon (":./openmw-cs.png")); CS::Editor editor (ogreInit); diff --git a/files/mac/opencs.icns b/files/mac/openmw-cs.icns similarity index 100% rename from files/mac/opencs.icns rename to files/mac/openmw-cs.icns diff --git a/files/opencs/opencs.png b/files/opencs/openmw-cs.png similarity index 100% rename from files/opencs/opencs.png rename to files/opencs/openmw-cs.png diff --git a/files/opencs/resources.qrc b/files/opencs/resources.qrc index 0cc6996a8..1bcd3ab4f 100644 --- a/files/opencs/resources.qrc +++ b/files/opencs/resources.qrc @@ -1,6 +1,6 @@ - opencs.png + openmw-cs.png activator.png added.png apparatus.png diff --git a/files/opencs.desktop b/files/openmw-cs.desktop similarity index 83% rename from files/opencs.desktop rename to files/openmw-cs.desktop index 638de6ebf..a5e3c27f2 100644 --- a/files/opencs.desktop +++ b/files/openmw-cs.desktop @@ -4,7 +4,7 @@ Name=OpenMW Content Editor GenericName=Content Editor Comment=A replacement for the Morrowind Construction Set. Keywords=Morrowind;Construction Set;Creation Kit Editor;Set;Kit; -TryExec=opencs -Exec=opencs -Icon=opencs +TryExec=openmw-cs +Exec=openmw-cs +Icon=openmw-cs Categories=Game;RolePlaying; diff --git a/files/windows/opencs.rc b/files/windows/opencs.rc index 8839f1861..3ae18dddd 100644 --- a/files/windows/opencs.rc +++ b/files/windows/opencs.rc @@ -1 +1 @@ -IDI_ICON1 ICON DISCARDABLE "opencs.ico" +IDI_ICON1 ICON DISCARDABLE "openmw-cs.ico" diff --git a/files/windows/opencs.ico b/files/windows/openmw-cs.ico similarity index 100% rename from files/windows/opencs.ico rename to files/windows/openmw-cs.ico From c02537c3b16c55fb889824595eb4bc9912f578f2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 3 Feb 2015 13:42:47 +0100 Subject: [PATCH 374/740] incremented version number --- CMakeLists.txt | 2 +- README.md | 44 ++++++++++++++++++++++---------------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 019d53c4e..8fe213b49 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/) message(STATUS "Configuring OpenMW...") set(OPENMW_VERSION_MAJOR 0) -set(OPENMW_VERSION_MINOR 34) +set(OPENMW_VERSION_MINOR 35) set(OPENMW_VERSION_RELEASE 0) set(OPENMW_VERSION_COMMITHASH "") diff --git a/README.md b/README.md index e17784752..1698a7ebc 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ OpenMW OpenMW is an attempt at recreating the engine for the popular role-playing game Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work. -* Version: 0.34.0 +* Version: 0.35.0 * License: GPL (see docs/license/GPL3.txt for more information) * Website: http://www.openmw.org * IRC: #openmw on irc.freenode.net @@ -39,26 +39,26 @@ Command line options --version print version information and quit --data arg (=data) set data directories (later directories have higher priority) - --data-local arg set local data directory (highest + --data-local arg set local data directory (highest priority) --fallback-archive arg (=fallback-archive) - set fallback BSA archives (later + set fallback BSA archives (later archives have higher priority) --resources arg (=resources) set resources directory --start arg set initial cell - --content arg content file(s): esm/esp, or + --content arg content file(s): esm/esp, or omwgame/omwaddon --no-sound [=arg(=1)] (=0) disable all sounds --script-verbose [=arg(=1)] (=0) verbose script output --script-all [=arg(=1)] (=0) compile all scripts (excluding dialogue scripts) at startup --script-all-dialogue [=arg(=1)] (=0) compile all dialogue scripts at startup - --script-console [=arg(=1)] (=0) enable console-only script + --script-console [=arg(=1)] (=0) enable console-only script functionality - --script-run arg select a file containing a list of - console commands that is executed on + --script-run arg select a file containing a list of + console commands that is executed on startup - --script-warn [=arg(=1)] (=1) handling of warnings when compiling + --script-warn [=arg(=1)] (=1) handling of warnings when compiling scripts 0 - ignore warning 1 - show warning but consider script as @@ -70,27 +70,27 @@ Command line options enable script blacklisting --load-savegame arg load a save game file on game startup --skip-menu [=arg(=1)] (=0) skip main menu on game startup - --new-game [=arg(=1)] (=0) run new game sequence (ignored if + --new-game [=arg(=1)] (=0) run new game sequence (ignored if skip-menu=0) - --fs-strict [=arg(=1)] (=0) strict file system handling (no case + --fs-strict [=arg(=1)] (=0) strict file system handling (no case folding) - --encoding arg (=win1252) Character encoding used in OpenMW game + --encoding arg (=win1252) Character encoding used in OpenMW game messages: - - win1250 - Central and Eastern European - such as Polish, Czech, Slovak, - Hungarian, Slovene, Bosnian, Croatian, - Serbian (Latin script), Romanian and + + win1250 - Central and Eastern European + such as Polish, Czech, Slovak, + Hungarian, Slovene, Bosnian, Croatian, + Serbian (Latin script), Romanian and Albanian languages - - win1251 - Cyrillic alphabet such as - Russian, Bulgarian, Serbian Cyrillic + + win1251 - Cyrillic alphabet such as + Russian, Bulgarian, Serbian Cyrillic and other languages - - win1252 - Western European (Latin) + + win1252 - Western European (Latin) alphabet, used by default --fallback arg fallback values --no-grab Don't grab mouse cursor - --export-fonts [=arg(=1)] (=0) Export Morrowind .fnt fonts to PNG + --export-fonts [=arg(=1)] (=0) Export Morrowind .fnt fonts to PNG image and XML file in current directory --activate-dist arg (=-1) activation distance override From 0b7b62744368a42a32f889ef6408dd1bdd283b04 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Feb 2015 13:57:40 +0100 Subject: [PATCH 375/740] CMake fix for opencs rename --- apps/opencs/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index be30431df..e713c65bc 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -185,7 +185,7 @@ add_executable(openmw-cs ) if(APPLE) - set_target_properties(opencs PROPERTIES + set_target_properties(openmw-cs PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}" OUTPUT_NAME "OpenMW-CS" MACOSX_BUNDLE_ICON_FILE "openmw-cs.icns" @@ -211,5 +211,5 @@ target_link_libraries(openmw-cs ) if(APPLE) - INSTALL(TARGETS opencs BUNDLE DESTINATION OpenMW-CS COMPONENT BUNDLE) + INSTALL(TARGETS openmw-cs BUNDLE DESTINATION OpenMW-CS COMPONENT BUNDLE) endif() From 9cfaffc7cc6db0e68f90c606ea3b07caa002a1d8 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 3 Feb 2015 14:12:30 +0100 Subject: [PATCH 376/740] updated changelog --- CHANGELOG.md | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 750cb5476..c2aa03dc2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,127 @@ +0.35.0 +------ + + Bug #244: Clipping/static in relation to the ghostgate/fence sound. + Bug #531: Missing transparent menu items + Bug #811: Content Lists in openmw.cfg are overwritten + Bug #925: OpenCS doesn't launch because it thinks its already started + Bug #969: Water shader strange behaviour on AMD card + Bug #1049: Partially highlighted word in dialogue may cause incorrect line break + Bug #1069: omwlauncher.exe crashes due to file lock + Bug #1192: It is possible to jump on top of hostile creatures in combat + Bug #1342: Loud ambient sounds + Bug #1431: Creatures can climb the player + Bug #1605: Guard in CharGen doesn't turn around to face you when reaching stairs + Bug #1624: Moon edges don't transition properly + Bug #1634: Items dropped by PC have collision + Bug #1637: Weird NPC behaviour in Vivec, Hlaalu Ancestral Vaults? + Bug #1638: Cannot climb staircases + Bug #1648: Enchanted equipment badly handled at game reload + Bug #1663: Crash when casting spell at enemy near you + Bug #1683: Scale doesn't apply to animated collision nodes + Bug #1702: Active enchanted item forgotten + Bug #1730: Scripts names starting with digit(s) fail to compile + Bug #1743: Moons are transparent + Bug #1745: Shadows crash: Assertion `mEffects.empty()' failed. + Bug #1785: Can't equip two-handed weapon and shield + Bug #1809: Player falls too easily + Bug #1825: Sword of Perithia can´t run in OpenMW + Bug #1899: The launcher resets any alterations you´ve made in the mod list order, + Bug #1964: Idle voices/dialogs not triggered correctly + Bug #1980: Please, change default click behavior in OpenMW Launchers Data Files list + Bug #1984: Vampire corpses standing up when looting the first item + Bug #1985: Calm spell does nothing + Bug #1986: Spell name lights up on mouseover but spell cost does not + Bug #1989: Tooltip still shown when menu toggled off + Bug #2010: Raindrops Displayed While Underwater + Bug #2023: Walking into plants causes massive framedrop + Bug #2031: [MOD: Shrines - Restore Health and Cancel Options]: Restore health option doesn't work + Bug #2039: Lake Fjalding pillar of fire not rendered + Bug #2040: AI_follow should stop further from the target + Bug #2076: Slaughterfish AI + Bug #2077: Direction of long jump can be changed much more than it is possible in vanilla + Bug #2078: error during rendering: Object '' not found (const) + Bug #2105: Lockpicking causes screen sync glitch + Bug #2113: [MOD: Julan Ashlander Companion] Julan does not act correctly within the Ghostfence. + Bug #2123: Window glow mod: Collision issues + Bug #2133: Missing collision for bridges in Balmora when using Morrowind Rebirth 2.81 + Bug #2135: Casting a summon spell while the summon is active does not reset the summon. + Bug #2144: Changing equipment will unequip drawn arrows/bolts + Bug #2169: Yellow on faces when using opengl renderer and mods from overhaul on windows + Bug #2175: Pathgrid mods do not overwrite the existing pathgrid + Bug #2176: Morrowind -Russian localization end add-on ChaosHeart. Error in framelistener;object ;frenzying toush; not found + Bug #2181: Mod Morrowind crafting merchants die. + Bug #2182: mods changing skill progression double the bonus for class specialization + Bug #2183: Editor: Skills "use value" only allows integer between 0 and 99 + Bug #2184: Animated Morrowind Expanded produces an error on Open MW Launch + Bug #2185: Conditional Operator formats + Bug #2193: Quest: Gateway Ghost + Bug #2194: Cannot summon multiples of the same creature + Bug #2195: Pathgrid in the (0,0) exterior cell not loaded + Bug #2200: Outdoor NPCs can stray away and keep walking into a wall + Bug #2201: Creatures do not receive fall damage + Bug #2202: The enchantment the item can hold is calculated incorrectly + Bug #2203: Having the mod Living Cities of Vvardenfall running causes the game world to fail to load after leaving the prison ship + Bug #2204: Abot's Water Life - Book rendered incorrectly + Bug #2205: sound_waterfall script no longer compiles + Bug #2206: Dialogue script fails to compile (extra .) + Bug #2207: Script using – instead of - character does not compile + Bug #2208: Failing dialogue scripts in french Morrowind.esm + Bug #2214: LGNPC Vivec Redoran 1.62 and The King Rat (Size and inventory Issues) + Bug #2215: Beast races can use enchanted boots + Bug #2218: Incorrect names body parts in 3D models for open helmet with skinning + Bug #2219: Orcs in Ghorak Manor in Caldera don't attack if you pick their pockets. + Bug #2220: Chargen race preview head incorrect orientation + Bug #2223: Reseting rock falling animation + Bug #2224: Fortify Attribute effects do not stack when Spellmaking. + Bug #2226: OpenCS pseudo-crash + Bug #2230: segfaulting when entering Ald'ruhn with a specific mod: "fermeture la nuit" (closed by night) + Bug #2233: Area effect spells on touch do not have the area effect + Bug #2234: Dwarven Crossbow clips through the ground when dropped + Bug #2235: class SettingsBase<> reverses the order of entries with multiple keys. + Bug #2236: Weird two handed longsword + torch interaction + Bug #2237: Shooting arrows while sneaking do not agro + Bug #2238: Bipedal creatures not using weapons are not handled properly + Bug #2245: Incorrect topic highlighting in HT_SpyBaladas quest + Bug #2252: Tab completion incomplete for places using COC from the console. + Bug #2255: Camera reverts to first person on load + Bug #2259: enhancement: the save/load progress bar is not very progressive + Bug #2263: TogglePOV can not be bound to Alt key + Bug #2267: dialogue disabling via mod + Bug #2268: Highlighting Files with load order problems in Data Files tab of Launcher + Bug #2276: [Mod]ShotN issues with Karthwasten + Bug #2283: Count argument for PlaceAt functions not working + Bug #2284: Local map notes should be visible on door marker leading to the cell with the note + Bug #2293: There is a graphical glitch at the end of the spell's animation in 3rd Person (looking over the shoulder) view + Bug #2294: When using Skyrim UI Overhaul, the tops of pinnable menus are invisible + Bug #2302: Random leveled items repeat way too often in a single dungeon + Bug #2306: Enchanted arrows should not be retrievable from corpses + Bug #2308: No sound effect when drawing the next throwing knife + Bug #2309: Guards chase see the player character even if they're invisible + Bug #2319: Inverted controls and other issues after becoming a vampire + Bug #2324: Spells cast when crossing cell border are imprinted on the local map + Bug #2330: Actors with Drain Health effect retain health after dying + Bug #2331: tgm (god mode) won't allow the player to cast spells if the player doesn't have enough mana + Bug #2332: Error in framelistener: Need a skeleton to attach the arrow to + Feature #114: ess-Importer + Feature #504: Editor: Delete selected rows from result windows + Feature #1024: Addition of remaining equipping hotkeys + Feature #1067: Handle NIF interpolation type 4 (XYZ_ROTATION_KEY) + Feature #1125: AI fast-forward + Feature #1228: Drowning while knocked out + Feature #1325: Editor: Opening window and User Settings window cleanup + Feature #1537: Ability to change the grid size from 3x3 to 5x5 (or more with good pc) + Feature #1546: Leveled list script functions + Feature #1659: Test dialogue scripts in --script-all + Feature #1720: NPC lookAt controller + Feature #2178: Load initial particle system state from NIF files + Feature #2197: Editor: When clicking on a script error in the report window set cursor in script editor to the respective line/column + Feature #2261: Warn when loading save games with mod mismatch + Feature #2313: ess-Importer: convert global map exploration overlay + Feature #2318: Add commandline option to load a save game + Task #810: Rename "profile" to "content list" + Task #2196: Label local/global openmw.cfg files via comments + 0.34.0 ------ From 42363191a41a30833247fbfe9eba634e8f035a3a Mon Sep 17 00:00:00 2001 From: Lazaroth Date: Tue, 3 Feb 2015 15:25:36 +0100 Subject: [PATCH 377/740] Layout tweaks --- files/mygui/openmw_enchanting_dialog.layout | 2 -- files/mygui/openmw_merchantrepair.layout | 20 ++++++++------- files/mygui/openmw_persuasion_dialog.layout | 14 +++++------ files/mygui/openmw_spell_buying_window.layout | 22 ++++++++-------- .../mygui/openmw_spellcreation_dialog.layout | 14 ++++------- files/mygui/openmw_trade_window.layout | 5 ++-- files/mygui/openmw_trainingwindow.layout | 20 +++++++++------ files/mygui/openmw_travel_window.layout | 25 ++++++++++--------- 8 files changed, 62 insertions(+), 60 deletions(-) diff --git a/files/mygui/openmw_enchanting_dialog.layout b/files/mygui/openmw_enchanting_dialog.layout index ed62c8dc6..b90fc7a77 100644 --- a/files/mygui/openmw_enchanting_dialog.layout +++ b/files/mygui/openmw_enchanting_dialog.layout @@ -141,8 +141,6 @@ - - diff --git a/files/mygui/openmw_merchantrepair.layout b/files/mygui/openmw_merchantrepair.layout index da7f37fe7..23ab6008f 100644 --- a/files/mygui/openmw_merchantrepair.layout +++ b/files/mygui/openmw_merchantrepair.layout @@ -1,26 +1,28 @@ - + - - - + + + + + - - - + + + - + - + diff --git a/files/mygui/openmw_persuasion_dialog.layout b/files/mygui/openmw_persuasion_dialog.layout index 87851b479..6fb298914 100644 --- a/files/mygui/openmw_persuasion_dialog.layout +++ b/files/mygui/openmw_persuasion_dialog.layout @@ -1,17 +1,13 @@ - + - + - - - - @@ -39,7 +35,11 @@ - + + + + + diff --git a/files/mygui/openmw_spell_buying_window.layout b/files/mygui/openmw_spell_buying_window.layout index 73820c3d4..0350f1e27 100644 --- a/files/mygui/openmw_spell_buying_window.layout +++ b/files/mygui/openmw_spell_buying_window.layout @@ -1,26 +1,28 @@ - + - - - + + + + + - - - + + + - - + + - + diff --git a/files/mygui/openmw_spellcreation_dialog.layout b/files/mygui/openmw_spellcreation_dialog.layout index 90b95b2f4..11197bf2a 100644 --- a/files/mygui/openmw_spellcreation_dialog.layout +++ b/files/mygui/openmw_spellcreation_dialog.layout @@ -1,10 +1,9 @@ - + - @@ -16,9 +15,7 @@ - - - + @@ -33,7 +30,6 @@ - @@ -46,7 +42,6 @@ - @@ -70,7 +65,7 @@ - + @@ -83,8 +78,9 @@ + + - diff --git a/files/mygui/openmw_trade_window.layout b/files/mygui/openmw_trade_window.layout index 8668243cc..b2017661b 100644 --- a/files/mygui/openmw_trade_window.layout +++ b/files/mygui/openmw_trade_window.layout @@ -29,10 +29,10 @@ - + - + @@ -63,7 +63,6 @@ - diff --git a/files/mygui/openmw_trainingwindow.layout b/files/mygui/openmw_trainingwindow.layout index d6cea8727..c58bd0ab3 100644 --- a/files/mygui/openmw_trainingwindow.layout +++ b/files/mygui/openmw_trainingwindow.layout @@ -1,22 +1,26 @@ - - - - + - + + + + + - - + + + + + - + diff --git a/files/mygui/openmw_travel_window.layout b/files/mygui/openmw_travel_window.layout index 4b383ee7c..3603f7dcb 100644 --- a/files/mygui/openmw_travel_window.layout +++ b/files/mygui/openmw_travel_window.layout @@ -1,28 +1,29 @@ - + - - - - + + + + + + - - - - + + + - - + + - + From abb334bc1e0e77ed142afda1e6f003f7def6995d Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 3 Feb 2015 22:43:15 +0100 Subject: [PATCH 378/740] Missing change for the tool rename --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8fe213b49..b5cd54bab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -714,7 +714,7 @@ if (WIN32) if (BUILD_OPENCS) # QT triggers an informational warning that the object layout may differ when compiled with /vd2 set(OPENCS_WARNINGS "${WARNINGS} ${MT_BUILD} /wd4435") - set_target_properties(opencs PROPERTIES COMPILE_FLAGS ${OPENCS_WARNINGS}) + set_target_properties(openmw-cs PROPERTIES COMPILE_FLAGS ${OPENCS_WARNINGS}) endif (BUILD_OPENCS) if (BUILD_MWINIIMPORTER) set_target_properties(openmw-iniimporter PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") From 14923f3e8bf0fb07c2ee05e0c048e412fb9f91ab Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Feb 2015 23:05:06 +0100 Subject: [PATCH 379/740] Fix for broken unsetRefNum --- apps/openmw/mwworld/cellref.cpp | 6 +++--- apps/openmw/mwworld/cellref.hpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index 744e0e27a..d2cced3b8 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -5,19 +5,19 @@ namespace MWWorld { - ESM::RefNum CellRef::getRefNum() const + const ESM::RefNum& CellRef::getRefNum() const { return mCellRef.mRefNum; } bool CellRef::hasContentFile() const { - return getRefNum().hasContentFile(); + return mCellRef.mRefNum.hasContentFile(); } void CellRef::unsetRefNum() { - getRefNum().unset(); + mCellRef.mRefNum.unset(); } std::string CellRef::getRefId() const diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index 054fd7fc6..f063b2727 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -23,7 +23,7 @@ namespace MWWorld } // Note: Currently unused for items in containers - ESM::RefNum getRefNum() const; + const ESM::RefNum& getRefNum() const; // Set RefNum to its default state. void unsetRefNum(); From fbb8998184f49ff077bb4941de88abb9931e5043 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Feb 2015 16:41:14 +0100 Subject: [PATCH 380/740] Account for not yet listed cells in getInteriorPtrs --- apps/openmw/mwworld/cells.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index fd5ec20dc..2aa817fa5 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -241,26 +241,30 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name) void MWWorld::Cells::getExteriorPtrs(const std::string &name, std::vector &out) { - for (std::map, CellStore>::iterator iter = mExteriors.begin(); - iter!=mExteriors.end(); ++iter) + const MWWorld::Store &cells = mStore.get(); + for (MWWorld::Store::iterator iter = cells.extBegin(); iter != cells.extEnd(); ++iter) { - Ptr ptr = getPtrAndCache (name, iter->second); + CellStore *cellStore = getCellStore (&(*iter)); + + Ptr ptr = getPtrAndCache (name, *cellStore); + if (!ptr.isEmpty()) out.push_back(ptr); } - } void MWWorld::Cells::getInteriorPtrs(const std::string &name, std::vector &out) { - for (std::map::iterator iter = mInteriors.begin(); - iter!=mInteriors.end(); ++iter) + const MWWorld::Store &cells = mStore.get(); + for (MWWorld::Store::iterator iter = cells.intBegin(); iter != cells.intEnd(); ++iter) { - Ptr ptr = getPtrAndCache (name, iter->second); + CellStore *cellStore = getCellStore (&(*iter)); + + Ptr ptr = getPtrAndCache (name, *cellStore); + if (!ptr.isEmpty()) out.push_back(ptr); } - } int MWWorld::Cells::countSavedGameRecords() const From 1f036c0381f3cbaaf3f21670d998b3f422a339c3 Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Wed, 4 Feb 2015 12:06:29 -0600 Subject: [PATCH 381/740] Patch for COC Spawn Issue. OMW Bug #1079 Fall back to the first static's position, if there are no door markers. --- apps/openmw/mwworld/worldimp.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1036d8ce6..e08000b0b 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2383,6 +2383,7 @@ namespace MWWorld bool World::findInteriorPosition(const std::string &name, ESM::Position &pos) { typedef MWWorld::CellRefList::List DoorList; + typedef MWWorld::CellRefList::List StaticList; pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; pos.pos[0] = pos.pos[1] = pos.pos[2] = 0; @@ -2427,6 +2428,13 @@ namespace MWWorld } } } + // Fall back to the first static location. + const StaticList &statics = cellStore->get().mList; + if ( statics.begin() != statics.end() ) { + pos = statics.begin()->mRef.getPosition(); + return true; + } + return false; } From 0c6e2170dbb5c880b4c3c8df3ff43566849cd804 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 31 Jan 2015 23:27:34 +0100 Subject: [PATCH 382/740] Include cleanup --- apps/launcher/graphicspage.cpp | 2 +- apps/openmw/mwbase/environment.hpp | 4 ++-- apps/openmw/mwbase/inputmanager.hpp | 4 +--- apps/openmw/mwbase/soundmanager.hpp | 4 +--- apps/openmw/mwbase/windowmanager.hpp | 18 +++++++++++------- apps/openmw/mwbase/world.hpp | 14 +++++--------- apps/openmw/mwdialogue/scripttest.cpp | 2 ++ apps/openmw/mwgui/hud.cpp | 1 + apps/openmw/mwgui/inventorywindow.cpp | 2 ++ apps/openmw/mwgui/itemmodel.cpp | 2 ++ apps/openmw/mwgui/journalviewmodel.cpp | 2 ++ apps/openmw/mwgui/loadingscreen.cpp | 2 ++ apps/openmw/mwgui/mainmenu.cpp | 1 + apps/openmw/mwgui/mapwindow.cpp | 1 + apps/openmw/mwgui/settingswindow.cpp | 1 + apps/openmw/mwgui/tooltips.cpp | 1 + apps/openmw/mwgui/waitdialog.cpp | 1 + apps/openmw/mwgui/windowbase.cpp | 2 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 5 +++++ apps/openmw/mwgui/windowmanagerimp.hpp | 7 ++++--- apps/openmw/mwmechanics/actors.hpp | 1 + apps/openmw/mwmechanics/character.cpp | 2 ++ apps/openmw/mwrender/animation.cpp | 1 + apps/openmw/mwrender/globalmap.cpp | 1 + apps/openmw/mwscript/animationextensions.cpp | 1 + apps/openmw/mwstate/statemanagerimp.cpp | 1 + apps/openmw/mwworld/livecellref.cpp | 3 ++- extern/sdl4ogre/events.h | 6 +++--- extern/sdl4ogre/sdlcursormanager.cpp | 3 +++ extern/sdl4ogre/sdlcursormanager.hpp | 5 +++-- 30 files changed, 66 insertions(+), 34 deletions(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 1f85bb5e7..dccf8bb8c 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -10,7 +10,7 @@ #define MAC_OS_X_VERSION_MIN_REQUIRED __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ #endif // MAC_OS_X_VERSION_MIN_REQUIRED -#include +#include #include #include diff --git a/apps/openmw/mwbase/environment.hpp b/apps/openmw/mwbase/environment.hpp index eb636ea2f..7f7919f81 100644 --- a/apps/openmw/mwbase/environment.hpp +++ b/apps/openmw/mwbase/environment.hpp @@ -1,5 +1,5 @@ -#ifndef GAME_BASE_INVIRONMENT_H -#define GAME_BASE_INVIRONMENT_H +#ifndef GAME_BASE_ENVIRONMENT_H +#define GAME_BASE_ENVIRONMENT_H namespace MWBase { diff --git a/apps/openmw/mwbase/inputmanager.hpp b/apps/openmw/mwbase/inputmanager.hpp index d44da4974..11eb1721f 100644 --- a/apps/openmw/mwbase/inputmanager.hpp +++ b/apps/openmw/mwbase/inputmanager.hpp @@ -3,8 +3,6 @@ #include -#include - namespace MWBase { /// \brief Interface for input manager (implemented in MWInput) @@ -29,7 +27,7 @@ namespace MWBase virtual void changeInputMode(bool guiMode) = 0; - virtual void processChangedSettings(const Settings::CategorySettingVector& changed) = 0; + virtual void processChangedSettings(const std::vector< std::pair >& changed) = 0; virtual void setDragDrop(bool dragDrop) = 0; diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index bc2f3f1c6..a4c08f06f 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -5,8 +5,6 @@ #include -#include - #include "../mwworld/ptr.hpp" namespace Ogre @@ -74,7 +72,7 @@ namespace MWBase virtual ~SoundManager() {} - virtual void processChangedSettings(const Settings::CategorySettingVector& settings) = 0; + virtual void processChangedSettings(const std::vector< std::pair >& settings) = 0; virtual void stopMusic() = 0; ///< Stops music if it's playing diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 69027d734..fc745d3e6 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -5,16 +5,20 @@ #include #include -#include - -#include - -#include - #include "../mwmechanics/stat.hpp" #include "../mwgui/mode.hpp" +namespace Loading +{ + class Listener; +} + +namespace Translation +{ + class Storage; +} + namespace MyGUI { class Gui; @@ -267,7 +271,7 @@ namespace MWBase */ virtual std::string getGameSettingString(const std::string &id, const std::string &default_) = 0; - virtual void processChangedSettings(const Settings::CategorySettingVector& changed) = 0; + virtual void processChangedSettings(const std::vector< std::pair >& changed) = 0; virtual void windowResized(int x, int y) = 0; diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 9d8fc90a1..3af2a2775 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -4,25 +4,21 @@ #include #include -#include - #include -#include "../mwworld/globals.hpp" #include "../mwworld/ptr.hpp" namespace Ogre { class Vector2; class Vector3; + class Quaternion; + class Image; } -namespace OEngine +namespace Loading { - namespace Physic - { - class PhysicEngine; - } + class Listener; } namespace ESM @@ -390,7 +386,7 @@ namespace MWBase virtual bool canPlaceObject (float cursorX, float cursorY) = 0; ///< @return true if it is possible to place on object at specified cursor location - virtual void processChangedSettings (const Settings::CategorySettingVector& settings) = 0; + virtual void processChangedSettings (const std::vector< std::pair >& settings) = 0; virtual bool isFlying(const MWWorld::Ptr &ptr) const = 0; virtual bool isSlowFalling(const MWWorld::Ptr &ptr) const = 0; diff --git a/apps/openmw/mwdialogue/scripttest.cpp b/apps/openmw/mwdialogue/scripttest.cpp index b2c8f536a..fd477365f 100644 --- a/apps/openmw/mwdialogue/scripttest.cpp +++ b/apps/openmw/mwdialogue/scripttest.cpp @@ -1,5 +1,7 @@ #include "scripttest.hpp" +#include + #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 13a5c559c..1f7ead6f5 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -10,6 +10,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index ed0f505f5..ae7d60d44 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -8,6 +8,8 @@ #include #include +#include + #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" diff --git a/apps/openmw/mwgui/itemmodel.cpp b/apps/openmw/mwgui/itemmodel.cpp index f5135ce80..8224fd55b 100644 --- a/apps/openmw/mwgui/itemmodel.cpp +++ b/apps/openmw/mwgui/itemmodel.cpp @@ -1,5 +1,7 @@ #include "itemmodel.hpp" +#include + #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/store.hpp" diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index add2ac62c..3a86613f6 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -8,6 +8,8 @@ #include +#include + #include "../mwbase/world.hpp" #include "../mwbase/journal.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 270066c97..9e3343c78 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -15,6 +15,8 @@ #include #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/statemanager.hpp" diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index f1c4c4088..6ad4da3bf 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -9,6 +9,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 61712a470..13e2e3904 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -13,6 +13,7 @@ #include #include +#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index f8741a67a..281093452 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -15,6 +15,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 2849688c2..275071737 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -8,6 +8,7 @@ #include #include +#include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 718e04e52..fedb0324e 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -3,6 +3,7 @@ #include #include +#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index 7f2eaec2e..8fdcf6b20 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -2,6 +2,8 @@ #include +#include + #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 975ee6c29..a35498dea 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -19,6 +19,9 @@ #include #include +#include +#include + #include #include @@ -26,6 +29,8 @@ #include +#include + #include #include diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index a08c59a2f..b3eb9cd0a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -5,13 +5,14 @@ This class owns and controls all the MW specific windows in the GUI. It can enable/disable Gui mode, and is responsible for sending and retrieving information from the Gui. - - MyGUI should be initialized separately before creating instances of - this class. **/ +#include + #include "../mwbase/windowmanager.hpp" +#include + #include "mapwindow.hpp" #include diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 39598b2a2..70f1b47d9 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "movement.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 91b375714..449c030f4 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -27,6 +27,8 @@ #include "creaturestats.hpp" #include "security.hpp" +#include + #include "../mwrender/animation.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index ec5398309..50afc5afd 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index f0f6158ed..de78748b5 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -11,6 +11,7 @@ #include #include +#include #include diff --git a/apps/openmw/mwscript/animationextensions.cpp b/apps/openmw/mwscript/animationextensions.cpp index 613cf7d24..00b8a9620 100644 --- a/apps/openmw/mwscript/animationextensions.cpp +++ b/apps/openmw/mwscript/animationextensions.cpp @@ -2,6 +2,7 @@ #include "animationextensions.hpp" #include +#include #include #include diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index a282f152a..d623ba465 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -13,6 +13,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwworld/livecellref.cpp b/apps/openmw/mwworld/livecellref.cpp index dd313632b..bfc708185 100644 --- a/apps/openmw/mwworld/livecellref.cpp +++ b/apps/openmw/mwworld/livecellref.cpp @@ -1,6 +1,7 @@ - #include "livecellref.hpp" +#include + #include #include "../mwbase/environment.hpp" diff --git a/extern/sdl4ogre/events.h b/extern/sdl4ogre/events.h index 0fb4d6f06..6961e81fc 100644 --- a/extern/sdl4ogre/events.h +++ b/extern/sdl4ogre/events.h @@ -1,8 +1,8 @@ #ifndef _SFO_EVENTS_H #define _SFO_EVENTS_H -#include - +#include +#include //////////// // Events // @@ -65,7 +65,7 @@ public: virtual ~WindowListener() {} /** @remarks The window's visibility changed */ - virtual void windowVisibilityChange( bool visible ) {}; + virtual void windowVisibilityChange( bool visible ) {} /** @remarks The window got / lost input focus */ virtual void windowFocusChange( bool have_focus ) {} diff --git a/extern/sdl4ogre/sdlcursormanager.cpp b/extern/sdl4ogre/sdlcursormanager.cpp index 5ef274b7e..7623d57db 100644 --- a/extern/sdl4ogre/sdlcursormanager.cpp +++ b/extern/sdl4ogre/sdlcursormanager.cpp @@ -4,6 +4,9 @@ #include #include +#include +#include + #include namespace SFO diff --git a/extern/sdl4ogre/sdlcursormanager.hpp b/extern/sdl4ogre/sdlcursormanager.hpp index 7e3e59b4a..58324fc01 100644 --- a/extern/sdl4ogre/sdlcursormanager.hpp +++ b/extern/sdl4ogre/sdlcursormanager.hpp @@ -1,11 +1,12 @@ #ifndef SDL4OGRE_CURSORMANAGER_H #define SDL4OGRE_CURSORMANAGER_H -#include - #include "cursormanager.hpp" #include +struct SDL_Cursor; +struct SDL_Surface; + namespace SFO { class SDLCursorManager : From 6d097fbfbd8f051de27bfcd81bb0746f1509bf47 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 1 Feb 2015 00:26:06 +0100 Subject: [PATCH 383/740] Normalise spelling of "levelled" throughout the code --- apps/esmtool/record.cpp | 4 ++-- apps/essimporter/importcellref.cpp | 4 ++-- apps/openmw/mwmechanics/levelledlist.hpp | 8 ++++---- apps/openmw/mwmechanics/npcstats.cpp | 2 +- apps/openmw/mwscript/miscextensions.cpp | 10 +++++----- components/esm/loadlevlist.cpp | 6 +++--- components/esm/loadlevlist.hpp | 12 ++++++------ 7 files changed, 23 insertions(+), 23 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index df2631c13..e167278f3 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -837,7 +837,7 @@ void Record::print() std::cout << " Chance for None: " << (int)mData.mChanceNone << std::endl; std::cout << " Flags: " << creatureListFlags(mData.mFlags) << std::endl; std::cout << " Number of items: " << mData.mList.size() << std::endl; - std::vector::iterator iit; + std::vector::iterator iit; for (iit = mData.mList.begin(); iit != mData.mList.end(); ++iit) std::cout << " Creature: Level: " << iit->mLevel << " Creature: " << iit->mId << std::endl; @@ -849,7 +849,7 @@ void Record::print() std::cout << " Chance for None: " << (int)mData.mChanceNone << std::endl; std::cout << " Flags: " << itemListFlags(mData.mFlags) << std::endl; std::cout << " Number of items: " << mData.mList.size() << std::endl; - std::vector::iterator iit; + std::vector::iterator iit; for (iit = mData.mList.begin(); iit != mData.mList.end(); ++iit) std::cout << " Inventory: Level: " << iit->mLevel << " Item: " << iit->mId << std::endl; diff --git a/apps/essimporter/importcellref.cpp b/apps/essimporter/importcellref.cpp index 906b2ed24..cca356b2a 100644 --- a/apps/essimporter/importcellref.cpp +++ b/apps/essimporter/importcellref.cpp @@ -22,7 +22,7 @@ namespace ESSImport ActorData::load(esm); if (esm.isNextSub("LVCR")) { - // occurs on leveled creature spawner references + // occurs on levelled creature spawner references // probably some identifier for the creature that has been spawned? unsigned char lvcr; esm.getHT(lvcr); @@ -32,7 +32,7 @@ namespace ESSImport mEnabled = true; esm.getHNOT(mEnabled, "ZNAM"); - // DATA should occur for all references, except leveled creature spawners + // DATA should occur for all references, except levelled creature spawners // I've seen DATA *twice* on a creature record, and with the exact same content too! weird // alarmvoi0000.ess esm.getHNOT(mPos, "DATA", 24); diff --git a/apps/openmw/mwmechanics/levelledlist.hpp b/apps/openmw/mwmechanics/levelledlist.hpp index 96410c35d..de652a9c8 100644 --- a/apps/openmw/mwmechanics/levelledlist.hpp +++ b/apps/openmw/mwmechanics/levelledlist.hpp @@ -12,9 +12,9 @@ namespace MWMechanics { /// @return ID of resulting item, or empty if none - inline std::string getLevelledItem (const ESM::LeveledListBase* levItem, bool creature, unsigned char failChance=0) + inline std::string getLevelledItem (const ESM::LevelledListBase* levItem, bool creature, unsigned char failChance=0) { - const std::vector& items = levItem->mList; + const std::vector& items = levItem->mList; const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayerPtr(); int playerLevel = player.getClass().getCreatureStats(player).getLevel(); @@ -27,7 +27,7 @@ namespace MWMechanics std::vector candidates; int highestLevel = 0; - for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) + for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) { if (it->mLevel > highestLevel && it->mLevel <= playerLevel) highestLevel = it->mLevel; @@ -39,7 +39,7 @@ namespace MWMechanics allLevels = levItem->mFlags & ESM::CreatureLevList::AllLevels; std::pair highest = std::make_pair(-1, ""); - for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) + for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) { if (playerLevel >= it->mLevel && (allLevels || it->mLevel == highestLevel)) diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index c517b4df8..7219d6185 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -200,7 +200,7 @@ void MWMechanics::NpcStats::useSkill (int skillIndex, const ESM::Class& class_, if (value.getProgress()>=1) { - // skill leveled up + // skill levelled up increaseSkill(skillIndex, class_, false); } } diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 37bb4235e..bffeef768 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -34,24 +34,24 @@ namespace { - void addToLevList(ESM::LeveledListBase* list, const std::string& itemId, int level) + void addToLevList(ESM::LevelledListBase* list, const std::string& itemId, int level) { - for (std::vector::iterator it = list->mList.begin(); it != list->mList.end();) + for (std::vector::iterator it = list->mList.begin(); it != list->mList.end();) { if (it->mLevel == level && itemId == it->mId) return; } - ESM::LeveledListBase::LevelItem item; + ESM::LevelledListBase::LevelItem item; item.mId = itemId; item.mLevel = level; list->mList.push_back(item); } - void removeFromLevList(ESM::LeveledListBase* list, const std::string& itemId, int level) + void removeFromLevList(ESM::LevelledListBase* list, const std::string& itemId, int level) { // level of -1 removes all items with that itemId - for (std::vector::iterator it = list->mList.begin(); it != list->mList.end();) + for (std::vector::iterator it = list->mList.begin(); it != list->mList.end();) { if (level != -1 && it->mLevel != level) { diff --git a/components/esm/loadlevlist.cpp b/components/esm/loadlevlist.cpp index 6385b9a71..f2c695c1f 100644 --- a/components/esm/loadlevlist.cpp +++ b/components/esm/loadlevlist.cpp @@ -7,7 +7,7 @@ namespace ESM { -void LeveledListBase::load(ESMReader &esm) +void LevelledListBase::load(ESMReader &esm) { esm.getHNT(mFlags, "DATA"); esm.getHNT(mChanceNone, "NNAM"); @@ -34,7 +34,7 @@ void LeveledListBase::load(ESMReader &esm) esm.getHNT(li.mLevel, "INTV"); } } -void LeveledListBase::save(ESMWriter &esm) const +void LevelledListBase::save(ESMWriter &esm) const { esm.writeHNT("DATA", mFlags); esm.writeHNT("NNAM", mChanceNone); @@ -47,7 +47,7 @@ void LeveledListBase::save(ESMWriter &esm) const } } - void LeveledListBase::blank() + void LevelledListBase::blank() { mFlags = 0; mChanceNone = 0; diff --git a/components/esm/loadlevlist.hpp b/components/esm/loadlevlist.hpp index a4e1b85c2..bcea2b234 100644 --- a/components/esm/loadlevlist.hpp +++ b/components/esm/loadlevlist.hpp @@ -11,14 +11,14 @@ class ESMReader; class ESMWriter; /* - * Leveled lists. Since these have identical layout, I only bothered + * Levelled lists. Since these have identical layout, I only bothered * to implement it once. * - * We should later implement the ability to merge leveled lists from + * We should later implement the ability to merge levelled lists from * several files. */ -struct LeveledListBase +struct LevelledListBase { int mFlags; unsigned char mChanceNone; // Chance that none are selected (0-100) @@ -43,7 +43,7 @@ struct LeveledListBase ///< Set record to default state (does not touch the ID). }; -struct CreatureLevList: LeveledListBase +struct CreatureLevList: LevelledListBase { static unsigned int sRecordId; @@ -61,7 +61,7 @@ struct CreatureLevList: LeveledListBase } }; -struct ItemLevList: LeveledListBase +struct ItemLevList: LevelledListBase { static unsigned int sRecordId; @@ -72,7 +72,7 @@ struct ItemLevList: LeveledListBase // list is instantiated, instead of // giving several identical items // (used when a container has more - // than one instance of one leveled + // than one instance of one levelled // list.) AllLevels = 0x02 // Calculate from all levels <= player // level, not just the closest below From 9825b68dfb6d5ab015d283c6bb858246b40ba9b2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 1 Feb 2015 16:19:05 +0100 Subject: [PATCH 384/740] Fix SDL eating SIGINT signals in the launcher (Fixes #2328) --- apps/launcher/main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/launcher/main.cpp b/apps/launcher/main.cpp index e4fae74f4..5c3f38458 100644 --- a/apps/launcher/main.cpp +++ b/apps/launcher/main.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -26,6 +27,8 @@ int main(int argc, char *argv[]) qDebug() << "SDL_Init failed: " << QString::fromStdString(SDL_GetError()); return 0; } + signal(SIGINT, SIG_DFL); // We don't want to use the SDL event loop in the launcher, + // so reset SIGINT which SDL wants to redirect to an SDL_Quit event. QApplication app(argc, argv); From 6ea59c93abf46402f505c8dd8519b42a7249dc15 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Feb 2015 04:20:33 +0100 Subject: [PATCH 385/740] Ignore the object scale in Move instruction (Fixes #2275) --- apps/openmw/mwscript/transformationextensions.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 3bbde2003..fcfc36995 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -691,10 +691,10 @@ namespace MWScript if (!ptr.getRefData().getBaseNode()) return; - Ogre::Vector3 worldPos = ptr.getRefData().getBaseNode()->convertLocalToWorldPosition(posChange); - - dynamic_cast(runtime.getContext()).updatePtr( - MWBase::Environment::get().getWorld()->moveObject(ptr, worldPos.x, worldPos.y, worldPos.z)); + Ogre::Vector3 diff = ptr.getRefData().getBaseNode()->getOrientation() * posChange; + Ogre::Vector3 worldPos(ptr.getRefData().getPosition().pos); + worldPos += diff; + MWBase::Environment::get().getWorld()->moveObject(ptr, worldPos.x, worldPos.y, worldPos.z); } }; From 27dc49a1357c2078d2305f0859efd3ccc3de8639 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Feb 2015 00:53:30 +0100 Subject: [PATCH 386/740] Rewrite game settings manager Removes the abhorrent dependency on Ogre for this code and improves the error handling. --- apps/openmw/engine.cpp | 6 +- apps/openmw/mwbase/inputmanager.hpp | 4 +- apps/openmw/mwbase/soundmanager.hpp | 4 +- apps/openmw/mwbase/windowmanager.hpp | 2 +- apps/openmw/mwbase/world.hpp | 3 +- components/settings/settings.cpp | 224 +++++++++++++++------------ components/settings/settings.hpp | 13 +- 7 files changed, 137 insertions(+), 119 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 859baebe4..a9a7f0632 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -292,14 +292,10 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings) else throw std::runtime_error ("No default settings file found! Make sure the file \"settings-default.cfg\" was properly installed."); - // load user settings if they exist, otherwise just load the default settings as user settings + // load user settings if they exist const std::string settingspath = mCfgMgr.getUserConfigPath().string() + "/settings.cfg"; if (boost::filesystem::exists(settingspath)) settings.loadUser(settingspath); - else if (boost::filesystem::exists(localdefault)) - settings.loadUser(localdefault); - else if (boost::filesystem::exists(globaldefault)) - settings.loadUser(globaldefault); mFpsLevel = settings.getInt("fps", "HUD"); diff --git a/apps/openmw/mwbase/inputmanager.hpp b/apps/openmw/mwbase/inputmanager.hpp index 11eb1721f..a53d8d9dc 100644 --- a/apps/openmw/mwbase/inputmanager.hpp +++ b/apps/openmw/mwbase/inputmanager.hpp @@ -2,6 +2,8 @@ #define GAME_MWBASE_INPUTMANAGER_H #include +#include +#include namespace MWBase { @@ -27,7 +29,7 @@ namespace MWBase virtual void changeInputMode(bool guiMode) = 0; - virtual void processChangedSettings(const std::vector< std::pair >& changed) = 0; + virtual void processChangedSettings(const std::set< std::pair >& changed) = 0; virtual void setDragDrop(bool dragDrop) = 0; diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index a4c08f06f..f3381a8fd 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -2,7 +2,7 @@ #define GAME_MWBASE_SOUNDMANAGER_H #include - +#include #include #include "../mwworld/ptr.hpp" @@ -72,7 +72,7 @@ namespace MWBase virtual ~SoundManager() {} - virtual void processChangedSettings(const std::vector< std::pair >& settings) = 0; + virtual void processChangedSettings(const std::set< std::pair >& settings) = 0; virtual void stopMusic() = 0; ///< Stops music if it's playing diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index fc745d3e6..c984b5e54 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -271,7 +271,7 @@ namespace MWBase */ virtual std::string getGameSettingString(const std::string &id, const std::string &default_) = 0; - virtual void processChangedSettings(const std::vector< std::pair >& changed) = 0; + virtual void processChangedSettings(const std::set< std::pair >& changed) = 0; virtual void windowResized(int x, int y) = 0; diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 3af2a2775..154d96f7d 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -3,6 +3,7 @@ #include #include +#include #include @@ -386,7 +387,7 @@ namespace MWBase virtual bool canPlaceObject (float cursorX, float cursorY) = 0; ///< @return true if it is possible to place on object at specified cursor location - virtual void processChangedSettings (const std::vector< std::pair >& settings) = 0; + virtual void processChangedSettings (const std::set< std::pair >& settings) = 0; virtual bool isFlying(const MWWorld::Ptr &ptr) const = 0; virtual bool isSlowFalling(const MWWorld::Ptr &ptr) const = 0; diff --git a/components/settings/settings.cpp b/components/settings/settings.cpp index 5fc2ca3c1..a9a78d035 100644 --- a/components/settings/settings.cpp +++ b/components/settings/settings.cpp @@ -1,95 +1,144 @@ #include "settings.hpp" #include -#include -#include -#include #include -#include -#include - -using namespace Settings; +#include +#include +#include -namespace bfs = boost::filesystem; +namespace Settings +{ -Ogre::ConfigFile Manager::mFile = Ogre::ConfigFile(); -Ogre::ConfigFile Manager::mDefaultFile = Ogre::ConfigFile(); +CategorySettingValueMap Manager::mDefaultSettings = CategorySettingValueMap(); +CategorySettingValueMap Manager::mUserSettings = CategorySettingValueMap(); CategorySettingVector Manager::mChangedSettings = CategorySettingVector(); -CategorySettingValueMap Manager::mNewSettings = CategorySettingValueMap(); - -void Manager::loadUser (const std::string& file) -{ - Ogre::DataStreamPtr stream = openConstrainedFileDataStream(file.c_str()); - mFile.load(stream); -} -void Manager::loadDefault (const std::string& file) -{ - Ogre::DataStreamPtr stream = openConstrainedFileDataStream(file.c_str()); - mDefaultFile.load(stream); -} -void Manager::saveUser(const std::string& file) +class SettingsFileParser { - bfs::ofstream fout((bfs::path(file))); +public: + SettingsFileParser() : mLine(0) {} - Ogre::ConfigFile::SectionIterator seci = mFile.getSectionIterator(); - - while (seci.hasMoreElements()) + void loadSettingsFile (const std::string& file, CategorySettingValueMap& settings) { - Ogre::String sectionName = seci.peekNextKey(); + mFile = file; + boost::filesystem::ifstream stream; + stream.open(boost::filesystem::path(file)); + std::string currentCategory; + mLine = 0; + while (!stream.eof() && !stream.fail()) + { + ++mLine; + std::string line; + std::getline( stream, line ); - if (sectionName.length() > 0) - fout << '\n' << '[' << seci.peekNextKey() << ']' << '\n'; + size_t i = 0; + if (!skipWhiteSpace(i, line)) + continue; - Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext(); - Ogre::ConfigFile::SettingsMultiMap::iterator i; - for (i = settings->begin(); i != settings->end(); ++i) - { - fout << i->first.c_str() << " = " << i->second.c_str() << '\n'; - } + if (line[i] == '#') // skip comment + continue; - CategorySettingValueMap::iterator it = mNewSettings.begin(); - while (it != mNewSettings.end()) - { - if (it->first.first == sectionName) + if (line[i] == '[') { - fout << it->first.second << " = " << it->second << '\n'; - mNewSettings.erase(it++); + size_t end = line.find(']', i); + if (end == std::string::npos) + fail("unterminated category"); + + currentCategory = line.substr(i+1, end - (i+1)); + boost::algorithm::trim(currentCategory); + i = end+1; } - else - ++it; + + if (!skipWhiteSpace(i, line)) + continue; + + if (currentCategory.empty()) + fail("empty category name"); + + size_t settingEnd = line.find('=', i); + if (settingEnd == std::string::npos) + fail("unterminated setting name"); + + std::string setting = line.substr(i, (settingEnd-i)); + boost::algorithm::trim(setting); + + size_t valueBegin = settingEnd+1; + std::string value = line.substr(valueBegin); + boost::algorithm::trim(value); + + if (settings.insert(std::make_pair(std::make_pair(currentCategory, setting), value)).second == false) + fail(std::string("duplicate setting: [" + currentCategory + "] " + setting)); } } - std::string category = ""; - for (CategorySettingValueMap::iterator it = mNewSettings.begin(); - it != mNewSettings.end(); ++it) +private: + /// Increment i until it longer points to a whitespace character + /// in the string or has reached the end of the string. + /// @return false if we have reached the end of the string + bool skipWhiteSpace(size_t& i, std::string& str) { - if (category != it->first.first) + while (i < str.size() && std::isspace(str[i], std::locale::classic())) { - category = it->first.first; - fout << '\n' << '[' << category << ']' << '\n'; + ++i; } - fout << it->first.second << " = " << it->second << '\n'; + return i < str.size(); } - fout.close(); + void fail(const std::string& message) + { + std::stringstream error; + error << "Error on line " << mLine << " in " << mFile << ":\n" << message; + throw std::runtime_error(error.str()); + } + + std::string mFile; + int mLine; +}; + +void Manager::loadDefault(const std::string &file) +{ + SettingsFileParser parser; + parser.loadSettingsFile(file, mDefaultSettings); } -std::string Manager::getString (const std::string& setting, const std::string& category) +void Manager::loadUser(const std::string &file) { - if (mNewSettings.find(std::make_pair(category, setting)) != mNewSettings.end()) - return mNewSettings[std::make_pair(category, setting)]; + SettingsFileParser parser; + parser.loadSettingsFile(file, mUserSettings); +} + +void Manager::saveUser(const std::string &file) +{ + boost::filesystem::ofstream stream; + stream.open(boost::filesystem::path(file)); + std::string currentCategory; + for (CategorySettingValueMap::iterator it = mUserSettings.begin(); it != mUserSettings.end(); ++it) + { + if (it->first.first != currentCategory) + { + currentCategory = it->first.first; + stream << "\n[" << currentCategory << "]\n"; + } + stream << it->first.second << " = " << it->second << "\n"; + } +} + +std::string Manager::getString(const std::string &setting, const std::string &category) +{ + CategorySettingValueMap::key_type key = std::make_pair(category, setting); + CategorySettingValueMap::iterator it = mUserSettings.find(key); + if (it != mUserSettings.end()) + return it->second; - std::string defaultval = mDefaultFile.getSetting(setting, category, "NOTFOUND"); - std::string val = mFile.getSetting(setting, category, defaultval); + it = mDefaultSettings.find(key); + if (it != mDefaultSettings.end()) + return it->second; - if (val == "NOTFOUND") - throw std::runtime_error("Trying to retrieve a non-existing setting: " + setting + " Make sure the settings-default.cfg file was properly installed."); - return val; + throw std::runtime_error(std::string("Trying to retrieve a non-existing setting: ") + setting + + ".\nMake sure the settings-default.cfg file file was properly installed."); } float Manager::getFloat (const std::string& setting, const std::string& category) @@ -107,51 +156,20 @@ bool Manager::getBool (const std::string& setting, const std::string& category) return Ogre::StringConverter::parseBool( getString(setting, category) ); } -void Manager::setString (const std::string& setting, const std::string& category, const std::string& value) +void Manager::setString(const std::string &setting, const std::string &category, const std::string &value) { - CategorySetting s = std::make_pair(category, setting); + CategorySettingValueMap::key_type key = std::make_pair(category, setting); - bool found=false; - try + CategorySettingValueMap::iterator found = mUserSettings.find(key); + if (found != mUserSettings.end()) { - Ogre::ConfigFile::SettingsIterator it = mFile.getSettingsIterator(category); - while (it.hasMoreElements()) - { - Ogre::ConfigFile::SettingsMultiMap::iterator i = it.current(); - - if ((*i).first == setting) - { - if ((*i).second != value) - { - mChangedSettings.push_back(std::make_pair(category, setting)); - (*i).second = value; - } - found = true; - } - - it.getNext(); - } + if (found->second == value) + return; } - catch (Ogre::Exception&) - {} - if (!found) - { - if (mNewSettings.find(s) != mNewSettings.end()) - { - if (mNewSettings[s] != value) - { - mChangedSettings.push_back(std::make_pair(category, setting)); - mNewSettings[s] = value; - } - } - else - { - if (mDefaultFile.getSetting(setting, category) != value) - mChangedSettings.push_back(std::make_pair(category, setting)); - mNewSettings[s] = value; - } - } + mUserSettings[key] = value; + + mChangedSettings.insert(key); } void Manager::setInt (const std::string& setting, const std::string& category, const int value) @@ -159,12 +177,12 @@ void Manager::setInt (const std::string& setting, const std::string& category, c setString(setting, category, Ogre::StringConverter::toString(value)); } -void Manager::setFloat (const std::string& setting, const std::string& category, const float value) +void Manager::setFloat (const std::string &setting, const std::string &category, const float value) { setString(setting, category, Ogre::StringConverter::toString(value)); } -void Manager::setBool (const std::string& setting, const std::string& category, const bool value) +void Manager::setBool(const std::string &setting, const std::string &category, const bool value) { setString(setting, category, Ogre::StringConverter::toString(value)); } @@ -175,3 +193,5 @@ const CategorySettingVector Manager::apply() mChangedSettings.clear(); return vec; } + +} diff --git a/components/settings/settings.hpp b/components/settings/settings.hpp index 03b0b517c..c16ff5a1e 100644 --- a/components/settings/settings.hpp +++ b/components/settings/settings.hpp @@ -1,12 +1,14 @@ #ifndef COMPONENTS_SETTINGS_H #define COMPONENTS_SETTINGS_H -#include +#include +#include +#include namespace Settings { typedef std::pair < std::string, std::string > CategorySetting; - typedef std::vector< std::pair > CategorySettingVector; + typedef std::set< std::pair > CategorySettingVector; typedef std::map < CategorySetting, std::string > CategorySettingValueMap; /// @@ -15,15 +17,12 @@ namespace Settings class Manager { public: - static Ogre::ConfigFile mFile; - static Ogre::ConfigFile mDefaultFile; + static CategorySettingValueMap mDefaultSettings; + static CategorySettingValueMap mUserSettings; static CategorySettingVector mChangedSettings; ///< tracks all the settings that were changed since the last apply() call - static CategorySettingValueMap mNewSettings; - ///< tracks all the settings that are in the default file, but not in user file yet - void loadDefault (const std::string& file); ///< load file as the default settings (can be overridden by user settings) From 955505c167800109590f4c56f40c679cef344611 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Feb 2015 01:05:40 +0100 Subject: [PATCH 387/740] Remove unused function --- apps/openmw/engine.cpp | 10 +--------- apps/openmw/engine.hpp | 4 ---- apps/openmw/mwgui/windowmanagerimp.cpp | 5 ++--- apps/openmw/mwgui/windowmanagerimp.hpp | 3 +-- 4 files changed, 4 insertions(+), 18 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index a9a7f0632..c70acaba8 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -170,7 +170,6 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) : mOgre (0) - , mFpsLevel(0) , mVerboseScripts (false) , mSkipMenu (false) , mUseSound (true) @@ -297,8 +296,6 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings) if (boost::filesystem::exists(settingspath)) settings.loadUser(settingspath); - mFpsLevel = settings.getInt("fps", "HUD"); - // load nif overrides NifOverrides::Overrides nifOverrides; std::string transparencyOverrides = "/transparency-overrides.cfg"; @@ -373,7 +370,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mEnvironment.setInputManager (input); MWGui::WindowManager* window = new MWGui::WindowManager( - mExtensions, mFpsLevel, mOgre, mCfgMgr.getLogPath().string() + std::string("/"), + mExtensions, mOgre, mCfgMgr.getLogPath().string() + std::string("/"), mCfgMgr.getCachePath ().string(), mScriptConsoleMode, mTranslationDataStorage, mEncoding, mExportFonts, mFallbackMap); mEnvironment.setWindowManager (window); @@ -574,11 +571,6 @@ void OMW::Engine::setSoundUsage(bool soundUsage) mUseSound = soundUsage; } -void OMW::Engine::showFPS(int level) -{ - mFpsLevel = level; -} - void OMW::Engine::setEncoding(const ToUTF8::FromType& encoding) { mEncoding = encoding; diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 079dd922c..3b088595c 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -71,7 +71,6 @@ namespace OMW OEngine::Render::OgreRenderer *mOgre; std::string mCellName; std::vector mContentFiles; - int mFpsLevel; bool mVerboseScripts; bool mSkipMenu; bool mUseSound; @@ -151,9 +150,6 @@ namespace OMW */ void addContentFile(const std::string& file); - /// Enable fps counter - void showFPS(int level); - /// Enable or disable verbose script output void setScriptsVerbosity(bool scriptsVerbosity); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index a35498dea..715f47c46 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -96,7 +96,7 @@ namespace MWGui { WindowManager::WindowManager( - const Compiler::Extensions& extensions, int fpsLevel, OEngine::Render::OgreRenderer *ogre, + const Compiler::Extensions& extensions, OEngine::Render::OgreRenderer *ogre, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap) : mConsoleOnlyScripts(consoleOnlyScripts) @@ -167,7 +167,6 @@ namespace MWGui , mForceHidden(GW_None) , mAllowed(GW_ALL) , mRestAllowed(true) - , mShowFPSLevel(fpsLevel) , mFPS(0.0f) , mTriangleCount(0) , mBatchCount(0) @@ -269,7 +268,7 @@ namespace MWGui trackWindow(mDialogueWindow, "dialogue"); mContainerWindow = new ContainerWindow(mDragAndDrop); trackWindow(mContainerWindow, "container"); - mHud = new HUD(mCustomMarkers, mShowFPSLevel, mDragAndDrop); + mHud = new HUD(mCustomMarkers, Settings::Manager::getInt("fps", "HUD"), mDragAndDrop); mToolTips = new ToolTips(); mScrollWindow = new ScrollWindow(); mBookWindow = new BookWindow(); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index b3eb9cd0a..9f01b136c 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -97,7 +97,7 @@ namespace MWGui typedef std::pair Faction; typedef std::vector FactionList; - WindowManager(const Compiler::Extensions& extensions, int fpsLevel, + WindowManager(const Compiler::Extensions& extensions, OEngine::Render::OgreRenderer *mOgre, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap); @@ -451,7 +451,6 @@ namespace MWGui void updateVisible(); // Update visibility of all windows based on mode, shown and allowed settings - int mShowFPSLevel; float mFPS; unsigned int mTriangleCount; unsigned int mBatchCount; From ab9100fa904898606cc41f6df706b85a583bc2dc Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Feb 2015 13:12:58 +0100 Subject: [PATCH 388/740] Prevent dropping item on itself in ContentModel (Fixes #2334) Also improves the drop indicator, it is now shown in between items instead of on an item. --- components/contentselector/model/contentmodel.cpp | 7 +++---- components/contentselector/model/contentmodel.hpp | 1 - components/contentselector/view/contentselector.cpp | 3 ++- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index b81b1cbf6..198bbffbb 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -15,8 +15,7 @@ ContentSelectorModel::ContentModel::ContentModel(QObject *parent, QIcon warningI mMimeType ("application/omwcontent"), mMimeTypes (QStringList() << mMimeType), mColumnCount (1), - mDragDropFlags (Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled), - mDropActions (Qt::CopyAction | Qt::MoveAction) + mDropActions (Qt::MoveAction) { setEncoding ("win1252"); uncheckAll(); @@ -104,7 +103,7 @@ QModelIndex ContentSelectorModel::ContentModel::indexFromItem(const EsmFile *ite Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index) const { if (!index.isValid()) - return Qt::NoItemFlags; + return Qt::ItemIsDropEnabled; const EsmFile *file = item(index.row()); @@ -152,7 +151,7 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index if (gamefileChecked) { if (allDependenciesFound) - returnFlags = returnFlags | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | mDragDropFlags; + returnFlags = returnFlags | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled; else returnFlags = Qt::ItemIsSelectable; } diff --git a/components/contentselector/model/contentmodel.hpp b/components/contentselector/model/contentmodel.hpp index 2ced40f04..6af5425c7 100644 --- a/components/contentselector/model/contentmodel.hpp +++ b/components/contentselector/model/contentmodel.hpp @@ -89,7 +89,6 @@ namespace ContentSelectorModel QString mMimeType; QStringList mMimeTypes; int mColumnCount; - Qt::ItemFlags mDragDropFlags; Qt::DropActions mDropActions; }; } diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index 2d560e054..ad023e5b2 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -15,7 +15,8 @@ ContentSelectorView::ContentSelector::ContentSelector(QWidget *parent) : QObject(parent) { - ui.setupUi (parent); + ui.setupUi(parent); + ui.addonView->setDragDropMode(QAbstractItemView::InternalMove); buildContentModel(); buildGameFileView(); From 2bf1dd8f46fa3bf19fb5416bc6b269631495a84f Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Feb 2015 14:01:31 +0100 Subject: [PATCH 389/740] Make the status badges consistent, again --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1698a7ebc..ed21b852f 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ OpenMW ====== -[![Build Status](https://img.shields.io/travis/OpenMW/openmw.svg)](https://travis-ci.org/OpenMW/openmw) [![Coverity Scan Build Status](https://scan.coverity.com/projects/3740/badge.svg)](https://scan.coverity.com/projects/3740) +[![Build Status](https://img.shields.io/travis/OpenMW/openmw.svg?style=plastic)](https://travis-ci.org/OpenMW/openmw) [![Coverity Scan Build Status](https://scan.coverity.com/projects/3740/badge.svg)](https://scan.coverity.com/projects/3740) OpenMW is an attempt at recreating the engine for the popular role-playing game Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work. From aa6ebcd75cd95c5423b7216759f19cfc6d65224a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Feb 2015 23:43:56 +0100 Subject: [PATCH 390/740] Change stolen items handling to match MW (Fixes #1443, Fixes #2290) --- apps/openmw/mwbase/mechanicsmanager.hpp | 4 +++- apps/openmw/mwgui/container.cpp | 2 +- apps/openmw/mwgui/inventorywindow.cpp | 2 +- .../mwmechanics/mechanicsmanagerimp.cpp | 24 ++++++++++++++++--- .../mwmechanics/mechanicsmanagerimp.hpp | 4 +++- apps/openmw/mwworld/actiontake.cpp | 2 +- 6 files changed, 30 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 33a2ef1ea..58f2f6ee5 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -129,7 +129,9 @@ namespace MWBase /// @return false if the attack was considered a "friendly hit" and forgiven virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker) = 0; /// Utility to check if taking this item is illegal and calling commitCrime if so - virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, int count) = 0; + /// @param container The container the item is in; may be empty for an item in the world + virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container, + int count) = 0; /// Utility to check if opening (i.e. unlocking) this object is illegal and calling commitCrime if so virtual void objectOpened (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item) = 0; /// Attempt sleeping in a bed. If this is illegal, call commitCrime. diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 53b1e679a..579730f42 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -285,7 +285,7 @@ namespace MWGui if (mPtr.getClass().isActor() && mPtr.getClass().getCreatureStats(mPtr).isDead()) return true; else - MWBase::Environment::get().getMechanicsManager()->itemTaken(player, item.mBase, count); + MWBase::Environment::get().getMechanicsManager()->itemTaken(player, item.mBase, mPtr, count); } return true; } diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index ae7d60d44..5cb67c048 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -624,7 +624,7 @@ namespace MWGui throw std::runtime_error("Added item not found"); mDragAndDrop->startDrag(i, mSortModel, mTradeModel, mItemView, count); - MWBase::Environment::get().getMechanicsManager()->itemTaken(player, newObject, count); + MWBase::Environment::get().getMechanicsManager()->itemTaken(player, newObject, MWWorld::Ptr(), count); if (MWBase::Environment::get().getWindowManager()->getSpellWindow()) MWBase::Environment::get().getWindowManager()->getSpellWindow()->updateSpells(); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index d52dcb43c..caa242338 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -936,11 +936,29 @@ namespace MWMechanics commitCrime(ptr, victim, OT_Trespassing); } - void MechanicsManager::itemTaken(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item, int count) + void MechanicsManager::itemTaken(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item, const MWWorld::Ptr& container, + int count) { MWWorld::Ptr victim; - if (isAllowedToUse(ptr, item, victim)) - return; + + if (!container.isEmpty()) + { + // Inherit the owner of the container + if (isAllowedToUse(ptr, container, victim)) + return; + } + else + { + if (isAllowedToUse(ptr, item, victim)) + return; + + if (!item.getCellRef().hasContentFile()) + { + // this is a manually placed item, which means it was already stolen + return; + } + } + commitCrime(ptr, victim, OT_Theft, item.getClass().getValue(item) * count); } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 2f443ad59..79580c050 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -121,7 +121,9 @@ namespace MWMechanics /// @return false if the attack was considered a "friendly hit" and forgiven virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker); /// Utility to check if taking this item is illegal and calling commitCrime if so - virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, int count); + /// @param container The container the item is in; may be empty for an item in the world + virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container, + int count); /// Utility to check if opening (i.e. unlocking) this object is illegal and calling commitCrime if so virtual void objectOpened (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item); /// Attempt sleeping in a bed. If this is illegal, call commitCrime. diff --git a/apps/openmw/mwworld/actiontake.cpp b/apps/openmw/mwworld/actiontake.cpp index 548a94981..269d941dc 100644 --- a/apps/openmw/mwworld/actiontake.cpp +++ b/apps/openmw/mwworld/actiontake.cpp @@ -16,7 +16,7 @@ namespace MWWorld void ActionTake::executeImp (const Ptr& actor) { MWBase::Environment::get().getMechanicsManager()->itemTaken( - actor, getTarget(), getTarget().getRefData().getCount()); + actor, getTarget(), MWWorld::Ptr(), getTarget().getRefData().getCount()); actor.getClass().getContainerStore (actor).add (getTarget(), getTarget().getRefData().getCount(), actor); MWBase::Environment::get().getWorld()->deleteObject (getTarget()); } From 8087a7d920ebd20d63f0b820856a45e795b9ab2c Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Feb 2015 00:21:35 +0100 Subject: [PATCH 391/740] Add possibility to dress up corpses (Fixes #2221) --- apps/openmw/mwworld/inventorystore.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 4950be912..020f9561a 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -133,12 +133,11 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::add(const Ptr& itemPtr, const MWWorld::ContainerStoreIterator& retVal = MWWorld::ContainerStore::add(itemPtr, count, actorPtr, setOwner); // Auto-equip items if an armor/clothing or weapon item is added, but not for the player nor werewolves - if ((actorPtr.getRefData().getHandle() != "player") - && !(actorPtr.getClass().isNpc() && actorPtr.getClass().getNpcStats(actorPtr).isWerewolf()) - && !actorPtr.getClass().getCreatureStats(actorPtr).isDead()) + if (actorPtr.getRefData().getHandle() != "player" + && !(actorPtr.getClass().isNpc() && actorPtr.getClass().getNpcStats(actorPtr).isWerewolf())) { std::string type = itemPtr.getTypeName(); - if ((type == typeid(ESM::Armor).name()) || (type == typeid(ESM::Clothing).name()) || (type == typeid(ESM::Weapon).name())) + if (type == typeid(ESM::Armor).name() || type == typeid(ESM::Clothing).name()) autoEquip(actorPtr); } @@ -234,7 +233,9 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) // ...unless this is a companion, he should always equip items given to him. if (!Misc::StringUtils::ciEqual(test.getCellRef().getOwner(), actor.getCellRef().getRefId()) && (actor.getClass().getScript(actor).empty() || - !actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion"))) + !actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion")) + && !actor.getClass().getCreatureStats(actor).isDead() // Corpses can be dressed up by the player as desired + ) { continue; } @@ -506,8 +507,7 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor && !(actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf())) { std::string type = item.getTypeName(); - if (((type == typeid(ESM::Armor).name()) || (type == typeid(ESM::Clothing).name())) - && !actor.getClass().getCreatureStats(actor).isDead()) + if (type == typeid(ESM::Armor).name() || type == typeid(ESM::Clothing).name()) autoEquip(actor); } From f8b4ff300412344c652a104b8d77ecc7aa281b0f Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Feb 2015 01:25:37 +0100 Subject: [PATCH 392/740] Documentation fix --- components/terrain/quadtreenode.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/terrain/quadtreenode.hpp b/components/terrain/quadtreenode.hpp index 626572701..e8392b8e4 100644 --- a/components/terrain/quadtreenode.hpp +++ b/components/terrain/quadtreenode.hpp @@ -98,7 +98,6 @@ namespace Terrain DefaultWorld* getTerrain() { return mTerrain; } /// Adjust LODs for the given camera position, possibly splitting up chunks or merging them. - /// @param force Always choose to render this node, even if not the perfect LOD. /// @return Did we (or all of our children) choose to render? bool update (const Ogre::Vector3& cameraPos); @@ -124,7 +123,6 @@ namespace Terrain /// call this method on their children. /// @note Do not call this before World::areLayersLoaded() == true /// @param area area in image space to put the quad - /// @param quads collect quads here so they can be deleted later void prepareForCompositeMap(Ogre::TRect area); /// Create a chunk for this node from the given data. From c1862cbfc28063be922c98f39e2a7489596a7211 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Feb 2015 02:39:47 +0100 Subject: [PATCH 393/740] Clarify documentation for --load-savegame --- README.md | 4 +++- apps/openmw/main.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ed21b852f..9207c5728 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,9 @@ Command line options of the blacklist is enabled) --script-blacklist-use [=arg(=1)] (=1) enable script blacklisting - --load-savegame arg load a save game file on game startup + --load-savegame arg load a save game file on game startup + (specify an absolute or relative + filename for this option) --skip-menu [=arg(=1)] (=0) skip main menu on game startup --new-game [=arg(=1)] (=0) run new game sequence (ignored if skip-menu=0) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index b96b90989..f4875e68a 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -153,7 +153,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ->default_value(true), "enable script blacklisting") ("load-savegame", bpo::value()->default_value(""), - "load a save game file on game startup") + "load a save game file on game startup (specify an absolute or relative filename for this option)") ("skip-menu", bpo::value()->implicit_value(true) ->default_value(false), "skip main menu on game startup") From 9d9cabf40d1b6fd73c90db416de8c4b9bf980b87 Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 6 Feb 2015 12:24:06 +1300 Subject: [PATCH 394/740] Fix: Importer creates a single Content List (Fixes #2345) --- apps/launcher/datafilespage.cpp | 9 ++++++--- apps/launcher/datafilespage.hpp | 4 ++++ apps/launcher/settingspage.cpp | 22 +++++++++++++++++----- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index ff1364b08..7861894b0 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -20,6 +20,9 @@ #include "utils/textinputdialog.hpp" #include "utils/profilescombobox.hpp" + +const char *Launcher::DataFilesPage::mDefaultContentListName = "Default"; + Launcher::DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, Config::GameSettings &gameSettings, Config::LauncherSettings &launcherSettings, QWidget *parent) : mCfgMgr(cfg) , mGameSettings(gameSettings) @@ -48,9 +51,9 @@ void Launcher::DataFilesPage::buildView() ui.deleteProfileButton->setToolTip ("Delete an existing Content List"); //combo box - ui.profilesComboBox->addItem ("Default"); + ui.profilesComboBox->addItem(mDefaultContentListName); ui.profilesComboBox->setPlaceholderText (QString("Select a Content List...")); - ui.profilesComboBox->setCurrentIndex(ui.profilesComboBox->findText(QLatin1String("Default"))); + ui.profilesComboBox->setCurrentIndex(ui.profilesComboBox->findText(QLatin1String(mDefaultContentListName))); // Add the actions to the toolbuttons ui.newProfileButton->setDefaultAction (ui.newProfileAction); @@ -284,7 +287,7 @@ void Launcher::DataFilesPage::updateOkButton(const QString &text) void Launcher::DataFilesPage::checkForDefaultProfile() { //don't allow deleting "Default" profile - bool success = (ui.profilesComboBox->currentText() != "Default"); + bool success = (ui.profilesComboBox->currentText() != mDefaultContentListName); ui.deleteProfileAction->setEnabled (success); ui.profilesComboBox->setEditEnabled (success); diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index 73b840c5c..1e0fc8e7a 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -58,6 +58,10 @@ namespace Launcher void on_newProfileAction_triggered(); void on_deleteProfileAction_triggered(); + public: + /// Content List that is aways present + const static char *mDefaultContentListName; + private: TextInputDialog *mProfileDialog; diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index ace8f4310..88c60766b 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -11,6 +11,7 @@ #include #include "utils/textinputdialog.hpp" +#include "datafilespage.hpp" using namespace Process; @@ -198,22 +199,33 @@ void Launcher::SettingsPage::importerFinished(int exitCode, QProcess::ExitStatus if (exitCode != 0 || exitStatus == QProcess::CrashExit) return; - // Re-read the settings in their current state + // Importer may have changed settings, so refresh mMain->reloadSettings(); // Import selected data files from openmw.cfg if (addonsCheckBox->isChecked()) { + // Because we've reloaded settings, the current content list matches content in OpenMW.cfg + QString oldContentListName = mLauncherSettings.getCurrentContentListName(); if (mProfileDialog->exec() == QDialog::Accepted) { - const QString profile(mProfileDialog->lineEdit()->text()); + // remove the current content list to prevent duplication + //... except, not allowed to delete the Default content list + if (oldContentListName.compare(DataFilesPage::mDefaultContentListName) != 0) + { + mLauncherSettings.removeContentList(oldContentListName); + } + + const QString newContentListName(mProfileDialog->lineEdit()->text()); const QStringList files(mGameSettings.getContentList()); - mLauncherSettings.setCurrentContentListName(profile); - mLauncherSettings.setContentList(profile, files); + mLauncherSettings.setCurrentContentListName(newContentListName); + mLauncherSettings.setContentList(newContentListName, files); + + // Make DataFiles Page load the new content list. + mMain->reloadSettings(); } } - mMain->reloadSettings(); importerButton->setEnabled(true); } From cac250a90d213d33e0560b0b49da1b17c790bba0 Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 6 Feb 2015 12:45:15 +1300 Subject: [PATCH 395/740] Fixed typo in comment. --- apps/launcher/datafilespage.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index 1e0fc8e7a..d25d20fc9 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -59,7 +59,7 @@ namespace Launcher void on_deleteProfileAction_triggered(); public: - /// Content List that is aways present + /// Content List that is always present const static char *mDefaultContentListName; private: From bea88c3643b78ddf81dbb50a367688b2b16589f9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Feb 2015 21:18:43 +0100 Subject: [PATCH 396/740] Stolen item tracking overhaul part 2 (Fixes #2338) --- apps/openmw/mwbase/mechanicsmanager.hpp | 12 +- apps/openmw/mwclass/container.cpp | 9 +- apps/openmw/mwclass/creature.cpp | 5 +- apps/openmw/mwclass/npc.cpp | 6 +- apps/openmw/mwgui/enchantingdialog.cpp | 3 +- apps/openmw/mwgui/inventoryitemmodel.cpp | 11 +- apps/openmw/mwgui/itemmodel.hpp | 13 +- apps/openmw/mwgui/tooltips.cpp | 10 ++ apps/openmw/mwgui/tradeitemmodel.cpp | 4 +- apps/openmw/mwgui/tradewindow.cpp | 5 +- .../mwmechanics/mechanicsmanagerimp.cpp | 120 +++++++++++++++--- .../mwmechanics/mechanicsmanagerimp.hpp | 20 ++- apps/openmw/mwstate/statemanagerimp.cpp | 1 + apps/openmw/mwworld/cellref.cpp | 9 ++ apps/openmw/mwworld/cellref.hpp | 2 + apps/openmw/mwworld/class.hpp | 2 + apps/openmw/mwworld/containerstore.cpp | 53 ++++---- apps/openmw/mwworld/containerstore.hpp | 8 +- apps/openmw/mwworld/worldimp.cpp | 14 +- components/CMakeLists.txt | 2 +- components/esm/defs.hpp | 1 + components/esm/stolenitems.cpp | 47 +++++++ components/esm/stolenitems.hpp | 24 ++++ 23 files changed, 289 insertions(+), 92 deletions(-) create mode 100644 components/esm/stolenitems.cpp create mode 100644 components/esm/stolenitems.hpp diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 58f2f6ee5..f7fc515f5 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -138,9 +138,6 @@ namespace MWBase /// @return was it illegal, and someone saw you doing it? virtual bool sleepInBed (const MWWorld::Ptr& ptr, const MWWorld::Ptr& bed) = 0; - /// @return is \a ptr allowed to take/use \a item or is it a crime? - virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, MWWorld::Ptr& victim) = 0; - enum PersuasionType { PT_Admire, @@ -205,6 +202,15 @@ namespace MWBase virtual void keepPlayerAlive() = 0; virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const = 0; + + virtual void confiscateStolenItems (const MWWorld::Ptr& player, const MWWorld::Ptr& targetContainer) = 0; + + /// List the owners that the player has stolen this item from (the owner can be an NPC or a faction). + /// + virtual std::vector > getStolenItemOwners(const std::string& itemid) = 0; + + /// Has the player stolen this item from the given owner? + virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid) = 0; }; } diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index c6a7bbf74..5f49a74b6 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -59,8 +59,10 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); + // setting ownership not needed, since taking items from a container inherits the + // container's owner automatically data->mContainerStore.fill( - ref->mBase->mInventory, ptr.getCellRef().getOwner(), ptr.getCellRef().getFaction(), ptr.getCellRef().getFactionRank(), MWBase::Environment::get().getWorld()->getStore()); + ref->mBase->mInventory, ""); // store ptr.getRefData().setCustomData (data.release()); @@ -82,7 +84,10 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); const ESM::InventoryList& list = ref->mBase->mInventory; MWWorld::ContainerStore& store = getContainerStore(ptr); - store.restock(list, ptr, ptr.getCellRef().getOwner(), ptr.getCellRef().getFaction(), ptr.getCellRef().getFactionRank()); + + // setting ownership not needed, since taking items from a container inherits the + // container's owner automatically + store.restock(list, ptr, ""); } void Container::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index df3f9c0d3..e44f4ffc1 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -139,8 +139,7 @@ namespace MWClass // store ptr.getRefData().setCustomData(data.release()); - getContainerStore(ptr).fill(ref->mBase->mInventory, getId(ptr), "", -1, - MWBase::Environment::get().getWorld()->getStore()); + getContainerStore(ptr).fill(ref->mBase->mInventory, getId(ptr)); if (ref->mBase->mFlags & ESM::Creature::Weapon) getInventoryStore(ptr).autoEquip(ptr); @@ -886,7 +885,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); const ESM::InventoryList& list = ref->mBase->mInventory; MWWorld::ContainerStore& store = getContainerStore(ptr); - store.restock(list, ptr, ptr.getCellRef().getRefId(), "", -1); + store.restock(list, ptr, ptr.getCellRef().getRefId()); } int Creature::getBaseFightRating(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index c55f81d91..cedff1291 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -384,8 +384,8 @@ namespace MWClass } // inventory - data->mInventoryStore.fill(ref->mBase->mInventory, getId(ptr), "", -1, - MWBase::Environment::get().getWorld()->getStore()); + // setting ownership is used to make the NPC auto-equip his initial equipment only, and not bartered items + data->mInventoryStore.fill(ref->mBase->mInventory, getId(ptr)); data->mNpcStats.setGoldPool(gold); @@ -1328,7 +1328,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); const ESM::InventoryList& list = ref->mBase->mInventory; MWWorld::ContainerStore& store = getContainerStore(ptr); - store.restock(list, ptr, ptr.getCellRef().getRefId(), "", -1); + store.restock(list, ptr, ptr.getCellRef().getRefId()); } int Npc::getBaseFightRating (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 3376858c1..43f2493a9 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -339,7 +339,8 @@ namespace MWGui for (int i=0; i<2; ++i) { MWWorld::Ptr item = (i == 0) ? mEnchanting.getOldItem() : mEnchanting.getGem(); - if (Misc::StringUtils::ciEqual(item.getCellRef().getOwner(), mPtr.getCellRef().getRefId())) + if (MWBase::Environment::get().getMechanicsManager()->isItemStolenFrom(item.getCellRef().getRefId(), + mPtr.getCellRef().getRefId())) { std::string msg = MWBase::Environment::get().getWorld()->getStore().get().find("sNotifyMessage49")->getString(); if (msg.find("%s") != std::string::npos) diff --git a/apps/openmw/mwgui/inventoryitemmodel.cpp b/apps/openmw/mwgui/inventoryitemmodel.cpp index cee0dc6ee..e8354b740 100644 --- a/apps/openmw/mwgui/inventoryitemmodel.cpp +++ b/apps/openmw/mwgui/inventoryitemmodel.cpp @@ -65,16 +65,7 @@ MWWorld::Ptr InventoryItemModel::moveItem(const ItemStack &item, size_t count, I if (item.mFlags & ItemStack::Flag_Bound) return MWWorld::Ptr(); - bool setNewOwner = false; - - // Are you dead? Then you wont need that anymore - if (mActor.getClass().isActor() && mActor.getClass().getCreatureStats(mActor).isDead() - // Make sure that the item is actually owned by the dead actor - // Prevents a potential exploit for resetting the owner of any item, by placing the item in a corpse - && Misc::StringUtils::ciEqual(item.mBase.getCellRef().getOwner(), mActor.getCellRef().getRefId())) - setNewOwner = true; - - MWWorld::Ptr ret = otherModel->copyItem(item, count, setNewOwner); + MWWorld::Ptr ret = otherModel->copyItem(item, count, false); removeItem(item, count); return ret; } diff --git a/apps/openmw/mwgui/itemmodel.hpp b/apps/openmw/mwgui/itemmodel.hpp index c1b243a76..53c7018e2 100644 --- a/apps/openmw/mwgui/itemmodel.hpp +++ b/apps/openmw/mwgui/itemmodel.hpp @@ -46,20 +46,27 @@ namespace MWGui ItemModel(); virtual ~ItemModel() {} - typedef int ModelIndex; + typedef int ModelIndex; // -1 means invalid index + /// Throws for invalid index or out of range index virtual ItemStack getItem (ModelIndex index) = 0; - ///< throws for invalid index + + /// The number of items in the model, this specifies the range of indices you can pass to + /// the getItem function (but this range is only valid until the next call to update()) virtual size_t getItemCount() = 0; + /// Returns an invalid index if the item was not found virtual ModelIndex getIndex (ItemStack item) = 0; + /// Rebuild the item model, this will invalidate existing model indices virtual void update() = 0; /// Move items from this model to \a otherModel. + /// @note Derived implementations may return an empty Ptr if the move was unsuccessful. virtual MWWorld::Ptr moveItem (const ItemStack& item, size_t count, ItemModel* otherModel); - /// @param setNewOwner Set the copied item's owner to the actor we are copying to, or keep the original owner? + /// @param setNewOwner If true, set the copied item's owner to the actor we are copying to, + /// otherwise reset owner to "" virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false) = 0; virtual void removeItem (const ItemStack& item, size_t count) = 0; diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 275071737..c6210ac64 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -13,6 +13,7 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" @@ -586,6 +587,15 @@ namespace MWGui ret += getMiscString(cellref.getFaction(), "Faction"); if (cellref.getFactionRank() > 0) ret += getValueString(cellref.getFactionRank(), "Rank"); + + std::vector > itemOwners = + MWBase::Environment::get().getMechanicsManager()->getStolenItemOwners(cellref.getRefId()); + + for (std::vector >::const_iterator it = itemOwners.begin(); it != itemOwners.end(); ++it) + { + ret += std::string("\nStolen ") + MyGUI::utility::toString(it->second) + " from " + it->first; + } + ret += getMiscString(cellref.getGlobalVariable(), "Global"); return ret; } diff --git a/apps/openmw/mwgui/tradeitemmodel.cpp b/apps/openmw/mwgui/tradeitemmodel.cpp index df0cbcac9..a5a2b3e88 100644 --- a/apps/openmw/mwgui/tradeitemmodel.cpp +++ b/apps/openmw/mwgui/tradeitemmodel.cpp @@ -135,11 +135,9 @@ namespace MWGui if (i == sourceModel->getItemCount()) throw std::runtime_error("The borrowed item disappeared"); - // reset owner while copying, but only for items bought by the player - bool setNewOwner = (mMerchant.isEmpty()); const ItemStack& item = sourceModel->getItem(i); // copy the borrowed items to our model - copyItem(item, it->mCount, setNewOwner); + copyItem(item, it->mCount); // then remove them from the source model sourceModel->removeItem(item, it->mCount); } diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index fab7c63a6..87b2362ef 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -300,7 +300,8 @@ namespace MWGui // check if the player is attempting to sell back an item stolen from this actor for (std::vector::iterator it = merchantBought.begin(); it != merchantBought.end(); ++it) { - if (Misc::StringUtils::ciEqual(it->mBase.getCellRef().getOwner(), mPtr.getCellRef().getRefId())) + if (MWBase::Environment::get().getMechanicsManager()->isItemStolenFrom(it->mBase.getCellRef().getRefId(), + mPtr.getCellRef().getRefId())) { std::string msg = gmst.find("sNotifyMessage49")->getString(); if (msg.find("%s") != std::string::npos) @@ -315,6 +316,8 @@ namespace MWGui } } + // TODO: move to mwmechanics + // Is the player buying? bool buying = (mCurrentMerchantOffer < 0); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index caa242338..4e4a1a8a6 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -2,6 +2,8 @@ #include "mechanicsmanagerimp.hpp" #include "npcstats.hpp" +#include + #include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" @@ -873,31 +875,31 @@ namespace MWMechanics mAI = true; } - bool MechanicsManager::isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, MWWorld::Ptr& victim) + bool MechanicsManager::isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim) { - const std::string& owner = item.getCellRef().getOwner(); + const std::string& owner = cellref.getOwner(); bool isOwned = !owner.empty() && owner != "player"; - const std::string& faction = item.getCellRef().getFaction(); + const std::string& faction = cellref.getFaction(); bool isFactionOwned = false; if (!faction.empty() && ptr.getClass().isNpc()) { const std::map& factions = ptr.getClass().getNpcStats(ptr).getFactionRanks(); std::map::const_iterator found = factions.find(Misc::StringUtils::lowerCase(faction)); if (found == factions.end() - || found->second < item.getCellRef().getFactionRank()) + || found->second < cellref.getFactionRank()) isFactionOwned = true; } - const std::string& globalVariable = item.getCellRef().getGlobalVariable(); + const std::string& globalVariable = cellref.getGlobalVariable(); if (!globalVariable.empty() && MWBase::Environment::get().getWorld()->getGlobalInt(Misc::StringUtils::lowerCase(globalVariable)) == 1) { isOwned = false; isFactionOwned = false; } - if (!item.getCellRef().getOwner().empty()) - victim = MWBase::Environment::get().getWorld()->searchPtr(item.getCellRef().getOwner(), true); + if (!cellref.getOwner().empty()) + victim = MWBase::Environment::get().getWorld()->searchPtr(cellref.getOwner(), true); return (!isOwned && !isFactionOwned); } @@ -916,7 +918,7 @@ namespace MWMechanics } MWWorld::Ptr victim; - if (isAllowedToUse(ptr, bed, victim)) + if (isAllowedToUse(ptr, bed.getCellRef(), victim)) return false; if(commitCrime(ptr, victim, OT_SleepingInOwnedBed)) @@ -931,27 +933,82 @@ namespace MWMechanics void MechanicsManager::objectOpened(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item) { MWWorld::Ptr victim; - if (isAllowedToUse(ptr, item, victim)) + if (isAllowedToUse(ptr, item.getCellRef(), victim)) return; commitCrime(ptr, victim, OT_Trespassing); } + std::vector > MechanicsManager::getStolenItemOwners(const std::string& itemid) + { + std::vector > result; + StolenItemsMap::const_iterator it = mStolenItems.find(Misc::StringUtils::lowerCase(itemid)); + if (it == mStolenItems.end()) + return result; + else + { + const OwnerMap& owners = it->second; + for (OwnerMap::const_iterator ownerIt = owners.begin(); ownerIt != owners.end(); ++ownerIt) + result.push_back(std::make_pair(ownerIt->first.first, ownerIt->second)); + return result; + } + } + + bool MechanicsManager::isItemStolenFrom(const std::string &itemid, const std::string &ownerid) + { + StolenItemsMap::const_iterator it = mStolenItems.find(Misc::StringUtils::lowerCase(itemid)); + if (it == mStolenItems.end()) + return false; + const OwnerMap& owners = it->second; + OwnerMap::const_iterator ownerFound = owners.find(std::make_pair(Misc::StringUtils::lowerCase(ownerid), false)); + return ownerFound != owners.end(); + } + + void MechanicsManager::confiscateStolenItems(const MWWorld::Ptr &player, const MWWorld::Ptr &targetContainer) + { + MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); + for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) + { + StolenItemsMap::iterator stolenIt = mStolenItems.find(Misc::StringUtils::lowerCase(it->getClass().getId(*it))); + if (stolenIt == mStolenItems.end()) + continue; + OwnerMap& owners = stolenIt->second; + int itemCount = it->getRefData().getCount(); + for (OwnerMap::iterator ownerIt = owners.begin(); ownerIt != owners.end();) + { + int toRemove = std::min(itemCount, ownerIt->second); + itemCount -= toRemove; + ownerIt->second -= toRemove; + if (ownerIt->second == 0) + owners.erase(ownerIt++); + else + ++ownerIt; + } + + int toMove = it->getRefData().getCount() - itemCount; + + targetContainer.getClass().getContainerStore(targetContainer).add(*it, toMove, targetContainer); + store.remove(*it, toMove, player); + } + // TODO: unhardcode the locklevel + targetContainer.getClass().lock(targetContainer,50); + } + void MechanicsManager::itemTaken(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item, const MWWorld::Ptr& container, int count) { + if (ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) + return; + MWWorld::Ptr victim; + const MWWorld::CellRef* ownerCellRef = &item.getCellRef(); if (!container.isEmpty()) { // Inherit the owner of the container - if (isAllowedToUse(ptr, container, victim)) - return; + ownerCellRef = &container.getCellRef(); } else { - if (isAllowedToUse(ptr, item, victim)) - return; - if (!item.getCellRef().hasContentFile()) { // this is a manually placed item, which means it was already stolen @@ -959,6 +1016,20 @@ namespace MWMechanics } } + if (isAllowedToUse(ptr, *ownerCellRef, victim)) + return; + + Owner owner; + owner.first = ownerCellRef->getOwner(); + owner.second = false; + if (owner.first.empty()) + { + owner.first = ownerCellRef->getFaction(); + owner.second = true; + } + Misc::StringUtils::toLower(owner.first); + mStolenItems[Misc::StringUtils::lowerCase(item.getClass().getId(item))][owner] += count; + commitCrime(ptr, victim, OT_Theft, item.getClass().getValue(item) * count); } @@ -967,7 +1038,7 @@ namespace MWMechanics // NOTE: victim may be empty // Only player can commit crime - if (player.getRefData().getHandle() != "player") + if (player != MWBase::Environment::get().getWorld()->getPlayerPtr()) return false; // Find all the actors within the alarm radius @@ -1369,22 +1440,37 @@ namespace MWMechanics int MechanicsManager::countSavedGameRecords() const { - return 1; // Death counter + return 1 // Death counter + +1; // Stolen items } void MechanicsManager::write(ESM::ESMWriter &writer, Loading::Listener &listener) const { mActors.write(writer, listener); + + ESM::StolenItems items; + items.mStolenItems = mStolenItems; + writer.startRecord(ESM::REC_STLN); + items.write(writer); + writer.endRecord(ESM::REC_STLN); } void MechanicsManager::readRecord(ESM::ESMReader &reader, uint32_t type) { - mActors.readRecord(reader, type); + if (type == ESM::REC_STLN) + { + ESM::StolenItems items; + items.load(reader); + mStolenItems = items.mStolenItems; + } + else + mActors.readRecord(reader, type); } void MechanicsManager::clear() { mActors.clear(); + mStolenItems.clear(); } bool MechanicsManager::isAggressive(const MWWorld::Ptr &ptr, const MWWorld::Ptr &target) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 79580c050..d08334ae8 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -35,6 +35,11 @@ namespace MWMechanics Objects mObjects; Actors mActors; + typedef std::pair Owner; // < Owner id, bool isFaction > + typedef std::map OwnerMap; // < Owner, number of stolen items with this id from this owner > + typedef std::map StolenItemsMap; + StolenItemsMap mStolenItems; + public: void buildPlayer(); @@ -130,9 +135,6 @@ namespace MWMechanics /// @return was it illegal, and someone saw you doing it? Also returns fail when enemies are nearby virtual bool sleepInBed (const MWWorld::Ptr& ptr, const MWWorld::Ptr& bed); - /// @return is \a ptr allowed to take/use \a item or is it a crime? - virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, MWWorld::Ptr& victim); - virtual void forceStateUpdate(const MWWorld::Ptr &ptr); virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); @@ -170,9 +172,21 @@ namespace MWMechanics virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const; + virtual void confiscateStolenItems (const MWWorld::Ptr& player, const MWWorld::Ptr& targetContainer); + + /// List the owners that the player has stolen this item from (the owner can be an NPC or a faction). + /// + virtual std::vector > getStolenItemOwners(const std::string& itemid); + + /// Has the player stolen this item from the given owner? + virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid); + private: void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, OffenseType type, int arg=0); + + /// @return is \a ptr allowed to take/use \a cellref or is it a crime? + virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim); }; } diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index d623ba465..0883bc63b 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -421,6 +421,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::str break; case ESM::REC_DCOU: + case ESM::REC_STLN: MWBase::Environment::get().getMechanicsManager()->readRecord(reader, n.val); break; diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index d2cced3b8..0d81e0636 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -117,6 +117,15 @@ namespace MWWorld return mCellRef.mGlobalVariable; } + void CellRef::resetGlobalVariable() + { + if (!mCellRef.mGlobalVariable.empty()) + { + mChanged = true; + mCellRef.mGlobalVariable.erase(); + } + } + void CellRef::setFactionRank(int factionRank) { if (factionRank != mCellRef.mFactionRank) diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index f063b2727..b8e85f286 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -75,6 +75,8 @@ namespace MWWorld // Used by bed rent scripts to allow the player to use the bed for the duration of the rent. std::string getGlobalVariable() const; + void resetGlobalVariable(); + // ID of creature trapped in this soul gem std::string getSoul() const; void setSoul(const std::string& soul); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 751375c55..380d2a34b 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -80,6 +80,8 @@ namespace MWWorld virtual std::string getId (const Ptr& ptr) const; ///< Return ID of \a ptr or throw an exception, if class does not support ID retrieval /// (default implementation: throw an exception) + /// @note This function is currently redundant; the same ID can be retrieved by CellRef::getRefId. + /// Leaving it here for now in case we want to optimize later. virtual void insertObjectRendering (const Ptr& ptr, const std::string& mesh, MWRender::RenderingInterface& renderingInterface) const; virtual void insertObject(const Ptr& ptr, const std::string& mesh, MWWorld::PhysicsSystem& physics) const; diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index b21486c2c..c2906e447 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -222,29 +222,22 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr MWWorld::ContainerStoreIterator it = end(); - if (setOwner && actorPtr.getClass().isActor()) + // HACK: Set owner on the original item, then reset it after we have copied it + // If we set the owner on the copied item, it would not stack correctly... + std::string oldOwner = itemPtr.getCellRef().getOwner(); + if (!setOwner || actorPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) // No point in setting owner to the player - NPCs will not respect this anyway { - // HACK: Set owner on the original item, then reset it after we have copied it - // If we set the owner on the copied item, it would not stack correctly... - std::string oldOwner = itemPtr.getCellRef().getOwner(); - if (actorPtr == player) - { - // No point in setting owner to the player - NPCs will not respect this anyway - // Additionally, setting it to "player" would make those items not stack with items that don't have an owner - itemPtr.getCellRef().setOwner(""); - } - else - itemPtr.getCellRef().setOwner(actorPtr.getCellRef().getRefId()); - - it = addImp(itemPtr, count); - - itemPtr.getCellRef().setOwner(oldOwner); + itemPtr.getCellRef().setOwner(""); } else { - it = addImp(itemPtr, count); + itemPtr.getCellRef().setOwner(actorPtr.getCellRef().getRefId()); } + it = addImp(itemPtr, count); + + itemPtr.getCellRef().setOwner(oldOwner); + // The copy of the original item we just made MWWorld::Ptr item = *it; @@ -258,6 +251,14 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr pos.pos[1] = 0; pos.pos[2] = 0; item.getCellRef().setPosition(pos); + + // reset ownership stuff, owner was already handled above + item.getCellRef().resetGlobalVariable(); + item.getCellRef().setFaction(""); + item.getCellRef().setFactionRank(-1); + + // must reset the RefNum on the copied item, so that the RefNum on the original item stays unique + // maybe we should do this in the copy constructor instead? item.getCellRef().unsetRefNum(); // destroy link to content file std::string script = item.getClass().getScript(item); @@ -399,19 +400,19 @@ int MWWorld::ContainerStore::remove(const Ptr& item, int count, const Ptr& actor return count - toRemove; } -void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const std::string& owner, const std::string& faction, int factionRank, const MWWorld::ESMStore& store) +void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const std::string& owner) { for (std::vector::const_iterator iter (items.mList.begin()); iter!=items.mList.end(); ++iter) { std::string id = Misc::StringUtils::lowerCase(iter->mItem.toString()); - addInitialItem(id, owner, faction, factionRank, iter->mCount); + addInitialItem(id, owner, iter->mCount); } flagAsModified(); } -void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::string& owner, const std::string& faction, int factionRank, +void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::string& owner, int count, bool topLevel, const std::string& levItem) { ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id, count); @@ -423,7 +424,7 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std:: if (topLevel && std::abs(count) > 1 && levItem->mFlags & ESM::ItemLevList::Each) { for (int i=0; i 0 ? 1 : -1, true, levItem->mId); + addInitialItem(id, owner, count > 0 ? 1 : -1, true, levItem->mId); return; } else @@ -431,7 +432,7 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std:: std::string id = MWMechanics::getLevelledItem(ref.getPtr().get()->mBase, false); if (id.empty()) return; - addInitialItem(id, owner, faction, factionRank, count, false, levItem->mId); + addInitialItem(id, owner, count, false, levItem->mId); } } else @@ -447,13 +448,11 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std:: count = std::abs(count); ref.getPtr().getCellRef().setOwner(owner); - ref.getPtr().getCellRef().setFaction(faction); - ref.getPtr().getCellRef().setFactionRank(factionRank); addImp (ref.getPtr(), count); } } -void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner, const std::string& faction, int factionRank) +void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner) { // Remove the items already spawned by levelled items that will restock for (std::map::iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it) @@ -472,13 +471,13 @@ void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MW if (MWBase::Environment::get().getWorld()->getStore().get().search(it->mItem.toString())) { - addInitialItem(item, owner, faction, factionRank, it->mCount, true); + addInitialItem(item, owner, it->mCount, true); } else { int currentCount = count(item); if (currentCount < std::abs(it->mCount)) - addInitialItem(item, owner, faction, factionRank, std::abs(it->mCount) - currentCount, true); + addInitialItem(item, owner, std::abs(it->mCount) - currentCount, true); } } flagAsModified(); diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index d909a98cc..e9750a622 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -75,7 +75,7 @@ namespace MWWorld mutable float mCachedWeight; mutable bool mWeightUpToDate; ContainerStoreIterator addImp (const Ptr& ptr, int count); - void addInitialItem (const std::string& id, const std::string& owner, const std::string& faction, int factionRank, int count, bool topLevel=true, const std::string& levItem = ""); + void addInitialItem (const std::string& id, const std::string& owner, int count, bool topLevel=true, const std::string& levItem = ""); template ContainerStoreIterator getState (CellRefList& collection, @@ -112,7 +112,7 @@ namespace MWWorld /// \attention Do not add items to an existing stack by increasing the count instead of /// calling this function! /// - /// @param setOwner Set the owner of the added item to \a actorPtr? + /// @param setOwner Set the owner of the added item to \a actorPtr? If false, the owner is reset to "". /// /// @return if stacking happened, return iterator to the item that was stacked against, otherwise iterator to the newly inserted item. @@ -151,10 +151,10 @@ namespace MWWorld virtual bool stacks (const Ptr& ptr1, const Ptr& ptr2); ///< @return true if the two specified objects can stack with each other - void fill (const ESM::InventoryList& items, const std::string& owner, const std::string& faction, int factionRank, const MWWorld::ESMStore& store); + void fill (const ESM::InventoryList& items, const std::string& owner); ///< Insert items into *this. - void restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner, const std::string& faction, int factionRank); + void restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner); virtual void clear(); ///< Empty container. diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1036d8ce6..933a1fa42 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2980,18 +2980,10 @@ namespace MWWorld if (!closestChest.isEmpty()) //Found a close chest { - ContainerStore& store = ptr.getClass().getContainerStore(ptr); - for (ContainerStoreIterator it = store.begin(); it != store.end(); ++it) //Move all stolen stuff into chest - { - MWWorld::Ptr dummy; - if (!MWBase::Environment::get().getMechanicsManager()->isAllowedToUse(getPlayerPtr(), *it, dummy)) - { - closestChest.getClass().getContainerStore(closestChest).add(*it, it->getRefData().getCount(), closestChest); - store.remove(*it, it->getRefData().getCount(), ptr); - } - } - closestChest.getClass().lock(closestChest,50); + MWBase::Environment::get().getMechanicsManager()->confiscateStolenItems(ptr, closestChest); } + else + std::cerr << "Failed to confiscate items: no stolen_goods container found" << std::endl; } void World::goToJail() diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 814dde6a2..6f8352ddb 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -63,7 +63,7 @@ add_component_dir (esm loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap inventorystate containerstate npcstate creaturestate dialoguestate statstate npcstats creaturestats weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate debugprofile - aisequence magiceffects util custommarkerstate + aisequence magiceffects util custommarkerstate stolenitems ) add_component_dir (esmterrain diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index 60926d562..7ef8102c2 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -117,6 +117,7 @@ enum RecNameInts REC_MARK = FourCC<'M','A','R','K'>::value, REC_ENAB = FourCC<'E','N','A','B'>::value, REC_CAM_ = FourCC<'C','A','M','_'>::value, + REC_STLN = FourCC<'S','T','L','N'>::value, // format 1 REC_FILT = FourCC<'F','I','L','T'>::value, diff --git a/components/esm/stolenitems.cpp b/components/esm/stolenitems.cpp new file mode 100644 index 000000000..c51b0b99b --- /dev/null +++ b/components/esm/stolenitems.cpp @@ -0,0 +1,47 @@ +#include "stolenitems.hpp" + +#include +#include + +namespace ESM +{ + + void StolenItems::write(ESMWriter &esm) const + { + for (StolenItemsMap::const_iterator it = mStolenItems.begin(); it != mStolenItems.end(); ++it) + { + esm.writeHNString("NAME", it->first); + for (std::map, int>::const_iterator ownerIt = it->second.begin(); + ownerIt != it->second.end(); ++ownerIt) + { + if (ownerIt->first.second) + esm.writeHNString("FNAM", ownerIt->first.first); + else + esm.writeHNString("ONAM", ownerIt->first.first); + esm.writeHNT("COUN", ownerIt->second); + } + } + } + + void StolenItems::load(ESMReader &esm) + { + while (esm.isNextSub("NAME")) + { + std::string itemid = esm.getHString(); + + std::map, int> ownerMap; + while (esm.isNextSub("FNAM") || esm.isNextSub("ONAM")) + { + std::string subname = esm.retSubName().toString(); + std::string owner = esm.getHString(); + bool isFaction = (subname == "FNAM"); + int count; + esm.getHNT(count, "COUN"); + ownerMap.insert(std::make_pair(std::make_pair(owner, isFaction), count)); + } + + mStolenItems[itemid] = ownerMap; + } + } + +} diff --git a/components/esm/stolenitems.hpp b/components/esm/stolenitems.hpp new file mode 100644 index 000000000..928fbbf75 --- /dev/null +++ b/components/esm/stolenitems.hpp @@ -0,0 +1,24 @@ +#ifndef OPENMW_COMPONENTS_ESM_STOLENITEMS_H +#define OPENMW_COMPONENTS_ESM_STOLENITEMS_H + +#include +#include + +namespace ESM +{ + class ESMReader; + class ESMWriter; + + // format 0, saved games only + struct StolenItems + { + typedef std::map, int> > StolenItemsMap; + StolenItemsMap mStolenItems; + + void load(ESM::ESMReader& esm); + void write(ESM::ESMWriter& esm) const; + }; + +} + +#endif From 356d1c7657124ccad4987a78fb0672e379909070 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Feb 2015 22:10:58 +0100 Subject: [PATCH 397/740] ESSImport: convert stolen item tracker --- apps/essimporter/converter.hpp | 35 ++++++++++++++++++++++++++++++---- apps/openmw/mwgui/tooltips.cpp | 2 +- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 775995605..c23083f8e 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -18,6 +18,7 @@ #include #include #include +#include #include "importcrec.hpp" #include "importcntc.hpp" @@ -387,24 +388,50 @@ public: virtual void read(ESM::ESMReader &esm) { std::string itemid = esm.getHNString("NAME"); + Misc::StringUtils::toLower(itemid); while (esm.isNextSub("FNAM") || esm.isNextSub("ONAM")) { if (esm.retSubName().toString() == "FNAM") { std::string factionid = esm.getHString(); - mFactionStolenItems.insert(std::make_pair(itemid, factionid)); + mStolenItems[itemid].insert(std::make_pair(Misc::StringUtils::lowerCase(factionid), true)); } else { std::string ownerid = esm.getHString(); - mStolenItems.insert(std::make_pair(itemid, ownerid)); + mStolenItems[itemid].insert(std::make_pair(Misc::StringUtils::lowerCase(ownerid), false)); } } } + virtual void write(ESM::ESMWriter &esm) + { + ESM::StolenItems items; + for (std::map >::const_iterator it = mStolenItems.begin(); it != mStolenItems.end(); ++it) + { + std::map, int> owners; + for (std::set::const_iterator ownerIt = it->second.begin(); ownerIt != it->second.end(); ++ownerIt) + { + owners.insert(std::make_pair(std::make_pair(ownerIt->first, ownerIt->second) + // Since OpenMW doesn't suffer from the owner contamination bug, + // it needs a count argument. But for legacy savegames, we don't know + // this count, so must assume all items of that ID are stolen, + // like vanilla MW did. + ,std::numeric_limits::max())); + } + + items.mStolenItems.insert(std::make_pair(it->first, owners)); + } + + esm.startRecord(ESM::REC_STLN); + items.write(esm); + esm.endRecord(ESM::REC_STLN); + } + private: - std::multimap mStolenItems; - std::multimap mFactionStolenItems; + typedef std::pair Owner; // + + std::map > mStolenItems; }; /// Seen responses for a dialogue topic? diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index c6210ac64..2c10004a6 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -593,7 +593,7 @@ namespace MWGui for (std::vector >::const_iterator it = itemOwners.begin(); it != itemOwners.end(); ++it) { - ret += std::string("\nStolen ") + MyGUI::utility::toString(it->second) + " from " + it->first; + ret += std::string("\nStolen from ") + it->first; } ret += getMiscString(cellref.getGlobalVariable(), "Global"); From dd8aab2a7ff2597d1665dfefc2d2773a2fa71d23 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Feb 2015 22:17:30 +0100 Subject: [PATCH 398/740] Adjust help for --load-savegame again --- README.md | 5 +++-- apps/openmw/main.cpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9207c5728..63a313896 100644 --- a/README.md +++ b/README.md @@ -69,8 +69,9 @@ Command line options --script-blacklist-use [=arg(=1)] (=1) enable script blacklisting --load-savegame arg load a save game file on game startup - (specify an absolute or relative - filename for this option) + (specify an absolute filename or a + filename relative to the current + working directory) --skip-menu [=arg(=1)] (=0) skip main menu on game startup --new-game [=arg(=1)] (=0) run new game sequence (ignored if skip-menu=0) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index f4875e68a..475fe63a2 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -153,7 +153,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ->default_value(true), "enable script blacklisting") ("load-savegame", bpo::value()->default_value(""), - "load a save game file on game startup (specify an absolute or relative filename for this option)") + "load a save game file on game startup (specify an absolute filename or a filename relative to the current working directory)") ("skip-menu", bpo::value()->implicit_value(true) ->default_value(false), "skip main menu on game startup") From ae77eacd7ea5f3ef5766138178d73345256f2b6e Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Feb 2015 23:15:12 +0100 Subject: [PATCH 399/740] Skill progress refactoring --- apps/openmw/mwgui/statswindow.cpp | 6 ++- apps/openmw/mwmechanics/npcstats.cpp | 54 +++++++++++------------- apps/openmw/mwmechanics/npcstats.hpp | 6 +-- apps/openmw/mwscript/statsextensions.cpp | 17 -------- 4 files changed, 31 insertions(+), 52 deletions(-) diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index a407aedc7..f624d751d 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -383,11 +383,15 @@ namespace MWGui const MWMechanics::SkillValue &stat = mSkillValues.find(skillId)->second; int base = stat.getBase(); int modified = stat.getModified(); - int progressPercent = stat.getProgress() * 100; + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); const MWWorld::ESMStore &esmStore = MWBase::Environment::get().getWorld()->getStore(); + int progressRequirement = player.getClass().getNpcStats(player).getSkillProgressRequirement(skillId, + *esmStore.get().find(player.get()->mBase->mClass)); + int progressPercent = int(int(stat.getProgress()) / float(progressRequirement) * 100.f); + const ESM::Skill* skill = esmStore.get().find(skillId); std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId]; diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 7219d6185..bd1cd5572 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -125,32 +125,9 @@ bool MWMechanics::NpcStats::isInFaction (const std::string& faction) const return (mFactionRank.find(Misc::StringUtils::lowerCase(faction)) != mFactionRank.end()); } -float MWMechanics::NpcStats::getSkillGain (int skillIndex, const ESM::Class& class_, int usageType, - int level, float extraFactor) const +float MWMechanics::NpcStats::getSkillProgressRequirement (int skillIndex, const ESM::Class& class_) const { - if (level<0) - level = static_cast (getSkill (skillIndex).getBase()); - - const ESM::Skill *skill = - MWBase::Environment::get().getWorld()->getStore().get().find (skillIndex); - - float skillFactor = 1; - - if (usageType>=4) - throw std::runtime_error ("skill usage type out of range"); - - if (usageType>=0) - { - skillFactor = skill->mData.mUseValue[usageType]; - - if (skillFactor<0) - throw std::runtime_error ("invalid skill gain factor"); - - if (skillFactor==0) - return 0; - } - - skillFactor *= extraFactor; + float progressRequirement = 1 + getSkill (skillIndex).getBase(); const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); @@ -173,11 +150,15 @@ float MWMechanics::NpcStats::getSkillGain (int skillIndex, const ESM::Class& cla break; } + progressRequirement *= typeFactor; + if (typeFactor<=0) throw std::runtime_error ("invalid skill type factor"); float specialisationFactor = 1; + const ESM::Skill *skill = + MWBase::Environment::get().getWorld()->getStore().get().find (skillIndex); if (skill->mData.mSpecialization==class_.mData.mSpecialization) { specialisationFactor = gmst.find ("fSpecialSkillBonus")->getFloat(); @@ -185,7 +166,9 @@ float MWMechanics::NpcStats::getSkillGain (int skillIndex, const ESM::Class& cla if (specialisationFactor<=0) throw std::runtime_error ("invalid skill specialisation factor"); } - return 1.0 / ((level+1) * (1.0/skillFactor) * typeFactor * specialisationFactor); + progressRequirement *= specialisationFactor; + + return progressRequirement; } void MWMechanics::NpcStats::useSkill (int skillIndex, const ESM::Class& class_, int usageType, float extraFactor) @@ -194,11 +177,24 @@ void MWMechanics::NpcStats::useSkill (int skillIndex, const ESM::Class& class_, if(mIsWerewolf) return; + const ESM::Skill *skill = + MWBase::Environment::get().getWorld()->getStore().get().find (skillIndex); + float skillGain = 1; + if (usageType>=4) + throw std::runtime_error ("skill usage type out of range"); + if (usageType>=0) + { + skillGain = skill->mData.mUseValue[usageType]; + if (skillGain<0) + throw std::runtime_error ("invalid skill gain factor"); + } + skillGain *= extraFactor; + MWMechanics::SkillValue& value = getSkill (skillIndex); - value.setProgress(value.getProgress() + getSkillGain (skillIndex, class_, usageType, -1, extraFactor)); + value.setProgress(value.getProgress() + skillGain); - if (value.getProgress()>=1) + if (int(value.getProgress())>=int(getSkillProgressRequirement(skillIndex, class_))) { // skill levelled up increaseSkill(skillIndex, class_, false); @@ -256,7 +252,7 @@ void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &clas MWBase::Environment::get().getWindowManager ()->messageBox ("#{sLevelUpMsg}", MWGui::ShowInDialogueMode_Never); } - getSkill (skillIndex).setBase (base); + getSkill(skillIndex).setBase (base); if (!preserveProgress) getSkill(skillIndex).setProgress(0); } diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index fc4f297db..1cb62276f 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -74,11 +74,7 @@ namespace MWMechanics bool isInFaction (const std::string& faction) const; - float getSkillGain (int skillIndex, const ESM::Class& class_, int usageType = -1, - int level = -1, float extraFactor=1.f) const; - ///< \param usageType: Usage specific factor, specified in the respective skill record; - /// -1: use a factor of 1.0 instead. - /// \param level Level to base calculation on; -1: use current level. + float getSkillProgressRequirement (int skillIndex, const ESM::Class& class_) const; void useSkill (int skillIndex, const ESM::Class& class_, int usageType = -1, float extraFactor=1.f); ///< Increase skill by usage. diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index f0cf12e5e..abef636cc 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -348,29 +348,12 @@ namespace MWScript MWMechanics::NpcStats& stats = ptr.getClass().getNpcStats (ptr); - MWWorld::LiveCellRef *ref = ptr.get(); - - assert (ref); - - const ESM::Class& class_ = - *MWBase::Environment::get().getWorld()->getStore().get().find (ref->mBase->mClass); - - float level = stats.getSkill(mIndex).getBase(); - float progress = stats.getSkill(mIndex).getProgress(); - int newLevel = value - (stats.getSkill(mIndex).getModified() - stats.getSkill(mIndex).getBase()); if (newLevel<0) newLevel = 0; - progress = (progress / stats.getSkillGain (mIndex, class_, -1, level)) - * stats.getSkillGain (mIndex, class_, -1, newLevel); - - if (progress>=1) - progress = 0.999999999; - stats.getSkill (mIndex).setBase (newLevel); - stats.getSkill (mIndex).setProgress(progress); } }; From f0b1d889c0f9f054207b07194f583f6a355d336e Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Feb 2015 23:24:49 +0100 Subject: [PATCH 400/740] ESSImport: import player skill progress --- apps/essimporter/convertplayer.cpp | 5 ++--- apps/openmw/mwmechanics/npcstats.hpp | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/essimporter/convertplayer.cpp b/apps/essimporter/convertplayer.cpp index ef22660f5..532efa7f5 100644 --- a/apps/essimporter/convertplayer.cpp +++ b/apps/essimporter/convertplayer.cpp @@ -17,6 +17,8 @@ namespace ESSImport } for (int i=0; i<8; ++i) out.mObject.mNpcStats.mSkillIncrease[i] = pcdt.mPNAM.mSkillIncreases[i]; + for (int i=0; i<27; ++i) + out.mObject.mNpcStats.mSkills[i].mRegular.mProgress = pcdt.mPNAM.mSkillProgress[i]; out.mObject.mNpcStats.mLevelProgress = pcdt.mPNAM.mLevelProgress; if (pcdt.mPNAM.mDrawState & PCDT::DrawState_Weapon) @@ -24,9 +26,6 @@ namespace ESSImport if (pcdt.mPNAM.mDrawState & PCDT::DrawState_Spell) out.mObject.mCreatureStats.mDrawState = 2; - // TODO: convert PNAM.mSkillProgress, needs to be converted to uniform scale - // (or change openmw to accept non-uniform skill progress) - firstPersonCam = (pcdt.mPNAM.mCameraState == PCDT::CameraState_FirstPerson); for (std::vector::const_iterator it = pcdt.mKnownDialogueTopics.begin(); diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index 1cb62276f..224366a3e 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -23,7 +23,7 @@ namespace MWMechanics class NpcStats : public CreatureStats { int mDisposition; - SkillValue mSkill[ESM::Skill::Length]; + SkillValue mSkill[ESM::Skill::Length]; // SkillValue.mProgress used by the player only SkillValue mWerewolfSkill[ESM::Skill::Length]; int mReputation; int mCrimeId; From 5096e5dc0c1cadad9d9b14ec9175a30e210411e6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Feb 2015 23:45:01 +0100 Subject: [PATCH 401/740] esmtool minor/major skills fix --- apps/esmtool/record.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index e167278f3..97b0635fe 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -535,10 +535,10 @@ void Record::print() std::cout << " Specialization: " << specializationLabel(mData.mData.mSpecialization) << " (" << mData.mData.mSpecialization << ")" << std::endl; for (int i = 0; i != 5; i++) - std::cout << " Major Skill: " << skillLabel(mData.mData.mSkills[i][0]) + std::cout << " Minor Skill: " << skillLabel(mData.mData.mSkills[i][0]) << " (" << mData.mData.mSkills[i][0] << ")" << std::endl; for (int i = 0; i != 5; i++) - std::cout << " Minor Skill: " << skillLabel(mData.mData.mSkills[i][1]) + std::cout << " Major Skill: " << skillLabel(mData.mData.mSkills[i][1]) << " (" << mData.mData.mSkills[i][1] << ")" << std::endl; } From 55cd9b526c93a44e22ccd784df93e590c61b1b04 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Feb 2015 00:56:32 +0100 Subject: [PATCH 402/740] Skill progress bar changed to match MW --- apps/essimporter/importacdt.hpp | 2 +- apps/openmw/mwgui/statswindow.cpp | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/apps/essimporter/importacdt.hpp b/apps/essimporter/importacdt.hpp index 1e0317049..47055092d 100644 --- a/apps/essimporter/importacdt.hpp +++ b/apps/essimporter/importacdt.hpp @@ -61,7 +61,7 @@ namespace ESSImport bool mHasACSC; ACSC mACSC; - int mSkills[27][2]; + int mSkills[27][2]; // skills, base and modified // creature combat stats, base and modified // I think these can be ignored in the conversion, because it is not possible diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index f624d751d..2a22f4239 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -376,9 +376,8 @@ namespace MWGui for (SkillList::const_iterator it = skills.begin(); it != end; ++it) { int skillId = *it; - if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes + if (skillId < 0 || skillId >= ESM::Skill::Length) // Skip unknown skill indexes continue; - assert(skillId >= 0 && skillId < ESM::Skill::Length); const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; const MWMechanics::SkillValue &stat = mSkillValues.find(skillId)->second; int base = stat.getBase(); @@ -388,9 +387,14 @@ namespace MWGui const MWWorld::ESMStore &esmStore = MWBase::Environment::get().getWorld()->getStore(); - int progressRequirement = player.getClass().getNpcStats(player).getSkillProgressRequirement(skillId, + float progressRequirement = player.getClass().getNpcStats(player).getSkillProgressRequirement(skillId, *esmStore.get().find(player.get()->mBase->mClass)); - int progressPercent = int(int(stat.getProgress()) / float(progressRequirement) * 100.f); + + // This is how vanilla MW displays the progress bar (I think). Note it's slightly inaccurate, + // due to the int casting in the skill levelup logic. Also the progress label could in rare cases + // reach 100% without the skill levelling up. + // Leaving the original display logic for now, for consistency with ess-imported savegames. + int progressPercent = int(float(stat.getProgress()) / float(progressRequirement) * 100.f + 0.5f); const ESM::Skill* skill = esmStore.get().find(skillId); From b5e0e45c78716e37dbeeaebb49c3d198a71ef140 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Feb 2015 01:03:10 +0100 Subject: [PATCH 403/740] Fix iLevelUpTotal not being used in the levelUp logic --- apps/openmw/mwmechanics/npcstats.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index bd1cd5572..9d3d967b9 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -264,13 +264,14 @@ int MWMechanics::NpcStats::getLevelProgress () const void MWMechanics::NpcStats::levelUp() { - mLevelProgress -= 10; - for (int i=0; i &gmst = MWBase::Environment::get().getWorld()->getStore().get(); + mLevelProgress -= gmst.find("iLevelUpTotal")->getInt(); + + for (int i=0; i Date: Thu, 5 Feb 2015 01:08:26 +0100 Subject: [PATCH 404/740] Cap the displayed attribute multiplier in levelup to attribute points left to 100 --- apps/openmw/mwgui/levelupdialog.cpp | 1 + apps/openmw/mwmechanics/npcstats.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index 8553811aa..6759824f9 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -176,6 +176,7 @@ namespace MWGui availableAttributes++; int mult = pcStats.getLevelupAttributeMultiplier (i); + mult = std::min(mult, 100-pcStats.getAttribute(i).getBase()); text->setCaption(mult <= 1 ? "" : "x" + MyGUI::utility::toString(mult)); } else diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 9d3d967b9..3aa034a3c 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -268,6 +268,7 @@ void MWMechanics::NpcStats::levelUp() MWBase::Environment::get().getWorld()->getStore().get(); mLevelProgress -= gmst.find("iLevelUpTotal")->getInt(); + mLevelProgress = std::max(0, mLevelProgress); // might be necessary when levelup was invoked via console for (int i=0; i Date: Thu, 5 Feb 2015 01:15:42 +0100 Subject: [PATCH 405/740] UI consistency fix in levelup dialog --- apps/openmw/mwgui/levelupdialog.cpp | 3 ++- files/mygui/openmw_levelup_dialog.layout | 16 ++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index 6759824f9..c392372ff 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -139,7 +139,6 @@ namespace MWGui if(world->getStore().get().isDynamic(cls->mId)) { - // Vanilla uses thief.dds for custom classes. // Choosing Stealth specialization and Speed/Agility as attributes, if possible. Otherwise fall back to first class found. MWWorld::SharedIterator it = world->getStore().get().begin(); for(; it != world->getStore().get().end(); ++it) @@ -173,6 +172,7 @@ namespace MWGui if (pcStats.getAttribute(i).getBase() < 100) { mAttributes[i]->setEnabled(true); + mAttributeValues[i]->setEnabled(true); availableAttributes++; int mult = pcStats.getLevelupAttributeMultiplier (i); @@ -182,6 +182,7 @@ namespace MWGui else { mAttributes[i]->setEnabled(false); + mAttributeValues[i]->setEnabled(false); text->setCaption(""); } diff --git a/files/mygui/openmw_levelup_dialog.layout b/files/mygui/openmw_levelup_dialog.layout index 190f16e5d..ead181d26 100644 --- a/files/mygui/openmw_levelup_dialog.layout +++ b/files/mygui/openmw_levelup_dialog.layout @@ -50,7 +50,7 @@ - + @@ -64,7 +64,7 @@ - + @@ -78,7 +78,7 @@ - + @@ -92,7 +92,7 @@ - + @@ -107,7 +107,7 @@ - + @@ -121,7 +121,7 @@ - + @@ -135,7 +135,7 @@ - + @@ -149,7 +149,7 @@ - + From d18d2a1882a297e21364b8f7aaaba5b4abf7d77e Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Feb 2015 04:28:05 +0100 Subject: [PATCH 406/740] Skip rest of LEVI record if it has no items (Bug #2348) --- components/esm/loadlevlist.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/esm/loadlevlist.cpp b/components/esm/loadlevlist.cpp index f2c695c1f..0d0267764 100644 --- a/components/esm/loadlevlist.cpp +++ b/components/esm/loadlevlist.cpp @@ -19,7 +19,10 @@ void LevelledListBase::load(ESMReader &esm) mList.resize(len); } else + { + esm.skipRecord(); return; + } // TODO: Merge with an existing lists here. This can be done // simply by adding the lists together, making sure that they are From 01b41778720b71dcefc4a26860861cebefd04429 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Feb 2015 04:29:52 +0100 Subject: [PATCH 407/740] Make sure birthsign spells are added when loading savegame --- apps/openmw/mwworld/player.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index c1e176b91..8f3560a69 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -260,9 +260,20 @@ namespace MWWorld mCellStore = world.getExterior(0,0); } - if (!player.mBirthsign.empty() && - !world.getStore().get().search (player.mBirthsign)) - throw std::runtime_error ("invalid player state record (birthsign)"); + if (!player.mBirthsign.empty()) + { + const ESM::BirthSign* sign = world.getStore().get().search (player.mBirthsign); + if (!sign) + throw std::runtime_error ("invalid player state record (birthsign does not exist)"); + + // To handle the case where a birth sign was edited in between play sessions (does not yet handle removing the old spells) + // Also needed for ess-imported savegames which do not specify the birtsign spells in the player's spell list. + for (std::vector::const_iterator iter (sign->mPowers.mList.begin()); + iter!=sign->mPowers.mList.end(); ++iter) + { + getPlayer().getClass().getCreatureStats(getPlayer()).getSpells().add (*iter); + } + } mCurrentCrimeId = player.mCurrentCrimeId; mPaidCrimeId = player.mPaidCrimeId; From cff0127ce70d1eafb7474d0821adfd6aee7bdb77 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Feb 2015 04:31:50 +0100 Subject: [PATCH 408/740] Update comment on merging levelled lists --- components/esm/loadlevlist.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/components/esm/loadlevlist.cpp b/components/esm/loadlevlist.cpp index 0d0267764..2cbfac0b4 100644 --- a/components/esm/loadlevlist.cpp +++ b/components/esm/loadlevlist.cpp @@ -24,11 +24,12 @@ void LevelledListBase::load(ESMReader &esm) return; } - // TODO: Merge with an existing lists here. This can be done - // simply by adding the lists together, making sure that they are - // sorted by level. A better way might be to exclude repeated - // items. Also, some times we don't want to merge lists, just - // overwrite. Figure out a way to give the user this option. + // If this levelled list was already loaded by a previous content file, + // we overwrite the list. Merging lists should probably be left to external tools, + // with the limited amount of information there is in the records, all merging methods + // will be flawed in some way. For a proper fix the ESM format would have to be changed + // to actually track list changes instead of including the whole list for every file + // that does something with that list. for (size_t i = 0; i < mList.size(); i++) { From 4c6b9f8266b67e34bc6c6552c3a3ff0a0c0e406b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Feb 2015 15:39:53 +0100 Subject: [PATCH 409/740] Remove redundant decoder in ContentModel --- components/contentselector/model/contentmodel.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 198bbffbb..56a86f87f 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -442,11 +442,6 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path) filters << "*.esp" << "*.esm" << "*.omwgame" << "*.omwaddon"; dir.setNameFilters(filters); - QTextCodec *codec = QTextCodec::codecForName("UTF8"); - - // Create a decoder for non-latin characters in esx metadata - QTextDecoder *decoder = codec->makeDecoder(); - foreach (const QString &path, dir.entryList()) { QFileInfo info(dir.absoluteFilePath(path)); @@ -466,11 +461,11 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path) foreach (const ESM::Header::MasterData &item, fileReader.getGameFiles()) file->addGameFile(QString::fromStdString(item.name)); - file->setAuthor (decoder->toUnicode(fileReader.getAuthor().c_str())); + file->setAuthor (QString::fromUtf8(fileReader.getAuthor().c_str())); file->setDate (info.lastModified()); file->setFormat (fileReader.getFormat()); file->setFilePath (info.absoluteFilePath()); - file->setDescription(decoder->toUnicode(fileReader.getDesc().c_str())); + file->setDescription(QString::fromUtf8(fileReader.getDesc().c_str())); // Put the file in the table addFile(file); @@ -483,8 +478,6 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path) } - delete decoder; - sortFiles(); } From 5534306eb332f42160dc79093c2c9894149baae9 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Fri, 6 Feb 2015 08:59:00 +0200 Subject: [PATCH 410/740] Few rename fixes --- CMakeLists.txt | 2 +- apps/opencs/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b5cd54bab..ab4363e2e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -761,7 +761,7 @@ if (APPLE) set(OPENMW_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}") - set(OPENCS_BUNDLE_NAME "OpenCS.app") + set(OPENCS_BUNDLE_NAME "OpenMW-CS.app") set(OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}") set(ABSOLUTE_PLUGINS "") diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index e713c65bc..0b83feb45 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -211,5 +211,5 @@ target_link_libraries(openmw-cs ) if(APPLE) - INSTALL(TARGETS openmw-cs BUNDLE DESTINATION OpenMW-CS COMPONENT BUNDLE) + INSTALL(TARGETS openmw-cs BUNDLE DESTINATION OpenMW COMPONENT BUNDLE) endif() From 28eb766bbaab526ad35e0d4e06f7a5148c7e3e44 Mon Sep 17 00:00:00 2001 From: Rosanne DiMesio Date: Fri, 6 Feb 2015 14:27:12 -0600 Subject: [PATCH 411/740] Respect LIB_SUFFIX --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b5cd54bab..f2fd9b8de 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -392,7 +392,7 @@ IF(NOT WIN32 AND NOT APPLE) # Linux building # Paths SET(BINDIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Where to install binaries") - SET(LIBDIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Where to install libraries") + SET(LIBDIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE PATH "Where to install libraries") SET(DATAROOTDIR "${CMAKE_INSTALL_PREFIX}/share" CACHE PATH "Sets the root of data directories to a non-default location") SET(GLOBAL_DATA_PATH "${DATAROOTDIR}/games/" CACHE PATH "Set data path prefix") SET(DATADIR "${GLOBAL_DATA_PATH}/openmw" CACHE PATH "Sets the openmw data directories to a non-default location") From 1d9e9735730a6b0db4aab7a716432d973f13317d Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sat, 7 Feb 2015 04:05:28 +0100 Subject: [PATCH 412/740] Add training progress bar, implement jail screen, tweak wait dialog (Fixes #1714) --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwbase/windowmanager.hpp | 3 + apps/openmw/mwgui/jailscreen.cpp | 136 ++++++++++++++++++++++++ apps/openmw/mwgui/jailscreen.hpp | 33 ++++++ apps/openmw/mwgui/mode.hpp | 1 + apps/openmw/mwgui/timeadvancer.cpp | 73 +++++++++++++ apps/openmw/mwgui/timeadvancer.hpp | 40 +++++++ apps/openmw/mwgui/trainingwindow.cpp | 22 ++++ apps/openmw/mwgui/trainingwindow.hpp | 8 ++ apps/openmw/mwgui/waitdialog.cpp | 92 ++++++++-------- apps/openmw/mwgui/waitdialog.hpp | 13 ++- apps/openmw/mwgui/windowmanagerimp.cpp | 15 +++ apps/openmw/mwgui/windowmanagerimp.hpp | 4 + apps/openmw/mwscript/miscextensions.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 54 +--------- 15 files changed, 394 insertions(+), 104 deletions(-) create mode 100644 apps/openmw/mwgui/jailscreen.cpp create mode 100644 apps/openmw/mwgui/jailscreen.hpp create mode 100644 apps/openmw/mwgui/timeadvancer.cpp create mode 100644 apps/openmw/mwgui/timeadvancer.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index cb6cc301b..eabbb7577 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -41,7 +41,7 @@ add_openmw_dir (mwgui itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview - draganddrop + draganddrop timeadvancer jailscreen ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index c984b5e54..32994a5a6 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -63,6 +63,7 @@ namespace MWGui class ContainerWindow; class DialogueWindow; class WindowModal; + class JailScreen; enum ShowInDialogueMode { ShowInDialogueMode_IfPossible, @@ -114,6 +115,8 @@ namespace MWBase virtual void removeGuiMode (MWGui::GuiMode mode) = 0; ///< can be anywhere in the stack + virtual void goToJail(int days) = 0; + virtual void updatePlayer() = 0; virtual MWGui::GuiMode getMode() const = 0; diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp new file mode 100644 index 000000000..0155ee5ff --- /dev/null +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -0,0 +1,136 @@ +#include +#include +#include +#include + +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" + +#include "../mwmechanics/npcstats.hpp" + +#include "../mwworld/esmstore.hpp" +#include "../mwworld/store.hpp" +#include "../mwworld/class.hpp" + +#include "jailscreen.hpp" + +namespace MWGui +{ + JailScreen::JailScreen() + : WindowBase("openmw_loading_screen.layout"), + mTimeAdvancer(0.0125), + mDays(1), + mFadeTimeRemaining(0) + { + getWidget(mLoadingText, "LoadingText"); + getWidget(mProgressBar, "ProgressBar"); + getWidget(mLoadingBox, "LoadingBox"); + + setVisible(false); + + mTimeAdvancer.eventProgressChanged += MyGUI::newDelegate(this, &JailScreen::onJailProgressChanged); + mTimeAdvancer.eventFinished += MyGUI::newDelegate(this, &JailScreen::onJailFinished); + + mLoadingText->setCaptionWithReplacing("#{sInPrisonTitle}"); + + center(); + } + + void JailScreen::goToJail(int days) + { + mDays = days; + + MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.5); + mFadeTimeRemaining = 0.5; + + setVisible(false); + mProgressBar->setScrollRange(days*24+1); + mProgressBar->setScrollPosition(0); + mProgressBar->setTrackSize(0); + } + + void JailScreen::onFrame(float dt) + { + mTimeAdvancer.onFrame(dt); + + if (mFadeTimeRemaining <= 0) + return; + + mFadeTimeRemaining -= dt; + + if (mFadeTimeRemaining <= 0) + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWBase::Environment::get().getWorld()->teleportToClosestMarker(player, "prisonmarker"); + + setVisible(true); + mTimeAdvancer.run(mDays*24); + } + } + + void JailScreen::onJailProgressChanged(int cur, int /*total*/) + { + mProgressBar->setScrollPosition(0); + mProgressBar->setTrackSize(cur / (float)(mProgressBar->getScrollRange()) * mProgressBar->getLineSize()); + } + + void JailScreen::onJailFinished() + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.5); + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + + MWBase::Environment::get().getWorld()->advanceTime(mDays * 24); + for (int i=0; irest(true); + + std::set skills; + for (int day=0; day (RAND_MAX) + 1) * ESM::Skill::Length; + skills.insert(skill); + + MWMechanics::SkillValue& value = player.getClass().getNpcStats(player).getSkill(skill); + if (skill == ESM::Skill::Security || skill == ESM::Skill::Sneak) + value.setBase(std::min(100, value.getBase()+1)); + else + value.setBase(value.getBase()-1); + } + + const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); + + std::string message; + if (mDays == 1) + message = gmst.find("sNotifyMessage42")->getString(); + else + message = gmst.find("sNotifyMessage43")->getString(); + + std::stringstream dayStr; + dayStr << mDays; + if (message.find("%d") != std::string::npos) + message.replace(message.find("%d"), 2, dayStr.str()); + + for (std::set::iterator it = skills.begin(); it != skills.end(); ++it) + { + std::string skillName = gmst.find(ESM::Skill::sSkillNameIds[*it])->getString(); + std::stringstream skillValue; + skillValue << player.getClass().getNpcStats(player).getSkill(*it).getBase(); + std::string skillMsg = gmst.find("sNotifyMessage44")->getString(); + if (*it == ESM::Skill::Sneak || *it == ESM::Skill::Security) + skillMsg = gmst.find("sNotifyMessage39")->getString(); + + if (skillMsg.find("%s") != std::string::npos) + skillMsg.replace(skillMsg.find("%s"), 2, skillName); + if (skillMsg.find("%d") != std::string::npos) + skillMsg.replace(skillMsg.find("%d"), 2, skillValue.str()); + message += "\n" + skillMsg; + } + + std::vector buttons; + buttons.push_back("#{sOk}"); + MWBase::Environment::get().getWindowManager()->interactiveMessageBox(message, buttons); + } +} diff --git a/apps/openmw/mwgui/jailscreen.hpp b/apps/openmw/mwgui/jailscreen.hpp new file mode 100644 index 000000000..06e9a3aa0 --- /dev/null +++ b/apps/openmw/mwgui/jailscreen.hpp @@ -0,0 +1,33 @@ +#ifndef MWGUI_JAILSCREEN_H +#define MWGUI_JAILSCREEN_H + +#include "windowbase.hpp" +#include "timeadvancer.hpp" + +namespace MWGui +{ + class JailScreen : public WindowBase + { + public: + JailScreen(); + void goToJail(int days); + + void onFrame(float dt); + + private: + int mDays; + + float mFadeTimeRemaining; + + MyGUI::Widget* mLoadingBox; + MyGUI::TextBox* mLoadingText; + MyGUI::ScrollBar* mProgressBar; + + void onJailProgressChanged(int cur, int total); + void onJailFinished(); + + TimeAdvancer mTimeAdvancer; + }; +} + +#endif diff --git a/apps/openmw/mwgui/mode.hpp b/apps/openmw/mwgui/mode.hpp index a1688d2e5..db851e067 100644 --- a/apps/openmw/mwgui/mode.hpp +++ b/apps/openmw/mwgui/mode.hpp @@ -46,6 +46,7 @@ namespace MWGui GM_Loading, GM_LoadingWallpaper, + GM_Jail, GM_QuickKeysMenu }; diff --git a/apps/openmw/mwgui/timeadvancer.cpp b/apps/openmw/mwgui/timeadvancer.cpp new file mode 100644 index 000000000..43504ce87 --- /dev/null +++ b/apps/openmw/mwgui/timeadvancer.cpp @@ -0,0 +1,73 @@ +#include "timeadvancer.hpp" + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +namespace MWGui +{ + TimeAdvancer::TimeAdvancer(float delay) + : mRunning(false), + mCurHour(0), + mHours(1), + mInterruptAt(-1), + mDelay(delay), + mRemainingTime(delay) + { + } + + void TimeAdvancer::run(int hours, int interruptAt) + { + mHours = hours; + mCurHour = 0; + mInterruptAt = interruptAt; + mRemainingTime = mDelay; + + mRunning = true; + } + + void TimeAdvancer::stop() + { + mRunning = false; + } + + void TimeAdvancer::onFrame(float dt) + { + if (!mRunning) + return; + + if (mCurHour == mInterruptAt) + { + stop(); + eventInterrupted(); + return; + } + + mRemainingTime -= dt; + + while (mRemainingTime <= 0) + { + mRemainingTime += mDelay; + ++mCurHour; + + if (mCurHour <= mHours) + eventProgressChanged(mCurHour, mHours); + else + { + stop(); + eventFinished(); + return; + } + + } + } + + int TimeAdvancer::getHours() + { + return mHours; + } + + bool TimeAdvancer::isRunning() + { + return mRunning; + } +} diff --git a/apps/openmw/mwgui/timeadvancer.hpp b/apps/openmw/mwgui/timeadvancer.hpp new file mode 100644 index 000000000..8367b5a8b --- /dev/null +++ b/apps/openmw/mwgui/timeadvancer.hpp @@ -0,0 +1,40 @@ +#ifndef MWGUI_TIMEADVANCER_H +#define MWGUI_TIMEADVANCER_H + +#include + +namespace MWGui +{ + class TimeAdvancer + { + public: + TimeAdvancer(float delay); + + void run(int hours, int interruptAt=-1); + void stop(); + void onFrame(float dt); + + int getHours(); + bool isRunning(); + + // signals + typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; + typedef MyGUI::delegates::CMultiDelegate2 EventHandle_IntInt; + + EventHandle_IntInt eventProgressChanged; + EventHandle_Void eventInterrupted; + EventHandle_Void eventFinished; + + private: + bool mRunning; + + int mCurHour; + int mHours; + int mInterruptAt; + + float mDelay; + float mRemainingTime; + }; +} + +#endif diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 88ba62cc1..5a5f61115 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -40,12 +40,18 @@ namespace MWGui TrainingWindow::TrainingWindow() : WindowBase("openmw_trainingwindow.layout") , mFadeTimeRemaining(0) + , mTimeAdvancer(0.05) { getWidget(mTrainingOptions, "TrainingOptions"); getWidget(mCancelButton, "CancelButton"); getWidget(mPlayerGold, "PlayerGold"); mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TrainingWindow::onCancelButtonClicked); + + mTimeAdvancer.eventProgressChanged += MyGUI::newDelegate(this, &TrainingWindow::onTrainingProgressChanged); + mTimeAdvancer.eventFinished += MyGUI::newDelegate(this, &TrainingWindow::onTrainingFinished); + + mProgressBar.setVisible(false); } void TrainingWindow::open() @@ -173,12 +179,28 @@ namespace MWGui MWBase::Environment::get().getMechanicsManager()->rest(false); MWBase::Environment::get().getMechanicsManager()->rest(false); + mProgressBar.setVisible(true); + mProgressBar.setProgress(0, 2); + mTimeAdvancer.run(2); + MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.25); mFadeTimeRemaining = 0.5; } + void TrainingWindow::onTrainingProgressChanged(int cur, int total) + { + mProgressBar.setProgress(cur, total); + } + + void TrainingWindow::onTrainingFinished() + { + mProgressBar.setVisible(false); + } + void TrainingWindow::onFrame(float dt) { + mTimeAdvancer.onFrame(dt); + if (mFadeTimeRemaining <= 0) return; diff --git a/apps/openmw/mwgui/trainingwindow.hpp b/apps/openmw/mwgui/trainingwindow.hpp index 1fc902b20..7c4582062 100644 --- a/apps/openmw/mwgui/trainingwindow.hpp +++ b/apps/openmw/mwgui/trainingwindow.hpp @@ -3,6 +3,8 @@ #include "windowbase.hpp" #include "referenceinterface.hpp" +#include "timeadvancer.hpp" +#include "waitdialog.hpp" namespace MWGui { @@ -26,11 +28,17 @@ namespace MWGui void onCancelButtonClicked (MyGUI::Widget* sender); void onTrainingSelected(MyGUI::Widget* sender); + void onTrainingProgressChanged(int cur, int total); + void onTrainingFinished(); + MyGUI::Widget* mTrainingOptions; MyGUI::Button* mCancelButton; MyGUI::TextBox* mPlayerGold; float mFadeTimeRemaining; + + WaitDialogProgressBar mProgressBar; + TimeAdvancer mTimeAdvancer; }; } diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index fedb0324e..ad873a7c3 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -49,12 +49,11 @@ namespace MWGui WaitDialog::WaitDialog() : WindowBase("openmw_wait_dialog.layout") , mProgressBar() - , mWaiting(false) + , mTimeAdvancer(0.05) , mSleeping(false) , mHours(1) - , mRemainingTime(0.05) - , mCurHour(0) , mManualHours(1) + , mFadeTimeRemaining(0) , mInterruptAt(-1) { getWidget(mDateTimeText, "DateTimeText"); @@ -70,6 +69,10 @@ namespace MWGui mWaitButton->eventMouseButtonClick += MyGUI::newDelegate(this, &WaitDialog::onWaitButtonClicked); mHourSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &WaitDialog::onHourSliderChangedPosition); + mTimeAdvancer.eventProgressChanged += MyGUI::newDelegate(this, &WaitDialog::onWaitingProgressChanged); + mTimeAdvancer.eventInterrupted += MyGUI::newDelegate(this, &WaitDialog::onWaitingInterrupted); + mTimeAdvancer.eventFinished += MyGUI::newDelegate(this, &WaitDialog::onWaitingFinished); + mProgressBar.setVisible (false); } @@ -133,11 +136,9 @@ namespace MWGui MWBase::World* world = MWBase::Environment::get().getWorld(); MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.2); + mFadeTimeRemaining = 0.4; setVisible(false); - mProgressBar.setVisible (true); - mWaiting = true; - mCurHour = 0; mHours = hoursToWait; // FIXME: move this somewhere else? @@ -164,8 +165,7 @@ namespace MWGui } } - mRemainingTime = 0.05; - mProgressBar.setProgress (0, mHours); + mProgressBar.setProgress (0, hoursToWait); } void WaitDialog::onCancelButtonClicked(MyGUI::Widget* sender) @@ -179,6 +179,36 @@ namespace MWGui mManualHours = position+1; } + void WaitDialog::onWaitingProgressChanged(int cur, int total) + { + mProgressBar.setProgress(cur, total); + MWBase::Environment::get().getWorld()->advanceTime(1); + MWBase::Environment::get().getMechanicsManager()->rest(mSleeping); + } + + void WaitDialog::onWaitingInterrupted() + { + MWBase::Environment::get().getWindowManager()->messageBox("#{sSleepInterrupt}"); + MWBase::Environment::get().getWorld()->spawnRandomCreature(mInterruptCreatureList); + stopWaiting(); + } + + void WaitDialog::onWaitingFinished() + { + stopWaiting(); + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWMechanics::NpcStats &pcstats = player.getClass().getNpcStats(player); + + // trigger levelup if possible + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); + if (mSleeping && pcstats.getLevelProgress () >= gmst.find("iLevelUpTotal")->getInt()) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode (GM_Levelup); + } + } + void WaitDialog::setCanRest (bool canRest) { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); @@ -205,45 +235,17 @@ namespace MWGui void WaitDialog::onFrame(float dt) { - if (!mWaiting) - return; + mTimeAdvancer.onFrame(dt); - if (mCurHour == mInterruptAt) - { - MWBase::Environment::get().getWindowManager()->messageBox("#{sSleepInterrupt}"); - MWBase::Environment::get().getWorld()->spawnRandomCreature(mInterruptCreatureList); - stopWaiting(); - } + if (mFadeTimeRemaining <= 0) + return; - mRemainingTime -= dt; + mFadeTimeRemaining -= dt; - while (mRemainingTime < 0) + if (mFadeTimeRemaining <= 0) { - mRemainingTime += 0.05; - ++mCurHour; - mProgressBar.setProgress (mCurHour, mHours); - - if (mCurHour <= mHours) - { - MWBase::Environment::get().getWorld ()->advanceTime (1); - MWBase::Environment::get().getMechanicsManager ()->rest (mSleeping); - } - } - - if (mCurHour > mHours) - { - stopWaiting(); - - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - const MWMechanics::NpcStats &pcstats = player.getClass().getNpcStats(player); - - // trigger levelup if possible - const MWWorld::Store &gmst = - MWBase::Environment::get().getWorld()->getStore().get(); - if (mSleeping && pcstats.getLevelProgress () >= gmst.find("iLevelUpTotal")->getInt()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode (GM_Levelup); - } + mProgressBar.setVisible(true); + mTimeAdvancer.run(mHours, mInterruptAt); } } @@ -253,14 +255,14 @@ namespace MWGui mProgressBar.setVisible (false); MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Rest); MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_RestBed); - mWaiting = false; + mTimeAdvancer.stop(); } void WaitDialog::wakeUp () { mSleeping = false; - mWaiting = false; + mTimeAdvancer.stop(); stopWaiting(); } diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index 435c1cb54..e8f58c574 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -1,6 +1,8 @@ #ifndef MWGUI_WAIT_DIALOG_H #define MWGUI_WAIT_DIALOG_H +#include "timeadvancer.hpp" + #include "windowbase.hpp" namespace MWGui @@ -38,7 +40,7 @@ namespace MWGui void bedActivated() { setCanRest(true); } - bool getSleeping() { return mWaiting && mSleeping; } + bool getSleeping() { return mTimeAdvancer.isRunning() && mSleeping; } void wakeUp(); void autosave(); @@ -51,12 +53,11 @@ namespace MWGui MyGUI::Button* mCancelButton; MWGui::Widgets::MWScrollBar* mHourSlider; - bool mWaiting; + TimeAdvancer mTimeAdvancer; bool mSleeping; - int mCurHour; int mHours; int mManualHours; // stores the hours to rest selected via slider - float mRemainingTime; + float mFadeTimeRemaining; int mInterruptAt; std::string mInterruptCreatureList; @@ -68,6 +69,10 @@ namespace MWGui void onCancelButtonClicked(MyGUI::Widget* sender); void onHourSliderChangedPosition(MyGUI::ScrollBar* sender, size_t position); + void onWaitingProgressChanged(int cur, int total); + void onWaitingInterrupted(); + void onWaitingFinished(); + void setCanRest(bool canRest); void startWaiting(int hoursToWait); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 715f47c46..d67ab17e0 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -91,6 +91,7 @@ #include "draganddrop.hpp" #include "container.hpp" #include "controllers.hpp" +#include "jailscreen.hpp" namespace MWGui { @@ -143,6 +144,7 @@ namespace MWGui , mHitFader(NULL) , mScreenFader(NULL) , mDebugWindow(NULL) + , mJailScreen(NULL) , mTranslationDataStorage (translationDataStorage) , mCharGen(NULL) , mInputBlocker(NULL) @@ -290,6 +292,7 @@ namespace MWGui mSoulgemDialog = new SoulgemDialog(mMessageBoxManager); mCompanionWindow = new CompanionWindow(mDragAndDrop, mMessageBoxManager); trackWindow(mCompanionWindow, "companion"); + mJailScreen = new JailScreen(); mWerewolfFader = new ScreenFader("textures\\werewolfoverlay.dds"); mBlindnessFader = new ScreenFader("black.png"); @@ -402,6 +405,7 @@ namespace MWGui delete mScreenFader; delete mBlindnessFader; delete mDebugWindow; + delete mJailScreen; delete mCursorManager; @@ -467,6 +471,7 @@ namespace MWGui mInventoryWindow->setTrading(false); mRecharge->setVisible(false); mVideoBackground->setVisible(false); + mJailScreen->setVisible(false); mHud->setVisible(mHudEnabled && mGuiEnabled); mToolTips->setVisible(mGuiEnabled); @@ -612,6 +617,9 @@ namespace MWGui case GM_Journal: mJournal->setVisible(true); break; + case GM_Jail: + mJailScreen->setVisible(true); + break; case GM_LoadingWallpaper: case GM_Loading: // Don't need to show anything here - GM_LoadingWallpaper covers everything else anyway, @@ -912,6 +920,7 @@ namespace MWGui mCompanionWindow->checkReferenceAvailable(); mConsole->checkReferenceAvailable(); mCompanionWindow->onFrame(); + mJailScreen->onFrame(frameDuration); mWerewolfFader->update(frameDuration); mBlindnessFader->update(frameDuration); @@ -1187,6 +1196,12 @@ namespace MWGui updateVisible(); } + void WindowManager::goToJail(int days) + { + pushGuiMode(MWGui::GM_Jail); + mJailScreen->goToJail(days); + } + void WindowManager::setSelectedSpell(const std::string& spellId, int successChancePercent) { mSelectedSpell = spellId; diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 9f01b136c..19c5e3166 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -90,6 +90,7 @@ namespace MWGui class WindowModal; class ScreenFader; class DebugWindow; + class JailScreen; class WindowManager : public MWBase::WindowManager { @@ -128,6 +129,8 @@ namespace MWGui virtual void popGuiMode(); virtual void removeGuiMode(GuiMode mode); ///< can be anywhere in the stack + virtual void goToJail(int days); + virtual GuiMode getMode() const; virtual bool containsMode(GuiMode mode) const; @@ -404,6 +407,7 @@ namespace MWGui ScreenFader* mHitFader; ScreenFader* mScreenFader; DebugWindow* mDebugWindow; + JailScreen* mJailScreen; Translation::Storage& mTranslationDataStorage; diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index bffeef768..40a356125 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -1008,7 +1008,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime &runtime) { /// \todo implement jail check - runtime.push (0); + runtime.push (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Jail); } }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a8238d161..af3fa5b3e 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3019,59 +3019,7 @@ namespace MWWorld MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue); - MWWorld::Ptr player = getPlayerPtr(); - teleportToClosestMarker(player, "prisonmarker"); - - int days = mDaysInPrison; - advanceTime(days * 24); - for (int i=0; irest (true); - - std::set skills; - for (int day=0; day (RAND_MAX) + 1) * ESM::Skill::Length; - skills.insert(skill); - - MWMechanics::SkillValue& value = player.getClass().getNpcStats(player).getSkill(skill); - if (skill == ESM::Skill::Security || skill == ESM::Skill::Sneak) - value.setBase(std::min(100, value.getBase()+1)); - else - value.setBase(value.getBase()-1); - } - - const Store& gmst = getStore().get(); - - std::string message; - if (days == 1) - message = gmst.find("sNotifyMessage42")->getString(); - else - message = gmst.find("sNotifyMessage43")->getString(); - - std::stringstream dayStr; - dayStr << days; - if (message.find("%d") != std::string::npos) - message.replace(message.find("%d"), 2, dayStr.str()); - - for (std::set::iterator it = skills.begin(); it != skills.end(); ++it) - { - std::string skillName = gmst.find(ESM::Skill::sSkillNameIds[*it])->getString(); - std::stringstream skillValue; - skillValue << player.getClass().getNpcStats(player).getSkill(*it).getBase(); - std::string skillMsg = gmst.find("sNotifyMessage44")->getString(); - if (*it == ESM::Skill::Sneak || *it == ESM::Skill::Security) - skillMsg = gmst.find("sNotifyMessage39")->getString(); - - if (skillMsg.find("%s") != std::string::npos) - skillMsg.replace(skillMsg.find("%s"), 2, skillName); - if (skillMsg.find("%d") != std::string::npos) - skillMsg.replace(skillMsg.find("%d"), 2, skillValue.str()); - message += "\n" + skillMsg; - } - - std::vector buttons; - buttons.push_back("#{sOk}"); - MWBase::Environment::get().getWindowManager()->interactiveMessageBox(message, buttons); + MWBase::Environment::get().getWindowManager()->goToJail(mDaysInPrison); } } From 2d17eaa5ea5ad5e57928649cf0553f01a8413e20 Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Fri, 6 Feb 2015 19:21:40 -0600 Subject: [PATCH 413/740] Fix argument name for setSunDirection. --- apps/openmw/mwrender/renderingmanager.cpp | 4 ++-- apps/openmw/mwrender/renderingmanager.hpp | 2 +- apps/openmw/mwrender/sky.cpp | 4 ++-- apps/openmw/mwrender/sky.hpp | 2 +- apps/openmw/mwworld/weather.cpp | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 3ffd787c7..3e95648c4 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -630,12 +630,12 @@ void RenderingManager::sunDisable(bool real) } } -void RenderingManager::setSunDirection(const Ogre::Vector3& direction, bool is_moon) +void RenderingManager::setSunDirection(const Ogre::Vector3& direction, bool is_night) { // direction * -1 (because 'direction' is camera to sun vector and not sun to camera), if (mSun) mSun->setDirection(Vector3(-direction.x, -direction.y, -direction.z)); - mSkyManager->setSunDirection(direction, is_moon); + mSkyManager->setSunDirection(direction, is_night); } void RenderingManager::setGlare(bool glare) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index d4b85133d..9f029c1b9 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -141,7 +141,7 @@ public: void setAmbientColour(const Ogre::ColourValue& colour); void setSunColour(const Ogre::ColourValue& colour); - void setSunDirection(const Ogre::Vector3& direction, bool is_moon); + void setSunDirection(const Ogre::Vector3& direction, bool is_night); void sunEnable(bool real); ///< @param real whether or not to really disable the sunlight (otherwise just set diffuse to 0) void sunDisable(bool real); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 454ed8820..f6287de5e 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -767,14 +767,14 @@ void SkyManager::setStormDirection(const Vector3 &direction) mStormDirection = direction; } -void SkyManager::setSunDirection(const Vector3& direction, bool is_moon) +void SkyManager::setSunDirection(const Vector3& direction, bool is_night) { if (!mCreated) return; mSun->setPosition(direction); mSunGlare->setPosition(direction); float height = direction.z; - float fade = is_moon ? 0.0 : (( height > 0.5) ? 1.0 : height * 2); + float fade = is_night ? 0.0 : (( height > 0.5) ? 1.0 : height * 2); sh::Factory::getInstance ().setSharedParameter ("waterSunFade_sunHeight", sh::makeProperty(new sh::Vector2(fade, height))); } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 70251f490..6950dbab3 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -153,7 +153,7 @@ namespace MWRender void setStormDirection(const Ogre::Vector3& direction); - void setSunDirection(const Ogre::Vector3& direction, bool is_moon); + void setSunDirection(const Ogre::Vector3& direction, bool is_night); void setMasserDirection(const Ogre::Vector3& direction); diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index a74c24768..a893b657a 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -443,13 +443,13 @@ void WeatherManager::update(float duration, bool paused) int facing = (mHour > 13.f) ? 1 : -1; - bool sun_is_moon = mHour >= mNightStart || mHour <= mSunriseTime; + bool is_night = mHour >= mNightStart || mHour <= mSunriseTime; Vector3 final( (height - 1) * facing, (height - 1) * facing, height); - mRendering->setSunDirection(final, sun_is_moon); + mRendering->setSunDirection(final, is_night); /* * TODO: import separated fadeInStart/Finish, fadeOutStart/Finish From c8a924196deacac0193f6698baa0bfa63a8f517d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 7 Feb 2015 17:22:29 +0100 Subject: [PATCH 414/740] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index f261ea423..bc39b1c70 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -84,6 +84,7 @@ Programmers Paul McElroy (Greendogo) Pieter van der Kloet (pvdk) Radu-Marius Popovici (rpopovici) + rdimesio riothamus Robert MacGregor (Ragora) Rohit Nirmal From 1230cf49bf63cebe82e355e517ae58205afb9c31 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sat, 7 Feb 2015 18:38:41 +0100 Subject: [PATCH 415/740] Properly center jail progress widget, fix a bug with it not disappearing if the console is open --- apps/openmw/mwgui/jailscreen.cpp | 11 ++--------- apps/openmw/mwgui/jailscreen.hpp | 2 -- files/mygui/CMakeLists.txt | 1 + files/mygui/openmw_jail_screen.layout | 15 +++++++++++++++ 4 files changed, 18 insertions(+), 11 deletions(-) create mode 100644 files/mygui/openmw_jail_screen.layout diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index 0155ee5ff..548b1b604 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -1,7 +1,4 @@ -#include #include -#include -#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -19,22 +16,18 @@ namespace MWGui { JailScreen::JailScreen() - : WindowBase("openmw_loading_screen.layout"), + : WindowBase("openmw_jail_screen.layout"), mTimeAdvancer(0.0125), mDays(1), mFadeTimeRemaining(0) { - getWidget(mLoadingText, "LoadingText"); getWidget(mProgressBar, "ProgressBar"); - getWidget(mLoadingBox, "LoadingBox"); setVisible(false); mTimeAdvancer.eventProgressChanged += MyGUI::newDelegate(this, &JailScreen::onJailProgressChanged); mTimeAdvancer.eventFinished += MyGUI::newDelegate(this, &JailScreen::onJailFinished); - mLoadingText->setCaptionWithReplacing("#{sInPrisonTitle}"); - center(); } @@ -78,7 +71,7 @@ namespace MWGui void JailScreen::onJailFinished() { - MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Jail); MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.5); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); diff --git a/apps/openmw/mwgui/jailscreen.hpp b/apps/openmw/mwgui/jailscreen.hpp index 06e9a3aa0..7a544126d 100644 --- a/apps/openmw/mwgui/jailscreen.hpp +++ b/apps/openmw/mwgui/jailscreen.hpp @@ -19,8 +19,6 @@ namespace MWGui float mFadeTimeRemaining; - MyGUI::Widget* mLoadingBox; - MyGUI::TextBox* mLoadingText; MyGUI::ScrollBar* mProgressBar; void onJailProgressChanged(int cur, int total); diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index 638266b0c..13d1a9e1a 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -86,6 +86,7 @@ set(MYGUI_FILES openmw_edit_note.layout openmw_debug_window.layout openmw_debug_window.skin.xml + openmw_jail_screen.layout DejaVuLGCSansMono.ttf ../launcher/images/openmw.png OpenMWResourcePlugin.xml diff --git a/files/mygui/openmw_jail_screen.layout b/files/mygui/openmw_jail_screen.layout new file mode 100644 index 000000000..4385494e1 --- /dev/null +++ b/files/mygui/openmw_jail_screen.layout @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + From 9bbe6f8c5e52808e8b1886b3c594e01934dd892c Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sat, 7 Feb 2015 18:39:05 +0100 Subject: [PATCH 416/740] Remove todo --- apps/openmw/mwscript/miscextensions.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 40a356125..1cc1b25e4 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -1007,7 +1007,6 @@ namespace MWScript virtual void execute (Interpreter::Runtime &runtime) { - /// \todo implement jail check runtime.push (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Jail); } }; From 23024d2bebc2a376b062b2bbe94bfe880f9e975d Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Sat, 7 Feb 2015 12:36:27 -0600 Subject: [PATCH 417/740] Re-work the sun's trajectory. OMW Bug #781 Have the sun travel 15 degrees south of vertical. --- apps/openmw/mwworld/weather.cpp | 44 +++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index a893b657a..dcd8e5a11 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -1,5 +1,7 @@ #include "weather.hpp" +#include + #include #include "../mwbase/environment.hpp" @@ -427,29 +429,33 @@ void WeatherManager::update(float duration, bool paused) else mRendering->getSkyManager()->sunEnable(); - // sun angle - float height; - - //Day duration - float dayDuration = (mNightStart - 1) - mSunriseTime; + // Update the sun direction. Run it east to west at 15 degrees south from overhead. + // The sun's speed at day and night will differ, since mSunriseTime and mNightStart + // mark when the sun is level with the horizon. + { + assert( mNightStart > mSunriseTime ); - // rise at 6, set at 20 - if (mHour >= mSunriseTime && mHour <= mNightStart) - height = 1 - std::abs(((mHour - dayDuration) / 7.f)); - else if (mHour > mNightStart) - height = (mHour - mNightStart) / 4.f; - else //if (mHour > 0 && mHour < 6) - height = 1 - (mHour / mSunriseTime); + float adjustedHour = mHour; + if ( mHour < mSunriseTime ) + adjustedHour += 24.f; - int facing = (mHour > 13.f) ? 1 : -1; + const bool is_night = mHour >= mNightStart || mHour <= mSunriseTime; + const float dayDuration = mNightStart - mSunriseTime; + const float nightDuration = 24.f - dayDuration; - bool is_night = mHour >= mNightStart || mHour <= mSunriseTime; + double theta; + if ( !is_night ) { + theta = M_PI * (adjustedHour - mSunriseTime) / dayDuration; + } else { + theta = M_PI * (adjustedHour - mNightStart) / nightDuration; + } - Vector3 final( - (height - 1) * facing, - (height - 1) * facing, - height); - mRendering->setSunDirection(final, is_night); + Vector3 final( + cos( theta ), + -0.268, // approx tan( 15 degrees ) + sin( theta ) ); + mRendering->setSunDirection( final, is_night ); + } /* * TODO: import separated fadeInStart/Finish, fadeOutStart/Finish From 2223a69ab827e3315781bd3ddd32eda68dd7cc9b Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sat, 7 Feb 2015 20:13:11 +0100 Subject: [PATCH 418/740] Fix getpcinjail returning 0 when the console is open --- apps/openmw/mwscript/miscextensions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 1cc1b25e4..20724cd23 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -1007,7 +1007,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime &runtime) { - runtime.push (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Jail); + runtime.push (MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Jail)); } }; From c63ab673e1f1a09862d500400cb4cc3713dbc46e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Feb 2015 23:24:27 +0100 Subject: [PATCH 419/740] Revert "Add freedesktop.org mimeinfo for OpenMW save game files" This reverts commit 94002b0758a8825215074b5341b6ec6b0cd28660. Conflicts: CMakeLists.txt --- CMakeLists.txt | 3 --- files/openmw-mimeinfo.xml | 11 ----------- files/openmw.desktop | 13 ------------- 3 files changed, 27 deletions(-) delete mode 100644 files/openmw-mimeinfo.xml diff --git a/CMakeLists.txt b/CMakeLists.txt index ab4363e2e..d22e0b129 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -371,8 +371,6 @@ configure_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters if (NOT WIN32 AND NOT APPLE) configure_file(${OpenMW_SOURCE_DIR}/files/openmw.desktop "${OpenMW_BINARY_DIR}/openmw.desktop") - configure_file(${OpenMW_SOURCE_DIR}/files/openmw-mimeinfo.xml - "${OpenMW_BINARY_DIR}/openmw-mimeinfo.xml") configure_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.desktop "${OpenMW_BINARY_DIR}/openmw-cs.desktop") endif() @@ -441,7 +439,6 @@ IF(NOT WIN32 AND NOT APPLE) # Install icon and desktop file INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") - INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-mimeinfo.xml" DESTINATION "${DATAROOTDIR}/mime/packages" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.png" DESTINATION "${ICONDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") IF(BUILD_OPENCS) INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.desktop" DESTINATION "${DATAROOTDIR}/applications" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs") diff --git a/files/openmw-mimeinfo.xml b/files/openmw-mimeinfo.xml deleted file mode 100644 index 1355383a5..000000000 --- a/files/openmw-mimeinfo.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - OpenMW Savegame - - - - diff --git a/files/openmw.desktop b/files/openmw.desktop index 6d64c5a7c..36d01b33e 100644 --- a/files/openmw.desktop +++ b/files/openmw.desktop @@ -8,16 +8,3 @@ TryExec=openmw-launcher Exec=openmw-launcher Icon=openmw Categories=Game;RolePlaying; - -[Desktop Entry] -Type=Application -Name=OpenMW -GenericName=Role Playing Game -Comment=An engine replacement for The Elder Scrolls III: Morrowind -Keywords=Morrowind;Reimplementation Mods;esm;bsa; -Exec=openmw --load-savegame=%f -Icon=openmw -Categories=Game;RolePlaying; -Terminal=false -NoDisplay=true -MimeType=application/x-openmw-savegame; From 01e32aef79fcdcf14c8dfcbb2d61d11589e05e31 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Feb 2015 14:34:31 +0100 Subject: [PATCH 420/740] Fix exception moving a disabled object between cells --- apps/openmw/mwrender/renderingmanager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 3ffd787c7..88ede1682 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -297,6 +297,8 @@ void RenderingManager::rotateObject(const MWWorld::Ptr &ptr) void RenderingManager::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) { + if (!old.getRefData().getBaseNode()) + return; Ogre::SceneNode *child = mRendering.getScene()->getSceneNode(old.getRefData().getHandle()); From ad8790fba0b81e03027b3f778cda002eb213155d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Feb 2015 15:39:10 +0100 Subject: [PATCH 421/740] Fix setWaterLevel script instruction not affecting physics --- apps/openmw/mwsound/soundmanagerimp.cpp | 4 ++-- apps/openmw/mwworld/physicssystem.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index d856f41ee..0bc155118 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -723,9 +723,9 @@ namespace MWSound MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - const ESM::Cell *cell = player.getCell()->getCell(); + const MWWorld::CellStore *cell = player.getCell(); - mListenerUnderwater = ((cell->mData.mFlags&cell->HasWater) && mListenerPos.z < cell->mWater); + mListenerUnderwater = ((cell->getCell()->mData.mFlags&ESM::Cell::HasWater) && mListenerPos.z < cell->getWaterLevel()); } void SoundManager::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index bea99029a..d31ae520b 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -862,9 +862,9 @@ namespace MWWorld for(;iter != mMovementQueue.end();++iter) { float waterlevel = -std::numeric_limits::max(); - const ESM::Cell *cell = iter->first.getCell()->getCell(); - if(cell->hasWater()) - waterlevel = cell->mWater; + const MWWorld::CellStore *cell = iter->first.getCell(); + if(cell->getCell()->hasWater()) + waterlevel = cell->getWaterLevel(); float oldHeight = iter->first.getRefData().getPosition().pos[2]; @@ -872,7 +872,7 @@ namespace MWWorld bool waterCollision = false; if (effects.get(ESM::MagicEffect::WaterWalking).getMagnitude() - && cell->hasWater() + && cell->getCell()->hasWater() && !world->isUnderwater(iter->first.getCell(), Ogre::Vector3(iter->first.getRefData().getPosition().pos))) waterCollision = true; From b542143e3a231bd7418ffc0975793ea2df5a1cb4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Feb 2015 21:04:01 +0100 Subject: [PATCH 422/740] Fix faction reputation case sensitivity issue (Fixes #2360) --- apps/openmw/mwmechanics/npcstats.cpp | 30 ++++++++++++++-------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index c517b4df8..f6e3090d7 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -125,6 +125,21 @@ bool MWMechanics::NpcStats::isInFaction (const std::string& faction) const return (mFactionRank.find(Misc::StringUtils::lowerCase(faction)) != mFactionRank.end()); } +int MWMechanics::NpcStats::getFactionReputation (const std::string& faction) const +{ + std::map::const_iterator iter = mFactionReputation.find (Misc::StringUtils::lowerCase(faction)); + + if (iter==mFactionReputation.end()) + return 0; + + return iter->second; +} + +void MWMechanics::NpcStats::setFactionReputation (const std::string& faction, int value) +{ + mFactionReputation[Misc::StringUtils::lowerCase(faction)] = value; +} + float MWMechanics::NpcStats::getSkillGain (int skillIndex, const ESM::Class& class_, int usageType, int level, float extraFactor) const { @@ -329,21 +344,6 @@ void MWMechanics::NpcStats::setBounty (int bounty) mBounty = bounty; } -int MWMechanics::NpcStats::getFactionReputation (const std::string& faction) const -{ - std::map::const_iterator iter = mFactionReputation.find (faction); - - if (iter==mFactionReputation.end()) - return 0; - - return iter->second; -} - -void MWMechanics::NpcStats::setFactionReputation (const std::string& faction, int value) -{ - mFactionReputation[faction] = value; -} - int MWMechanics::NpcStats::getReputation() const { return mReputation; From 9dbd9af31c422fd236e300d53e350c7801ff027e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Feb 2015 21:26:58 +0100 Subject: [PATCH 423/740] Adjust fix for Bug #2360 to repair affected savegames --- apps/openmw/mwmechanics/npcstats.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index f6e3090d7..a3a29acab 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -515,7 +515,7 @@ void MWMechanics::NpcStats::readState (const ESM::NpcStats& state) mFactionRank[iter->first] = iter->second.mRank; if (iter->second.mReputation) - mFactionReputation[iter->first] = iter->second.mReputation; + mFactionReputation[Misc::StringUtils::lowerCase(iter->first)] = iter->second.mReputation; } mDisposition = state.mDisposition; From ec3487b669c35e9df8260fa66f0c2f8de904cf5e Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Sun, 8 Feb 2015 14:26:38 -0600 Subject: [PATCH 424/740] Sun trajectory: handle mNightStart <= mSunriseTime OMW Bug #781 Note: mNightStart == mSunriseTime is treated as 24-hour night. --- apps/openmw/mwworld/weather.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index dcd8e5a11..7a36d6ac7 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -429,30 +429,32 @@ void WeatherManager::update(float duration, bool paused) else mRendering->getSkyManager()->sunEnable(); - // Update the sun direction. Run it east to west at 15 degrees south from overhead. - // The sun's speed at day and night will differ, since mSunriseTime and mNightStart + // Update the sun direction. Run it east to west at a fixed angle from overhead. + // The sun's speed at day and night may differ, since mSunriseTime and mNightStart // mark when the sun is level with the horizon. { - assert( mNightStart > mSunriseTime ); - + // Shift times into a 24-hour window beginning at mSunriseTime... float adjustedHour = mHour; + float adjustedNightStart = mNightStart; if ( mHour < mSunriseTime ) adjustedHour += 24.f; + if ( mNightStart < mSunriseTime ) + adjustedNightStart += 24.f; - const bool is_night = mHour >= mNightStart || mHour <= mSunriseTime; - const float dayDuration = mNightStart - mSunriseTime; + const bool is_night = adjustedHour >= adjustedNightStart; + const float dayDuration = adjustedNightStart - mSunriseTime; const float nightDuration = 24.f - dayDuration; double theta; if ( !is_night ) { theta = M_PI * (adjustedHour - mSunriseTime) / dayDuration; } else { - theta = M_PI * (adjustedHour - mNightStart) / nightDuration; + theta = M_PI * (adjustedHour - adjustedNightStart) / nightDuration; } Vector3 final( cos( theta ), - -0.268, // approx tan( 15 degrees ) + -0.268f, // approx tan( -15 degrees ) sin( theta ) ); mRendering->setSunDirection( final, is_night ); } From df5a08b6de043ddde3f1f777921d55f9d43ab33b Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 9 Feb 2015 15:01:49 +0100 Subject: [PATCH 425/740] Move manualref code out of header --- apps/openmw/mwclass/misc.cpp | 1 + apps/openmw/mwdialogue/scripttest.cpp | 1 + apps/openmw/mwgui/tradewindow.cpp | 1 + apps/openmw/mwmechanics/enchanting.cpp | 1 + apps/openmw/mwmechanics/levelledlist.hpp | 1 + apps/openmw/mwmechanics/obstacle.hpp | 2 - .../mwscript/transformationextensions.cpp | 1 + apps/openmw/mwworld/manualref.cpp | 67 +++++++++++++++++++ apps/openmw/mwworld/manualref.hpp | 62 +---------------- apps/openmw/mwworld/projectilemanager.cpp | 1 + 10 files changed, 75 insertions(+), 63 deletions(-) create mode 100644 apps/openmw/mwworld/manualref.cpp diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 271a7510e..f9cfd8e0b 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -12,6 +12,7 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" #include "../mwworld/cellstore.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/manualref.hpp" #include "../mwworld/nullaction.hpp" diff --git a/apps/openmw/mwdialogue/scripttest.cpp b/apps/openmw/mwdialogue/scripttest.cpp index fd477365f..3f4654610 100644 --- a/apps/openmw/mwdialogue/scripttest.cpp +++ b/apps/openmw/mwdialogue/scripttest.cpp @@ -3,6 +3,7 @@ #include #include "../mwworld/manualref.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwworld/class.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 87b2362ef..40cf3e9bf 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -16,6 +16,7 @@ #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwmechanics/creaturestats.hpp" diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 002831acc..de5921a70 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -2,6 +2,7 @@ #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "creaturestats.hpp" diff --git a/apps/openmw/mwmechanics/levelledlist.hpp b/apps/openmw/mwmechanics/levelledlist.hpp index de652a9c8..691996410 100644 --- a/apps/openmw/mwmechanics/levelledlist.hpp +++ b/apps/openmw/mwmechanics/levelledlist.hpp @@ -2,6 +2,7 @@ #define OPENMW_MECHANICS_LEVELLEDLIST_H #include "../mwworld/ptr.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwmechanics/obstacle.hpp b/apps/openmw/mwmechanics/obstacle.hpp index 76ab9d029..e2d4d7b42 100644 --- a/apps/openmw/mwmechanics/obstacle.hpp +++ b/apps/openmw/mwmechanics/obstacle.hpp @@ -1,8 +1,6 @@ #ifndef OPENMW_MECHANICS_OBSTACLE_H #define OPENMW_MECHANICS_OBSTACLE_H -//#include "../mwbase/world.hpp" -//#include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" namespace MWWorld diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index fcfc36995..15fe58065 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -11,6 +11,7 @@ #include "../mwbase/environment.hpp" +#include "../mwworld/cellstore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/manualref.hpp" #include "../mwworld/player.hpp" diff --git a/apps/openmw/mwworld/manualref.cpp b/apps/openmw/mwworld/manualref.cpp new file mode 100644 index 000000000..30b4fe353 --- /dev/null +++ b/apps/openmw/mwworld/manualref.cpp @@ -0,0 +1,67 @@ +#include "manualref.hpp" + +#include "esmstore.hpp" +#include "cellstore.hpp" + +namespace +{ + + template + void create(const MWWorld::Store& list, const std::string& name, boost::any& refValue, MWWorld::Ptr& ptrValue) + { + const T* base = list.find(name); + + ESM::CellRef cellRef; + cellRef.mRefNum.unset(); + cellRef.mRefID = name; + cellRef.mScale = 1; + cellRef.mFactionRank = 0; + cellRef.mChargeInt = -1; + cellRef.mGoldValue = 1; + cellRef.mEnchantmentCharge = -1; + cellRef.mTeleport = false; + cellRef.mLockLevel = 0; + cellRef.mReferenceBlocked = 0; + + MWWorld::LiveCellRef ref(cellRef, base); + + refValue = ref; + ptrValue = MWWorld::Ptr(&boost::any_cast&>(refValue), 0); + } +} + +MWWorld::ManualRef::ManualRef(const MWWorld::ESMStore& store, const std::string& name, const int count) +{ + std::string lowerName = Misc::StringUtils::lowerCase(name); + switch (store.find(lowerName)) + { + case ESM::REC_ACTI: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_ALCH: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_APPA: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_ARMO: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_BOOK: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_CLOT: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_CONT: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_CREA: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_DOOR: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_INGR: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_LEVC: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_LEVI: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_LIGH: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_LOCK: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_MISC: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_NPC_: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_PROB: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_REPA: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_STAT: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_WEAP: create(store.get(), lowerName, mRef, mPtr); break; + + case 0: + throw std::logic_error("failed to create manual cell ref for " + lowerName + " (unknown ID)"); + + default: + throw std::logic_error("failed to create manual cell ref for " + lowerName + " (unknown type)"); + } + + mPtr.getRefData().setCount(count); +} \ No newline at end of file diff --git a/apps/openmw/mwworld/manualref.hpp b/apps/openmw/mwworld/manualref.hpp index f32b07471..2fc599471 100644 --- a/apps/openmw/mwworld/manualref.hpp +++ b/apps/openmw/mwworld/manualref.hpp @@ -3,9 +3,7 @@ #include -#include "esmstore.hpp" #include "ptr.hpp" -#include "cellstore.hpp" namespace MWWorld { @@ -18,66 +16,8 @@ namespace MWWorld ManualRef (const ManualRef&); ManualRef& operator= (const ManualRef&); - template - void create (const MWWorld::Store& list, const std::string& name) - { - const T* base = list.find(name); - - ESM::CellRef cellRef; - cellRef.mRefNum.unset(); - cellRef.mRefID = name; - cellRef.mScale = 1; - cellRef.mFactionRank = 0; - cellRef.mChargeInt = -1; - cellRef.mGoldValue = 1; - cellRef.mEnchantmentCharge = -1; - cellRef.mTeleport = false; - cellRef.mLockLevel = 0; - cellRef.mReferenceBlocked = 0; - - LiveCellRef ref(cellRef, base); - - mRef = ref; - mPtr = Ptr (&boost::any_cast&> (mRef), 0); - } - public: - - ManualRef (const MWWorld::ESMStore& store, const std::string& name, const int count=1) - { - std::string lowerName = Misc::StringUtils::lowerCase (name); - switch (store.find (lowerName)) - { - case ESM::REC_ACTI: create (store.get(), lowerName); break; - case ESM::REC_ALCH: create (store.get(), lowerName); break; - case ESM::REC_APPA: create (store.get(), lowerName); break; - case ESM::REC_ARMO: create (store.get(), lowerName); break; - case ESM::REC_BOOK: create (store.get(), lowerName); break; - case ESM::REC_CLOT: create (store.get(), lowerName); break; - case ESM::REC_CONT: create (store.get(), lowerName); break; - case ESM::REC_CREA: create (store.get(), lowerName); break; - case ESM::REC_DOOR: create (store.get(), lowerName); break; - case ESM::REC_INGR: create (store.get(), lowerName); break; - case ESM::REC_LEVC: create (store.get(), lowerName); break; - case ESM::REC_LEVI: create (store.get(), lowerName); break; - case ESM::REC_LIGH: create (store.get(), lowerName); break; - case ESM::REC_LOCK: create (store.get(), lowerName); break; - case ESM::REC_MISC: create (store.get(), lowerName); break; - case ESM::REC_NPC_: create (store.get(), lowerName); break; - case ESM::REC_PROB: create (store.get(), lowerName); break; - case ESM::REC_REPA: create (store.get(), lowerName); break; - case ESM::REC_STAT: create (store.get(), lowerName); break; - case ESM::REC_WEAP: create (store.get(), lowerName); break; - - case 0: - throw std::logic_error ("failed to create manual cell ref for " + lowerName + " (unknown ID)"); - - default: - throw std::logic_error ("failed to create manual cell ref for " + lowerName + " (unknown type)"); - } - - mPtr.getRefData().setCount(count); - } + ManualRef(const MWWorld::ESMStore& store, const std::string& name, const int count = 1); const Ptr& getPtr() const { diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 7af51fd28..c97e4e3a5 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -9,6 +9,7 @@ #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwbase/soundmanager.hpp" From 8c49812d56f428c630fa3ab375e5a906f1b106e6 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 9 Feb 2015 15:12:10 +0100 Subject: [PATCH 426/740] Remove unneeded include in obstacle.hpp --- apps/openmw/mwmechanics/aiwander.hpp | 1 + apps/openmw/mwmechanics/obstacle.hpp | 2 -- apps/openmw/mwworld/worldimp.cpp | 1 + 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 975ebfb81..5e1b41813 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -17,6 +17,7 @@ namespace ESM { + class Cell; namespace AiSequence { struct AiWander; diff --git a/apps/openmw/mwmechanics/obstacle.hpp b/apps/openmw/mwmechanics/obstacle.hpp index e2d4d7b42..e0ae9203d 100644 --- a/apps/openmw/mwmechanics/obstacle.hpp +++ b/apps/openmw/mwmechanics/obstacle.hpp @@ -1,8 +1,6 @@ #ifndef OPENMW_MECHANICS_OBSTACLE_H #define OPENMW_MECHANICS_OBSTACLE_H -#include "../mwworld/cellstore.hpp" - namespace MWWorld { class Ptr; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a8238d161..3ed273967 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -44,6 +44,7 @@ #include "player.hpp" #include "manualref.hpp" +#include "cellstore.hpp" #include "cellfunctors.hpp" #include "containerstore.hpp" #include "inventorystore.hpp" From d3128a12b6bdb6deb579b4098e0f7e066358daf3 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 9 Feb 2015 16:23:41 +0100 Subject: [PATCH 427/740] Remove a large include form mwbase/windowmanager.hpp --- apps/openmw/mwbase/windowmanager.hpp | 12 ++++++++++-- apps/openmw/mwgui/journalwindow.cpp | 1 + apps/openmw/mwgui/settingswindow.cpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 1 + apps/openmw/mwgui/windowmanagerimp.hpp | 1 + apps/openmw/mwmechanics/npcstats.hpp | 2 -- apps/openmw/mwscript/containerextensions.cpp | 2 ++ 7 files changed, 16 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index c984b5e54..0d0731265 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -1,11 +1,11 @@ #ifndef GAME_MWBASE_WINDOWMANAGER_H #define GAME_MWBASE_WINDOWMANAGER_H +#include #include #include #include - -#include "../mwmechanics/stat.hpp" +#include #include "../mwgui/mode.hpp" @@ -42,6 +42,14 @@ namespace ESM struct CellId; } +namespace MWMechanics +{ + class AttributeValue; + template + class DynamicStat; + class SkillValue; +} + namespace MWWorld { class CellStore; diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index afff5601a..d7e27a277 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 281093452..a4f87e598 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -14,6 +14,7 @@ #include +#include #include #include diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 715f47c46..7f32f2b27 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -42,6 +42,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwmechanics/stat.hpp" #include "../mwmechanics/npcstats.hpp" #include "../mwsound/soundmanagerimp.hpp" diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 9f01b136c..dfeef982b 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -12,6 +12,7 @@ #include "../mwbase/windowmanager.hpp" #include +#include #include "mapwindow.hpp" diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index 224366a3e..0b9090f28 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -6,8 +6,6 @@ #include #include -#include "stat.hpp" - #include "creaturestats.hpp" namespace ESM diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 58b1b375b..69dfc9972 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -14,6 +14,8 @@ #include #include +#include + #include #include "../mwbase/environment.hpp" From f2c5060cc09fd17a4fab0c5c4c36ca6c03e66670 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 9 Feb 2015 16:37:20 +0100 Subject: [PATCH 428/740] Fix cstdint issue on travis GCC build --- apps/openmw/mwbase/windowmanager.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 0d0731265..36a99306b 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -1,7 +1,7 @@ #ifndef GAME_MWBASE_WINDOWMANAGER_H #define GAME_MWBASE_WINDOWMANAGER_H -#include +#include #include #include #include From cfcaf4528fa7f11a283afdd17276c4b5d1d9531c Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 9 Feb 2015 16:50:34 +0100 Subject: [PATCH 429/740] Some more forward-declaring for OpenMW-CS --- apps/opencs/model/world/pathgrid.cpp | 3 ++- apps/opencs/model/world/pathgrid.hpp | 9 ++++++--- apps/opencs/model/world/subcellcollection.hpp | 11 ++++++++++- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/apps/opencs/model/world/pathgrid.cpp b/apps/opencs/model/world/pathgrid.cpp index 1c82585df..5c66e7d8e 100644 --- a/apps/opencs/model/world/pathgrid.cpp +++ b/apps/opencs/model/world/pathgrid.cpp @@ -1,4 +1,5 @@ - +#include "cell.hpp" +#include "idcollection.hpp" #include "pathgrid.hpp" #include diff --git a/apps/opencs/model/world/pathgrid.hpp b/apps/opencs/model/world/pathgrid.hpp index 3c9fcff50..7ce5aff8c 100644 --- a/apps/opencs/model/world/pathgrid.hpp +++ b/apps/opencs/model/world/pathgrid.hpp @@ -6,11 +6,14 @@ #include -#include "idcollection.hpp" -#include "cell.hpp" - namespace CSMWorld { + struct Cell; + template + struct IdAccessor; + template> + class IdCollection; + /// \brief Wrapper for Pathgrid record /// /// \attention The mData.mX and mData.mY fields of the ESM::Pathgrid struct are not used. diff --git a/apps/opencs/model/world/subcellcollection.hpp b/apps/opencs/model/world/subcellcollection.hpp index 28f0de695..2100df4f4 100644 --- a/apps/opencs/model/world/subcellcollection.hpp +++ b/apps/opencs/model/world/subcellcollection.hpp @@ -1,10 +1,19 @@ #ifndef CSM_WOLRD_SUBCOLLECTION_H #define CSM_WOLRD_SUBCOLLECTION_H -#include "idcollection.hpp" +namespace ESM +{ + class ESMReader; +} namespace CSMWorld { + struct Cell; + template + struct IdAccessor; + template> + class IdCollection; + /// \brief Single type collection of top level records that are associated with cells template > class SubCellCollection : public IdCollection From f77ae711e426d873eefc8fc53af9a0b6b9c3b76b Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 9 Feb 2015 17:10:09 +0100 Subject: [PATCH 430/740] Fix template closer --- apps/opencs/model/world/pathgrid.hpp | 2 +- apps/opencs/model/world/subcellcollection.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/pathgrid.hpp b/apps/opencs/model/world/pathgrid.hpp index 7ce5aff8c..f13ad38c0 100644 --- a/apps/opencs/model/world/pathgrid.hpp +++ b/apps/opencs/model/world/pathgrid.hpp @@ -11,7 +11,7 @@ namespace CSMWorld struct Cell; template struct IdAccessor; - template> + template > class IdCollection; /// \brief Wrapper for Pathgrid record diff --git a/apps/opencs/model/world/subcellcollection.hpp b/apps/opencs/model/world/subcellcollection.hpp index 2100df4f4..4ed4308ea 100644 --- a/apps/opencs/model/world/subcellcollection.hpp +++ b/apps/opencs/model/world/subcellcollection.hpp @@ -11,7 +11,7 @@ namespace CSMWorld struct Cell; template struct IdAccessor; - template> + template > class IdCollection; /// \brief Single type collection of top level records that are associated with cells From b714e5211d19a341a95bc10bcf4c9e0ef7271227 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 9 Feb 2015 17:25:55 +0100 Subject: [PATCH 431/740] Redefinition of default template argument Sometimes it's annoying how MSVC casually allows you to break C++ standards --- apps/opencs/model/world/pathgrid.hpp | 4 +--- apps/opencs/model/world/subcellcollection.hpp | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/world/pathgrid.hpp b/apps/opencs/model/world/pathgrid.hpp index f13ad38c0..d8cc89f24 100644 --- a/apps/opencs/model/world/pathgrid.hpp +++ b/apps/opencs/model/world/pathgrid.hpp @@ -9,9 +9,7 @@ namespace CSMWorld { struct Cell; - template - struct IdAccessor; - template > + template class IdCollection; /// \brief Wrapper for Pathgrid record diff --git a/apps/opencs/model/world/subcellcollection.hpp b/apps/opencs/model/world/subcellcollection.hpp index 4ed4308ea..74bb6c955 100644 --- a/apps/opencs/model/world/subcellcollection.hpp +++ b/apps/opencs/model/world/subcellcollection.hpp @@ -9,9 +9,7 @@ namespace ESM namespace CSMWorld { struct Cell; - template - struct IdAccessor; - template > + template class IdCollection; /// \brief Single type collection of top level records that are associated with cells From fce404acc5b09a8989444bd155f6fe939a4ac749 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 9 Feb 2015 17:45:48 +0100 Subject: [PATCH 432/740] Remove some including of mwbase/world.hpp Since ref.hpp is rather well used in OpenMW-CS this should help compile times there --- apps/openmw/mwscript/animationextensions.cpp | 1 + apps/openmw/mwscript/containerextensions.cpp | 1 + apps/openmw/mwscript/controlextensions.cpp | 1 + apps/openmw/mwscript/dialogueextensions.cpp | 1 + apps/openmw/mwscript/guiextensions.cpp | 2 +- apps/openmw/mwscript/miscextensions.cpp | 1 + apps/openmw/mwscript/ref.cpp | 29 ++++++++++++++++ apps/openmw/mwscript/ref.hpp | 33 +++++-------------- apps/openmw/mwscript/statsextensions.cpp | 1 + .../mwscript/transformationextensions.cpp | 1 + 10 files changed, 45 insertions(+), 26 deletions(-) create mode 100644 apps/openmw/mwscript/ref.cpp diff --git a/apps/openmw/mwscript/animationextensions.cpp b/apps/openmw/mwscript/animationextensions.cpp index 00b8a9620..c43cdf565 100644 --- a/apps/openmw/mwscript/animationextensions.cpp +++ b/apps/openmw/mwscript/animationextensions.cpp @@ -11,6 +11,7 @@ #include #include +#include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "interpretercontext.hpp" diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 69dfc9972..86329191e 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -20,6 +20,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" diff --git a/apps/openmw/mwscript/controlextensions.cpp b/apps/openmw/mwscript/controlextensions.cpp index fb6b73be6..fd7fe4737 100644 --- a/apps/openmw/mwscript/controlextensions.cpp +++ b/apps/openmw/mwscript/controlextensions.cpp @@ -10,6 +10,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/inputmanager.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwworld/ptr.hpp" diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index ea4b8d06e..8b6805264 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -11,6 +11,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/dialoguemanager.hpp" #include "../mwbase/journal.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwmechanics/npcstats.hpp" diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index f5549a172..40c555f50 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -12,7 +12,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" - +#include "../mwbase/world.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "interpretercontext.hpp" diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index bffeef768..f4e82ebd4 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -17,6 +17,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/scriptmanager.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" diff --git a/apps/openmw/mwscript/ref.cpp b/apps/openmw/mwscript/ref.cpp new file mode 100644 index 000000000..6347c2c2e --- /dev/null +++ b/apps/openmw/mwscript/ref.cpp @@ -0,0 +1,29 @@ +#include "ref.hpp" + +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +#include "interpretercontext.hpp" + +MWWorld::Ptr MWScript::ExplicitRef::operator() (Interpreter::Runtime& runtime, bool required, + bool activeOnly) const +{ + std::string id = runtime.getStringLiteral(runtime[0].mInteger); + runtime.pop(); + + if (required) + return MWBase::Environment::get().getWorld()->getPtr(id, activeOnly); + else + return MWBase::Environment::get().getWorld()->searchPtr(id, activeOnly); +} + +MWWorld::Ptr MWScript::ImplicitRef::operator() (Interpreter::Runtime& runtime, bool required, + bool activeOnly) const +{ + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + return context.getReference(required); +} diff --git a/apps/openmw/mwscript/ref.hpp b/apps/openmw/mwscript/ref.hpp index 18f7453e4..e572f5147 100644 --- a/apps/openmw/mwscript/ref.hpp +++ b/apps/openmw/mwscript/ref.hpp @@ -3,14 +3,12 @@ #include -#include - -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" - #include "../mwworld/ptr.hpp" -#include "interpretercontext.hpp" +namespace Interpreter +{ + class Runtime; +} namespace MWScript { @@ -18,31 +16,16 @@ namespace MWScript { static const bool implicit = false; - MWWorld::Ptr operator() (Interpreter::Runtime& runtime, bool required=true, - bool activeOnly = false) const - { - std::string id = runtime.getStringLiteral (runtime[0].mInteger); - runtime.pop(); - - if (required) - return MWBase::Environment::get().getWorld()->getPtr (id, activeOnly); - else - return MWBase::Environment::get().getWorld()->searchPtr (id, activeOnly); - } + MWWorld::Ptr operator() (Interpreter::Runtime& runtime, bool required = true, + bool activeOnly = false) const; }; struct ImplicitRef { static const bool implicit = true; - MWWorld::Ptr operator() (Interpreter::Runtime& runtime, bool required=true, - bool activeOnly = false) const - { - MWScript::InterpreterContext& context - = static_cast (runtime.getContext()); - - return context.getReference(required); - } + MWWorld::Ptr operator() (Interpreter::Runtime& runtime, bool required = true, + bool activeOnly = false) const; }; } diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index abef636cc..b8bb76388 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -18,6 +18,7 @@ #include "../mwbase/dialoguemanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 15fe58065..7af35a9ff 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -10,6 +10,7 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/class.hpp" From a7320781a5e46400f359de39c032fbc233954919 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 9 Feb 2015 17:58:33 +0100 Subject: [PATCH 433/740] updated credits file --- AUTHORS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AUTHORS.md b/AUTHORS.md index bc39b1c70..59aa42721 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -33,7 +33,7 @@ Programmers Douglas Diniz (Dgdiniz) Douglas Mencken (dougmencken) dreamer-dead - dteviot + David Teviotdale (dteviot) Edmondo Tommasina (edmondo) Eduard Cot (trombonecot) Eli2 From dbd4abd6fe3ae3b3f1e812c8069b094bad50846e Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Feb 2015 19:28:29 +0100 Subject: [PATCH 434/740] Fix ripples for D3D - added simpler effect (Fixes #1649) --- apps/openmw/engine.cpp | 1 + apps/openmw/mwrender/renderconst.hpp | 1 + apps/openmw/mwrender/renderingmanager.cpp | 3 +- apps/openmw/mwrender/ripplesimulation.cpp | 275 ++++++------------ apps/openmw/mwrender/ripplesimulation.hpp | 62 ++-- apps/openmw/mwrender/water.cpp | 20 +- apps/openmw/mwrender/water.hpp | 9 +- apps/openmw/mwworld/fallback.cpp | 9 + apps/openmw/mwworld/fallback.hpp | 1 + files/CMakeLists.txt | 7 +- files/materials/ripples.particle | 26 ++ files/materials/water.mat | 24 ++ files/materials/water.shader | 17 +- files/materials/watersim.mat | 59 ---- files/materials/watersim.shaderset | 31 -- files/materials/watersim_addimpulse.shader | 12 - files/materials/watersim_common.h | 25 -- files/materials/watersim_heightmap.shader | 51 ---- .../materials/watersim_heighttonormal.shader | 36 --- 19 files changed, 195 insertions(+), 474 deletions(-) create mode 100644 files/materials/ripples.particle delete mode 100644 files/materials/watersim.mat delete mode 100644 files/materials/watersim.shaderset delete mode 100644 files/materials/watersim_addimpulse.shader delete mode 100644 files/materials/watersim_common.h delete mode 100644 files/materials/watersim_heightmap.shader delete mode 100644 files/materials/watersim_heighttonormal.shader diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 859baebe4..9b87c612d 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -349,6 +349,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) addResourcesDirectory(mResDir / "mygui"); addResourcesDirectory(mResDir / "water"); addResourcesDirectory(mResDir / "shadows"); + addResourcesDirectory(mResDir / "materials"); OEngine::Render::WindowSettings windowSettings; windowSettings.fullscreen = settings.getBool("fullscreen", "Video"); diff --git a/apps/openmw/mwrender/renderconst.hpp b/apps/openmw/mwrender/renderconst.hpp index 4ac21ad51..cfd84cb32 100644 --- a/apps/openmw/mwrender/renderconst.hpp +++ b/apps/openmw/mwrender/renderconst.hpp @@ -21,6 +21,7 @@ enum RenderQueueGroups RQG_UnderWater = Ogre::RENDER_QUEUE_4, RQG_Water = RQG_Alpha, + RQG_Ripples = RQG_Water+1, // Sky late (sun & sun flare) RQG_SkiesLate = Ogre::RENDER_QUEUE_SKIES_LATE diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 88ede1682..8b7f04b19 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -175,7 +175,7 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b mDebugging = new Debugging(mRootNode, engine); mLocalMap = new MWRender::LocalMap(&mRendering, this); - mWater = new MWRender::Water(mRendering.getCamera(), this); + mWater = new MWRender::Water(mRendering.getCamera(), this, mFallback); setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI")); } @@ -693,6 +693,7 @@ void RenderingManager::enableLights(bool sun) void RenderingManager::notifyWorldSpaceChanged() { mEffectManager->clear(); + mWater->clearRipples(); } Ogre::Vector4 RenderingManager::boundingBoxToScreen(Ogre::AxisAlignedBox bounds) diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index 64b5e48c3..84794162f 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -1,162 +1,72 @@ #include "ripplesimulation.hpp" -#include -#include -#include -#include -#include +#include + #include -#include -#include +#include +#include +#include #include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" -namespace MWRender -{ +#include "../mwworld/fallback.hpp" +#include "renderconst.hpp" -RippleSimulation::RippleSimulation(Ogre::SceneManager* mainSceneManager) - : mMainSceneMgr(mainSceneManager), - mTime(0), - mCurrentFrameOffset(0,0), - mPreviousFrameOffset(0,0), - mRippleCenter(0,0), - mTextureSize(512), - mRippleAreaLength(1000), - mImpulseSize(20), - mTexelOffset(0,0), - mFirstUpdate(true), - mRectangle(NULL), - mImpulse(NULL) +namespace MWRender { - Ogre::AxisAlignedBox aabInf; - aabInf.setInfinite(); - - mSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC); - - mCamera = mSceneMgr->createCamera("RippleCamera"); - - mRectangle = new Ogre::Rectangle2D(true); - mRectangle->setBoundingBox(aabInf); - mRectangle->setCorners(-1.0, 1.0, 1.0, -1.0, false); - Ogre::SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode(); - node->attachObject(mRectangle); - mImpulse = new Ogre::Rectangle2D(true); - mImpulse->setCorners(-0.1, 0.1, 0.1, -0.1, false); - mImpulse->setBoundingBox(aabInf); - mImpulse->setMaterial("AddImpulse"); - Ogre::SceneNode* impulseNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); - impulseNode->attachObject(mImpulse); - - //float w=0.05; - for (int i=0; i<4; ++i) - { - Ogre::TexturePtr texture; - if (i != 3) - texture = Ogre::TextureManager::getSingleton().createManual("RippleHeight" + Ogre::StringConverter::toString(i), - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, mTextureSize, mTextureSize, 1, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET); - else - texture = Ogre::TextureManager::getSingleton().createManual("RippleNormal", - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, mTextureSize, mTextureSize, 1, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET); - - - Ogre::RenderTexture* rt = texture->getBuffer()->getRenderTarget(); - rt->removeAllViewports(); - rt->addViewport(mCamera); - rt->setAutoUpdated(false); - rt->getViewport(0)->setClearEveryFrame(false); +RippleSimulation::RippleSimulation(Ogre::SceneManager* mainSceneManager, const MWWorld::Fallback* fallback) + : mSceneMgr(mainSceneManager) + , mParticleSystem(NULL) + , mSceneNode(NULL) +{ + mRippleLifeTime = fallback->getFallbackFloat("Water_RippleLifetime"); + mRippleRotSpeed = fallback->getFallbackFloat("Water_RippleRotSpeed"); - // debug overlay - /* - Ogre::Rectangle2D* debugOverlay = new Ogre::Rectangle2D(true); - debugOverlay->setCorners(w*2-1, 0.9, (w+0.18)*2-1, 0.4, false); - w += 0.2; - debugOverlay->setBoundingBox(aabInf); - Ogre::SceneNode* debugNode = mMainSceneMgr->getRootSceneNode()->createChildSceneNode(); - debugNode->attachObject(debugOverlay); + // Unknown: + // fallback=Water_RippleScale,0.15, 6.5 + // fallback=Water_RippleAlphas,0.7, 0.1, 0.01 - Ogre::MaterialPtr debugMaterial = Ogre::MaterialManager::getSingleton().create("RippleDebug" + Ogre::StringConverter::toString(i), - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); + // Instantiate from ripples.particle file + mParticleSystem = mSceneMgr->createParticleSystem("openmw/Ripples", "openmw/Ripples"); - if (i != 3) - debugMaterial->getTechnique(0)->getPass(0)->createTextureUnitState("RippleHeight" + Ogre::StringConverter::toString(i)); - else - debugMaterial->getTechnique(0)->getPass(0)->createTextureUnitState("RippleNormal"); - debugMaterial->getTechnique(0)->getPass(0)->setLightingEnabled(false); + mParticleSystem->setRenderQueueGroup(RQG_Ripples); + mParticleSystem->setVisibilityFlags(RV_Effects); - debugOverlay->setMaterial("RippleDebug" + Ogre::StringConverter::toString(i)); - */ + int rippleFrameCount = fallback->getFallbackInt("Water_RippleFrameCount"); + std::string tex = fallback->getFallbackString("Water_RippleTexture"); - mRenderTargets[i] = rt; - mTextures[i] = texture; - } + sh::MaterialInstance* mat = sh::Factory::getInstance().getMaterialInstance("openmw/Ripple"); + mat->setProperty("anim_texture2", sh::makeProperty(new sh::StringValue(std::string("textures\\water\\") + tex + ".dds " + + Ogre::StringConverter::toString(rippleFrameCount) + + " " + + Ogre::StringConverter::toString(0.3)))); - sh::Factory::getInstance().setSharedParameter("rippleTextureSize", sh::makeProperty( - new sh::Vector4(1.0/512, 1.0/512, 512, 512))); - sh::Factory::getInstance().setSharedParameter("rippleCenter", sh::makeProperty( - new sh::Vector3(0, 0, 0))); - sh::Factory::getInstance().setSharedParameter("rippleAreaLength", sh::makeProperty( - new sh::FloatValue(mRippleAreaLength))); + // seems to be required to allocate mFreeParticles. TODO: patch Ogre to handle this better + mParticleSystem->_update(0.f); + mSceneNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); + mSceneNode->attachObject(mParticleSystem); } RippleSimulation::~RippleSimulation() { - delete mRectangle; - delete mImpulse; + if (mParticleSystem) + mSceneMgr->destroyParticleSystem(mParticleSystem); + mParticleSystem = NULL; - Ogre::Root::getSingleton().destroySceneManager(mSceneMgr); + if (mSceneNode) + mSceneMgr->destroySceneNode(mSceneNode); + mSceneNode = NULL; } void RippleSimulation::update(float dt, Ogre::Vector2 position) { - // try to keep 20 fps - mTime += dt; - - while (mTime >= 1/20.0 || mFirstUpdate) - { - mPreviousFrameOffset = mCurrentFrameOffset; - - mCurrentFrameOffset = position - mRippleCenter; - // add texel offsets from previous frame. - mCurrentFrameOffset += mTexelOffset; - - mTexelOffset = Ogre::Vector2(std::fmod(mCurrentFrameOffset.x, 1.0f/mTextureSize), - std::fmod(mCurrentFrameOffset.y, 1.0f/mTextureSize)); - - // now subtract new offset in order to snap to texels - mCurrentFrameOffset -= mTexelOffset; - - // texture coordinate space - mCurrentFrameOffset /= mRippleAreaLength; - - mRippleCenter = position; - - addImpulses(); - waterSimulation(); - heightMapToNormalMap(); - - swapHeightMaps(); - if (!mFirstUpdate) - mTime -= 1/20.0; - else - mFirstUpdate = false; - } - - sh::Factory::getInstance().setSharedParameter("rippleCenter", sh::makeProperty( - new sh::Vector3(mRippleCenter.x + mTexelOffset.x, mRippleCenter.y + mTexelOffset.y, 0))); -} - -void RippleSimulation::addImpulses() -{ - mRectangle->setVisible(false); - mImpulse->setVisible(true); - - /// \todo it should be more efficient to render all emitters at once + bool newParticle = false; for (std::vector::iterator it=mEmitters.begin(); it !=mEmitters.end(); ++it) { if (it->mPtr == MWBase::Environment::get().getWorld ()->getPlayerPtr()) @@ -165,69 +75,50 @@ void RippleSimulation::addImpulses() // for non-player actors this is done in updateObjectCell it->mPtr = MWBase::Environment::get().getWorld ()->getPlayerPtr(); } - const float* _currentPos = it->mPtr.getRefData().getPosition().pos; - Ogre::Vector3 currentPos (_currentPos[0], _currentPos[1], _currentPos[2]); - - if ( (currentPos - it->mLastEmitPosition).length() > 2 - && MWBase::Environment::get().getWorld ()->isUnderwater (it->mPtr.getCell(), currentPos)) + Ogre::Vector3 currentPos (it->mPtr.getRefData().getPosition().pos); + currentPos.z = 0; + if ( (currentPos - it->mLastEmitPosition).length() > 10 + // Only emit when close to the water surface, not above it and not too deep in the water + && MWBase::Environment::get().getWorld ()->isUnderwater (it->mPtr.getCell(), + Ogre::Vector3(it->mPtr.getRefData().getPosition().pos)) + && !MWBase::Environment::get().getWorld()->isSubmerged(it->mPtr)) { it->mLastEmitPosition = currentPos; - Ogre::Vector2 pos (currentPos.x, currentPos.y); - pos -= mRippleCenter; - pos /= mRippleAreaLength; - float size = mImpulseSize / mRippleAreaLength; - mImpulse->setCorners(pos.x-size, pos.y+size, pos.x+size, pos.y-size, false); - - // don't render if we are offscreen - if (pos.x - size >= 1.0 || pos.y+size <= -1.0 || pos.x+size <= -1.0 || pos.y-size >= 1.0) - continue; - mRenderTargets[1]->update(); + newParticle = true; + Ogre::Particle* created = mParticleSystem->createParticle(); + if (!created) + break; // TODO: cleanup the oldest particle to make room +#if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) + Ogre::Vector3& position = created->mPosition; + Ogre::Vector3& direction = created->mDirection; + Ogre::ColourValue& colour = created->mColour; + float& totalTimeToLive = created->mTotalTimeToLive; + float& timeToLive = created->mTimeToLive; + Ogre::Radian& rotSpeed = created->mRotationSpeed; + Ogre::Radian& rotation = created->mRotation; +#else + Ogre::Vector3& position = created->position; + Ogre::Vector3& direction = created->direction; + Ogre::ColourValue& colour = created->colour; + float& totalTimeToLive = created->totalTimeToLive; + float& timeToLive = created->timeToLive; + Ogre::Radian& rotSpeed = created->rotationSpeed; + Ogre::Radian& rotation = created->rotation; +#endif + timeToLive = totalTimeToLive = mRippleLifeTime; + colour = Ogre::ColourValue(0.f, 0.f, 0.f, 0.7); // Water_RippleAlphas.x? + direction = Ogre::Vector3(0,0,0); + position = currentPos; + position.z = 0; // Z is set by the Scene Node + rotSpeed = mRippleRotSpeed; + rotation = Ogre::Radian(Ogre::Math::RangeRandom(-Ogre::Math::PI, Ogre::Math::PI)); + created->setDimensions(50,50); } } - mImpulse->setVisible(false); - mRectangle->setVisible(true); -} - -void RippleSimulation::waterSimulation() -{ - mRectangle->setMaterial("HeightmapSimulation"); - - sh::Factory::getInstance().setTextureAlias("Heightmap0", mTextures[0]->getName()); - sh::Factory::getInstance().setTextureAlias("Heightmap1", mTextures[1]->getName()); - - sh::Factory::getInstance().setSharedParameter("currentFrameOffset", sh::makeProperty( - new sh::Vector3(mCurrentFrameOffset.x, mCurrentFrameOffset.y, 0))); - sh::Factory::getInstance().setSharedParameter("previousFrameOffset", sh::makeProperty( - new sh::Vector3(mPreviousFrameOffset.x, mPreviousFrameOffset.y, 0))); - - mRenderTargets[2]->update(); -} - -void RippleSimulation::heightMapToNormalMap() -{ - mRectangle->setMaterial("HeightToNormalMap"); - - sh::Factory::getInstance().setTextureAlias("Heightmap2", mTextures[2]->getName()); - - mRenderTargets[TEX_NORMAL]->update(); -} - -void RippleSimulation::swapHeightMaps() -{ - // 0 -> 1 -> 2 to 2 -> 0 ->1 - Ogre::RenderTexture* tmp = mRenderTargets[0]; - Ogre::TexturePtr tmp2 = mTextures[0]; - - mRenderTargets[0] = mRenderTargets[1]; - mTextures[0] = mTextures[1]; - - mRenderTargets[1] = mRenderTargets[2]; - mTextures[1] = mTextures[2]; - - mRenderTargets[2] = tmp; - mTextures[2] = tmp2; + if (newParticle) // now apparently needs another update, otherwise it won't render in the first frame after a particle is created. TODO: patch Ogre to handle this better + mParticleSystem->_update(0.f); } void RippleSimulation::addEmitter(const MWWorld::Ptr& ptr, float scale, float force) @@ -264,5 +155,15 @@ void RippleSimulation::updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld: } } +void RippleSimulation::setWaterHeight(float height) +{ + mSceneNode->setPosition(0,0,height); +} + +void RippleSimulation::clear() +{ + mParticleSystem->clear(); +} + } diff --git a/apps/openmw/mwrender/ripplesimulation.hpp b/apps/openmw/mwrender/ripplesimulation.hpp index e203212cf..4551476a4 100644 --- a/apps/openmw/mwrender/ripplesimulation.hpp +++ b/apps/openmw/mwrender/ripplesimulation.hpp @@ -1,19 +1,19 @@ #ifndef RIPPLE_SIMULATION_H #define RIPPLE_SIMULATION_H -#include -#include -#include #include #include "../mwworld/ptr.hpp" namespace Ogre { - class RenderTexture; - class Camera; class SceneManager; - class Rectangle2D; + class ParticleSystem; +} + +namespace MWWorld +{ + class Fallback; } namespace MWRender @@ -30,9 +30,11 @@ struct Emitter class RippleSimulation { public: - RippleSimulation(Ogre::SceneManager* mainSceneManager); + RippleSimulation(Ogre::SceneManager* mainSceneManager, const MWWorld::Fallback* fallback); ~RippleSimulation(); + /// @param dt Time since the last frame + /// @param position Position of the player void update(float dt, Ogre::Vector2 position); /// adds an emitter, position will be tracked automatically @@ -40,47 +42,21 @@ public: void removeEmitter (const MWWorld::Ptr& ptr); void updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr); -private: - RippleSimulation(const RippleSimulation&); - RippleSimulation& operator=(const RippleSimulation&); - - std::vector mEmitters; - - Ogre::RenderTexture* mRenderTargets[4]; - Ogre::TexturePtr mTextures[4]; - - int mTextureSize; - float mRippleAreaLength; - float mImpulseSize; - - bool mFirstUpdate; + /// Change the height of the water surface, thus moving all ripples with it + void setWaterHeight(float height); - Ogre::Camera* mCamera; + /// Remove all active ripples + void clear(); - // own scenemanager to render our simulation +private: Ogre::SceneManager* mSceneMgr; - Ogre::Rectangle2D* mRectangle; - - // scenemanager to create the debug overlays on - Ogre::SceneManager* mMainSceneMgr; - - static const int TEX_NORMAL = 3; - - Ogre::Rectangle2D* mImpulse; + Ogre::ParticleSystem* mParticleSystem; + Ogre::SceneNode* mSceneNode; - void addImpulses(); - void heightMapToNormalMap(); - void waterSimulation(); - void swapHeightMaps(); - - float mTime; - - Ogre::Vector2 mRippleCenter; - - Ogre::Vector2 mTexelOffset; + std::vector mEmitters; - Ogre::Vector2 mCurrentFrameOffset; - Ogre::Vector2 mPreviousFrameOffset; + float mRippleLifeTime; + float mRippleRotSpeed; }; } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 44e184269..456fc47e9 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -20,9 +20,6 @@ #include #include -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" - using namespace Ogre; namespace MWRender @@ -187,7 +184,7 @@ void PlaneReflection::setVisibilityMask (int flags) // -------------------------------------------------------------------------------------------------------------------------------- -Water::Water (Ogre::Camera *camera, RenderingManager* rend) : +Water::Water (Ogre::Camera *camera, RenderingManager* rend, const MWWorld::Fallback* fallback) : mCamera (camera), mSceneMgr (camera->getSceneManager()), mIsUnderwater(false), mVisibilityFlags(0), mActive(1), mToggled(1), @@ -198,7 +195,7 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend) : mSimulation(NULL), mPlayer(0,0) { - mSimulation = new RippleSimulation(mSceneMgr); + mSimulation = new RippleSimulation(mSceneMgr, fallback); mSky = rend->getSkyManager(); @@ -313,6 +310,8 @@ void Water::setHeight(const float height) { mTop = height; + mSimulation->setWaterHeight(height); + mWaterPlane = Plane(Vector3::UNIT_Z, -height); if (mReflection) @@ -382,9 +381,13 @@ void Water::update(float dt, Ogre::Vector3 player) void Water::frameStarted(float dt) { + if (!mActive) + return; + + mSimulation->update(dt, mPlayer); + if (mReflection) { - mSimulation->update(dt, mPlayer); mReflection->update(); } } @@ -497,4 +500,9 @@ void Water::updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr) mSimulation->updateEmitterPtr(old, ptr); } +void Water::clearRipples() +{ + mSimulation->clear(); +} + } // namespace diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 6a7b05a3a..10d0a06ff 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -30,6 +30,11 @@ namespace Ogre struct RenderTargetEvent; } +namespace MWWorld +{ + class Fallback; +} + namespace MWRender { class SkyManager; @@ -145,9 +150,11 @@ namespace MWRender { Ogre::Vector2 mPlayer; public: - Water (Ogre::Camera *camera, RenderingManager* rend); + Water (Ogre::Camera *camera, RenderingManager* rend, const MWWorld::Fallback* fallback); ~Water(); + void clearRipples(); + void setActive(bool active); bool toggle(); diff --git a/apps/openmw/mwworld/fallback.cpp b/apps/openmw/mwworld/fallback.cpp index c0b21b2ef..3a8154ca7 100644 --- a/apps/openmw/mwworld/fallback.cpp +++ b/apps/openmw/mwworld/fallback.cpp @@ -22,6 +22,15 @@ namespace MWWorld else return boost::lexical_cast(fallback); } + int Fallback::getFallbackInt(const std::string& fall) const + { + std::string fallback=getFallbackString(fall); + if(fallback.empty()) + return 0; + else + return boost::lexical_cast(fallback); + } + bool Fallback::getFallbackBool(const std::string& fall) const { std::string fallback=getFallbackString(fall); diff --git a/apps/openmw/mwworld/fallback.hpp b/apps/openmw/mwworld/fallback.hpp index 6c5802e07..f69a5e57b 100644 --- a/apps/openmw/mwworld/fallback.hpp +++ b/apps/openmw/mwworld/fallback.hpp @@ -15,6 +15,7 @@ namespace MWWorld Fallback(const std::map& fallback); std::string getFallbackString(const std::string& fall) const; float getFallbackFloat(const std::string& fall) const; + int getFallbackInt(const std::string& fall) const; bool getFallbackBool(const std::string& fall) const; Ogre::ColourValue getFallbackColour(const std::string& fall) const; }; diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt index 9b2325744..da3451d93 100644 --- a/files/CMakeLists.txt +++ b/files/CMakeLists.txt @@ -38,15 +38,10 @@ set(MATERIAL_FILES selection.mat selection.shader selection.shaderset - watersim_heightmap.shader - watersim_addimpulse.shader - watersim_heighttonormal.shader - watersim_common.h - watersim.mat - watersim.shaderset mygui.mat mygui.shader mygui.shaderset + ripples.particle ) copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/water "${OpenMW_BINARY_DIR}/resources/water/" "${WATER_FILES}") diff --git a/files/materials/ripples.particle b/files/materials/ripples.particle new file mode 100644 index 000000000..e8402b691 --- /dev/null +++ b/files/materials/ripples.particle @@ -0,0 +1,26 @@ +particle_system openmw/Ripples +{ + material openmw/Ripple + particle_width 50 + particle_height 50 + // To make the particles move with the scene node when the waterlevel changes + local_space true + quota 300 + billboard_type perpendicular_common + common_up_vector 0 1 0 + common_direction 0 0 1 + + affector ColourFader + { + alpha -0.33 + } + + affector Scaler + { + rate 100 + } + + affector Rotator + { + } +} diff --git a/files/materials/water.mat b/files/materials/water.mat index ade55f326..cf03be39e 100644 --- a/files/materials/water.mat +++ b/files/materials/water.mat @@ -75,3 +75,27 @@ material Water } } } + +material openmw/Ripple +{ + // this will be overridden by Water_RippleFrameCount fallback setting + anim_texture2 textures\water\ripple.dds 4 0.25 + pass + { + scene_blend alpha_blend + depth_write off + cull_hardware none + diffuse vertexcolour + emissive 1 1 1 + ambient 0 0 0 + texture_unit diffuseMap + { + create_in_ffp true + anim_texture2 $anim_texture2 + + // to make sure rotating doesn't cause the texture to repeat + tex_address_mode border + tex_border_colour 0 0 0 0 + } + } +} diff --git a/files/materials/water.shader b/files/materials/water.shader index 4dec57276..373277d0b 100644 --- a/files/materials/water.shader +++ b/files/materials/water.shader @@ -64,7 +64,6 @@ #include "shadows.h" #endif -#define RIPPLES 1 #define REFRACTION @shGlobalSettingBool(refraction) #ifdef SH_VERTEX_SHADER @@ -187,11 +186,6 @@ shInput(float3, screenCoordsPassthrough) shInput(float4, position) shInput(float, depthPassthrough) - - #if RIPPLES - shUniform(float3, rippleCenter) @shSharedParameter(rippleCenter, rippleCenter) - shUniform(float, rippleAreaLength) @shSharedParameter(rippleAreaLength, rippleAreaLength) - #endif shUniform(float, far) @shAutoConstant(far, far_clip_distance) @@ -203,10 +197,6 @@ shSampler2D(normalMap) shUniform(float4x4, wMat) @shAutoConstant(wMat, world_matrix) - - #if RIPPLES - shSampler2D(rippleNormalMap) - #endif shUniform(float3, windDir_windSpeed) @shSharedParameter(windDir_windSpeed) #define WIND_SPEED windDir_windSpeed.z @@ -296,12 +286,7 @@ normal2 * MID_WAVES_X + normal3 * MID_WAVES_Y + normal4 * SMALL_WAVES_X + normal5 * SMALL_WAVES_Y); - float4 worldPosition = shMatrixMult(wMat, float4(position.xyz, 1)); - float2 relPos = (worldPosition.xy - rippleCenter.xy) / rippleAreaLength + 0.5; - float3 normal_ripple = normalize(shSample(rippleNormalMap, relPos.xy).xyz * 2.0 - 1.0); - - //normal = normalize(normal + normal_ripple); - normal = normalize(float3(normal.x * BUMP + normal_ripple.x, normal.y * BUMP + normal_ripple.y, normal.z)); + normal = normalize(float3(normal.x * BUMP, normal.y * BUMP, normal.z)); normal = float3(normal.x, normal.y, -normal.z); // normal for sunlight scattering diff --git a/files/materials/watersim.mat b/files/materials/watersim.mat deleted file mode 100644 index b58b1a851..000000000 --- a/files/materials/watersim.mat +++ /dev/null @@ -1,59 +0,0 @@ -material HeightmapSimulation -{ - allow_fixed_function false - pass - { - depth_check off - depth_write off - vertex_program transform_vertex - fragment_program watersim_fragment - - texture_unit heightPrevSampler - { - tex_address_mode border - tex_border_colour 0 0 0 - texture_alias Heightmap0 - } - texture_unit heightCurrentSampler - { - tex_address_mode border - tex_border_colour 0 0 0 - texture_alias Heightmap1 - } - } -} - -material HeightToNormalMap -{ - allow_fixed_function false - pass - { - depth_check off - depth_write off - vertex_program transform_vertex - fragment_program height_to_normal_fragment - - texture_unit heightCurrentSampler - { - texture_alias Heightmap2 - } - } -} - -material AddImpulse -{ - allow_fixed_function false - pass - { - depth_check off - depth_write off - scene_blend alpha_blend - vertex_program transform_vertex - fragment_program add_impulse_fragment - - texture_unit alphaMap - { - texture circle.png - } - } -} diff --git a/files/materials/watersim.shaderset b/files/materials/watersim.shaderset deleted file mode 100644 index ea512e25f..000000000 --- a/files/materials/watersim.shaderset +++ /dev/null @@ -1,31 +0,0 @@ -shader_set transform_vertex -{ - source quad.shader - type vertex - profiles_cg vs_2_0 vp40 arbvp1 - profiles_hlsl vs_2_0 -} - -shader_set watersim_fragment -{ - source watersim_heightmap.shader - type fragment - profiles_cg ps_3_0 ps_2_x ps_2_0 fp40 arbfp1 - profiles_hlsl ps_3_0 ps_2_0 -} - -shader_set height_to_normal_fragment -{ - source watersim_heighttonormal.shader - type fragment - profiles_cg ps_3_0 ps_2_x ps_2_0 fp40 arbfp1 - profiles_hlsl ps_3_0 ps_2_0 -} - -shader_set add_impulse_fragment -{ - source watersim_addimpulse.shader - type fragment - profiles_cg ps_3_0 ps_2_x ps_2_0 fp40 arbfp1 - profiles_hlsl ps_3_0 ps_2_0 -} diff --git a/files/materials/watersim_addimpulse.shader b/files/materials/watersim_addimpulse.shader deleted file mode 100644 index 3ca4192cd..000000000 --- a/files/materials/watersim_addimpulse.shader +++ /dev/null @@ -1,12 +0,0 @@ -#include "core.h" -#include "watersim_common.h" - - SH_BEGIN_PROGRAM - shInput(float2, UV) - shSampler2D(alphaMap) - - SH_START_PROGRAM - { - shOutputColour(0) = EncodeHeightmap(1.0); - shOutputColour(0).a = shSample (alphaMap, UV.xy).a; - } diff --git a/files/materials/watersim_common.h b/files/materials/watersim_common.h deleted file mode 100644 index aa7a636a0..000000000 --- a/files/materials/watersim_common.h +++ /dev/null @@ -1,25 +0,0 @@ -float DecodeHeightmap(float4 heightmap) -{ - float4 table = float4(1.0, -1.0, 0.0, 0.0); - return dot(heightmap, table); -} - -float DecodeHeightmap(shTexture2D HeightmapSampler, float2 texcoord) -{ - float4 heightmap = shSample(HeightmapSampler, texcoord); - return DecodeHeightmap(heightmap); -} - -float4 EncodeHeightmap(float fHeight) -{ - float h = fHeight; - float positive = fHeight > 0.0 ? fHeight : 0.0; - float negative = fHeight < 0.0 ? -fHeight : 0.0; - - float4 color = float4(0,0,0,0); - - color.r = positive; - color.g = negative; - - return color; -} diff --git a/files/materials/watersim_heightmap.shader b/files/materials/watersim_heightmap.shader deleted file mode 100644 index ec8ae4174..000000000 --- a/files/materials/watersim_heightmap.shader +++ /dev/null @@ -1,51 +0,0 @@ -#include "core.h" - -#define DAMPING 0.95 - -#include "watersim_common.h" - - SH_BEGIN_PROGRAM - shInput(float2, UV) - shSampler2D(heightPrevSampler) - shSampler2D(heightCurrentSampler) - shUniform(float3, previousFrameOffset) @shSharedParameter(previousFrameOffset, previousFrameOffset) - shUniform(float3, currentFrameOffset) @shSharedParameter(currentFrameOffset, currentFrameOffset) - shUniform(float4, rippleTextureSize) @shSharedParameter(rippleTextureSize, rippleTextureSize) - - SH_START_PROGRAM - { -#if !SH_HLSL - const float3 offset[4] = float3[4]( - float3(-1.0, 0.0, 0.25), - float3( 1.0, 0.0, 0.25), - float3( 0.0,-1.0, 0.25), - float3( 0.0, 1.0, 0.25) - ); -#else - const float3 offset[4] = { - float3(-1.0, 0.0, 0.25), - float3( 1.0, 0.0, 0.25), - float3( 0.0,-1.0, 0.25), - float3( 0.0, 1.0, 0.25) - }; -#endif - - float fHeightPrev = DecodeHeightmap(heightPrevSampler, UV.xy + previousFrameOffset.xy + currentFrameOffset.xy); - - float fNeighCurrent = 0; - for ( int i=0; i<4; i++ ) - { - float2 vTexcoord = UV + currentFrameOffset.xy + offset[i].xy * rippleTextureSize.xy; - fNeighCurrent += (DecodeHeightmap(heightCurrentSampler, vTexcoord) * offset[i].z); - } - - float fHeight = fNeighCurrent * 2.0 - fHeightPrev; - - fHeight *= DAMPING; - - shOutputColour(0) = EncodeHeightmap(fHeight); - } - - - - diff --git a/files/materials/watersim_heighttonormal.shader b/files/materials/watersim_heighttonormal.shader deleted file mode 100644 index eaa4af498..000000000 --- a/files/materials/watersim_heighttonormal.shader +++ /dev/null @@ -1,36 +0,0 @@ -#include "core.h" -#include "watersim_common.h" - - SH_BEGIN_PROGRAM - shInput(float2, UV) - shSampler2D(heightCurrentSampler) - shUniform(float4, rippleTextureSize) @shSharedParameter(rippleTextureSize, rippleTextureSize) - - SH_START_PROGRAM - { -#if !SH_HLSL - float2 offset[4] = float2[4] ( - float2(-1.0, 0.0), - float2( 1.0, 0.0), - float2( 0.0,-1.0), - float2( 0.0, 1.0) - ); -#else - float2 offset[4] = { - float2(-1.0, 0.0), - float2( 1.0, 0.0), - float2( 0.0,-1.0), - float2( 0.0, 1.0) - }; -#endif - - float fHeightL = DecodeHeightmap(heightCurrentSampler, UV.xy + offset[0]*rippleTextureSize.xy); - float fHeightR = DecodeHeightmap(heightCurrentSampler, UV.xy + offset[1]*rippleTextureSize.xy); - float fHeightT = DecodeHeightmap(heightCurrentSampler, UV.xy + offset[2]*rippleTextureSize.xy); - float fHeightB = DecodeHeightmap(heightCurrentSampler, UV.xy + offset[3]*rippleTextureSize.xy); - - float3 n = float3(fHeightB - fHeightT, fHeightR - fHeightL, 1.0); - float3 normal = (n + 1.0) * 0.5; - - shOutputColour(0) = float4(normal.rgb, 1.0); - } From 801c0eb57c4300ffb35556711a84411a1b62b28a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Feb 2015 17:34:08 +0100 Subject: [PATCH 435/740] Detect Creature should detect alive creatures only (Fixes #2353) --- apps/openmw/mwworld/worldimp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a60eae48a..0694a3da6 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2886,6 +2886,9 @@ namespace MWWorld } else if (ptr.getClass().getTypeName() != typeid(ESM::Creature).name()) return false; + + if (ptr.getClass().getCreatureStats(ptr).isDead()) + return false; } if (mType == World::Detect_Key && !ptr.getClass().isKey(ptr)) return false; From 03257ecae538feb9fdd1482629a16883c57ca191 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Feb 2015 18:05:02 +0100 Subject: [PATCH 436/740] QString encoding fix --- apps/launcher/graphicspage.cpp | 10 +++++----- apps/launcher/main.cpp | 2 +- components/contentselector/model/contentmodel.cpp | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index dccf8bb8c..cdb51348c 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -67,7 +67,7 @@ bool Launcher::GraphicsPage::setupOgre() } catch(Ogre::Exception &ex) { - QString ogreError = QString::fromStdString(ex.getFullDescription().c_str()); + QString ogreError = QString::fromUtf8(ex.getFullDescription().c_str()); QMessageBox msgBox; msgBox.setWindowTitle("Error creating Ogre::Root"); msgBox.setIcon(QMessageBox::Critical); @@ -135,7 +135,7 @@ bool Launcher::GraphicsPage::setupSDL() msgBox.setWindowTitle(tr("Error receiving number of screens")); msgBox.setIcon(QMessageBox::Critical); msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
SDL_GetNumDisplayModes failed:

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

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

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

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

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

") + QString::fromUtf8(SDL_GetError()) + "
"); msgBox.exec(); return result; } diff --git a/apps/launcher/main.cpp b/apps/launcher/main.cpp index 5c3f38458..11ea56869 100644 --- a/apps/launcher/main.cpp +++ b/apps/launcher/main.cpp @@ -24,7 +24,7 @@ int main(int argc, char *argv[]) SDL_SetMainReady(); if (SDL_Init(SDL_INIT_VIDEO) != 0) { - qDebug() << "SDL_Init failed: " << QString::fromStdString(SDL_GetError()); + qDebug() << "SDL_Init failed: " << QString::fromUtf8(SDL_GetError()); return 0; } signal(SIGINT, SIG_DFL); // We don't want to use the SDL event loop in the launcher, diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 56a86f87f..ec1fcc21e 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -459,7 +459,7 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path) EsmFile *file = new EsmFile(path); foreach (const ESM::Header::MasterData &item, fileReader.getGameFiles()) - file->addGameFile(QString::fromStdString(item.name)); + file->addGameFile(QString::fromUtf8(item.name.c_str())); file->setAuthor (QString::fromUtf8(fileReader.getAuthor().c_str())); file->setDate (info.lastModified()); From 399c24c64668046f879e788418def56285dd5d8f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Feb 2015 23:27:32 +0100 Subject: [PATCH 437/740] CMake cleanup: remove redundant setting of Permissions to default values --- CMakeLists.txt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b80d4c95..ed4136813 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -438,23 +438,23 @@ IF(NOT WIN32 AND NOT APPLE) INSTALL(FILES "extern/shiny/License.txt" DESTINATION "${LICDIR}" RENAME "Shiny License.txt" ) # Install icon and desktop file - INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") - INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.png" DESTINATION "${ICONDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications" COMPONENT "openmw") + INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.png" DESTINATION "${ICONDIR}" COMPONENT "openmw") IF(BUILD_OPENCS) - INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.desktop" DESTINATION "${DATAROOTDIR}/applications" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs") - INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/opencs/openmw-cs.png" DESTINATION "${ICONDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs") + INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.desktop" DESTINATION "${DATAROOTDIR}/applications" COMPONENT "opencs") + INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/opencs/openmw-cs.png" DESTINATION "${ICONDIR}" COMPONENT "opencs") ENDIF(BUILD_OPENCS) # Install global configuration files - INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${SYSCONFDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") - INSTALL(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${SYSCONFDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") - INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "${SYSCONFDIR}" RENAME "openmw.cfg" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "${SYSCONFDIR}" RENAME "openmw.cfg" COMPONENT "openmw") IF(BUILD_OPENCS) - INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${SYSCONFDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs") + INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${SYSCONFDIR}" COMPONENT "opencs") ENDIF(BUILD_OPENCS) # Install resources - INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${DATADIR}" FILE_PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT "Resources") + INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${DATADIR}" COMPONENT "Resources") INSTALL(DIRECTORY DESTINATION "${DATADIR}/data" COMPONENT "Resources") ENDIF(NOT WIN32 AND NOT APPLE) From 218f789d88ac1ea46ba9675dc9dcd67009602184 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Feb 2015 01:08:07 +0100 Subject: [PATCH 438/740] Fix player DrawState reset when selecting enchanted item (Fixes #2356) --- apps/openmw/mwgui/spellwindow.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 6d3c79b34..69365c108 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -95,8 +95,9 @@ namespace MWGui return; } - MWBase::Environment::get().getWindowManager()->unsetSelectedSpell(); store.setSelectedEnchantItem(it); + // to reset WindowManager::mSelectedSpell immediately + MWBase::Environment::get().getWindowManager()->setSelectedEnchantItem(*it); updateSpells(); } From ee574e08ef48c2496ad522c9fa8aecd5b218dccc Mon Sep 17 00:00:00 2001 From: jacmoe Date: Tue, 3 Feb 2015 23:12:33 +0100 Subject: [PATCH 439/740] MIT License header added to all terrain component files. --- components/terrain/buffercache.cpp | 21 +++++++++++++++++++++ components/terrain/buffercache.hpp | 21 +++++++++++++++++++++ components/terrain/chunk.cpp | 21 +++++++++++++++++++++ components/terrain/chunk.hpp | 21 +++++++++++++++++++++ components/terrain/defaultworld.cpp | 21 +++++++++++++++++++++ components/terrain/defaultworld.hpp | 21 +++++++++++++++++++++ components/terrain/defs.hpp | 21 +++++++++++++++++++++ components/terrain/material.cpp | 21 +++++++++++++++++++++ components/terrain/material.hpp | 21 +++++++++++++++++++++ components/terrain/quadtreenode.cpp | 21 +++++++++++++++++++++ components/terrain/quadtreenode.hpp | 21 +++++++++++++++++++++ components/terrain/storage.cpp | 21 +++++++++++++++++++++ components/terrain/storage.hpp | 21 +++++++++++++++++++++ components/terrain/terraingrid.cpp | 21 +++++++++++++++++++++ components/terrain/terraingrid.hpp | 21 +++++++++++++++++++++ components/terrain/world.cpp | 21 +++++++++++++++++++++ components/terrain/world.hpp | 21 +++++++++++++++++++++ files/materials/terrain.shader | 22 ++++++++++++++++++++++ 18 files changed, 379 insertions(+) diff --git a/components/terrain/buffercache.cpp b/components/terrain/buffercache.cpp index 3d0b35910..01032bcda 100644 --- a/components/terrain/buffercache.cpp +++ b/components/terrain/buffercache.cpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #include "buffercache.hpp" #include diff --git a/components/terrain/buffercache.hpp b/components/terrain/buffercache.hpp index 51c0a61af..887f0822e 100644 --- a/components/terrain/buffercache.hpp +++ b/components/terrain/buffercache.hpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_BUFFERCACHE_H #define COMPONENTS_TERRAIN_BUFFERCACHE_H diff --git a/components/terrain/chunk.cpp b/components/terrain/chunk.cpp index 9c60ee017..cce5abd36 100644 --- a/components/terrain/chunk.cpp +++ b/components/terrain/chunk.cpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #include "chunk.hpp" #include diff --git a/components/terrain/chunk.hpp b/components/terrain/chunk.hpp index 9b2ed76ac..22b4f26ef 100644 --- a/components/terrain/chunk.hpp +++ b/components/terrain/chunk.hpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_TERRAINBATCH_H #define COMPONENTS_TERRAIN_TERRAINBATCH_H diff --git a/components/terrain/defaultworld.cpp b/components/terrain/defaultworld.cpp index 943658235..e14c64f3a 100644 --- a/components/terrain/defaultworld.cpp +++ b/components/terrain/defaultworld.cpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #include "defaultworld.hpp" #include diff --git a/components/terrain/defaultworld.hpp b/components/terrain/defaultworld.hpp index 62441c420..90e8cc2b6 100644 --- a/components/terrain/defaultworld.hpp +++ b/components/terrain/defaultworld.hpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_H #define COMPONENTS_TERRAIN_H diff --git a/components/terrain/defs.hpp b/components/terrain/defs.hpp index 685937653..6d173d136 100644 --- a/components/terrain/defs.hpp +++ b/components/terrain/defs.hpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_DEFS_HPP #define COMPONENTS_TERRAIN_DEFS_HPP diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index a40e576ed..4ff04ab93 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #include "material.hpp" #include diff --git a/components/terrain/material.hpp b/components/terrain/material.hpp index b9000cb1b..f35080e7c 100644 --- a/components/terrain/material.hpp +++ b/components/terrain/material.hpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_MATERIAL_H #define COMPONENTS_TERRAIN_MATERIAL_H diff --git a/components/terrain/quadtreenode.cpp b/components/terrain/quadtreenode.cpp index 755c45c21..5fce5eae9 100644 --- a/components/terrain/quadtreenode.cpp +++ b/components/terrain/quadtreenode.cpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #include "quadtreenode.hpp" #include diff --git a/components/terrain/quadtreenode.hpp b/components/terrain/quadtreenode.hpp index e8392b8e4..1ecd6fcd5 100644 --- a/components/terrain/quadtreenode.hpp +++ b/components/terrain/quadtreenode.hpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_QUADTREENODE_H #define COMPONENTS_TERRAIN_QUADTREENODE_H diff --git a/components/terrain/storage.cpp b/components/terrain/storage.cpp index e69de29bb..14009127d 100644 --- a/components/terrain/storage.cpp +++ b/components/terrain/storage.cpp @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ diff --git a/components/terrain/storage.hpp b/components/terrain/storage.hpp index aa52ffc4b..7846e91c6 100644 --- a/components/terrain/storage.hpp +++ b/components/terrain/storage.hpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_STORAGE_H #define COMPONENTS_TERRAIN_STORAGE_H diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 6a66ac3d7..269152e61 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #include "terraingrid.hpp" #include diff --git a/components/terrain/terraingrid.hpp b/components/terrain/terraingrid.hpp index 7cbf45576..97ef6d14d 100644 --- a/components/terrain/terraingrid.hpp +++ b/components/terrain/terraingrid.hpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_TERRAINGRID_H #define COMPONENTS_TERRAIN_TERRAINGRID_H diff --git a/components/terrain/world.cpp b/components/terrain/world.cpp index 93caeb8df..5cc2647c6 100644 --- a/components/terrain/world.cpp +++ b/components/terrain/world.cpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #include "world.hpp" #include diff --git a/components/terrain/world.hpp b/components/terrain/world.hpp index beca7903a..3e63b4c93 100644 --- a/components/terrain/world.hpp +++ b/components/terrain/world.hpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_WORLD_H #define COMPONENTS_TERRAIN_WORLD_H diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index 8384588e4..a4ca10fcc 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + #include "core.h" #define IS_FIRST_PASS (@shPropertyString(pass_index) == 0) From 9da0a9f8c4dab03e1917d54ba8d8a4f23f02693f Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 10 Feb 2015 00:55:31 +0100 Subject: [PATCH 440/740] Enable link-time optimization on MSVC --- CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index d22e0b129..382a8e8e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -384,6 +384,12 @@ if (CMAKE_COMPILER_IS_GNUCC) if ("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6) SET(CMAKE_CXX_FLAGS "-Wno-unused-but-set-parameter ${CMAKE_CXX_FLAGS}") endif("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6) +elseif (MSVC) + # Enable link-time code generation globally for all linking + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL") + set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG") + set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG") + set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "${CMAKE_STATIC_LINKER_FLAGS_RELEASE} /LTCG") endif (CMAKE_COMPILER_IS_GNUCC) IF(NOT WIN32 AND NOT APPLE) From 1a19253158bb3eba7fb671fb90886a286d247c81 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 10 Feb 2015 15:32:54 +0100 Subject: [PATCH 441/740] Fix MSVC build due to missing M_PI define Apparently the header guard on cmath only adds the defines if _USE_MATH_DEFINES is defined when cmath is included for the first time. So enabling that define and moving cmath up to be the first include, so that nothing else includes it without the define set. --- apps/openmw/mwworld/weather.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 7a36d6ac7..4440ed030 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -1,7 +1,8 @@ -#include "weather.hpp" - +#define _USE_MATH_DEFINES #include +#include "weather.hpp" + #include #include "../mwbase/environment.hpp" From 3ccf4642b4e7f68c73c43ed451732789cf559683 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Feb 2015 20:25:57 +0100 Subject: [PATCH 442/740] Implement ToggleScripts --- apps/openmw/engine.cpp | 13 +++++++----- apps/openmw/mwbase/world.hpp | 3 +++ apps/openmw/mwgui/inventorywindow.cpp | 2 +- apps/openmw/mwscript/docs/vmformat.txt | 3 ++- apps/openmw/mwscript/miscextensions.cpp | 14 +++++++++++++ apps/openmw/mwworld/worldimp.cpp | 28 ++++++++++++++++++++----- apps/openmw/mwworld/worldimp.hpp | 4 ++++ components/compiler/extensions0.cpp | 1 + components/compiler/opcodes.hpp | 1 + 9 files changed, 57 insertions(+), 12 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 611f0a304..669bae60a 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -109,11 +109,14 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) { if (!paused) { - // local scripts - executeLocalScripts(); - - // global scripts - MWBase::Environment::get().getScriptManager()->getGlobalScripts().run(); + if (MWBase::Environment::get().getWorld()->getScriptsEnabled()) + { + // local scripts + executeLocalScripts(); + + // global scripts + MWBase::Environment::get().getScriptManager()->getGlobalScripts().run(); + } MWBase::Environment::get().getWorld()->markCellAsUnchanged(); } diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 154d96f7d..8180d0b1a 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -489,6 +489,9 @@ namespace MWBase virtual bool toggleGodMode() = 0; + virtual bool toggleScripts() = 0; + virtual bool getScriptsEnabled() const = 0; + /** * @brief startSpellCast attempt to start casting a spell. Might fail immediately if conditions are not met. * @param actor diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 5cb67c048..4270c4be1 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -420,7 +420,7 @@ namespace MWGui // Give the script a chance to run once before we do anything else // this is important when setting pcskipequip as a reaction to onpcequip being set (bk_treasuryreport does this) - if (!script.empty()) + if (!script.empty() && MWBase::Environment::get().getWorld()->getScriptsEnabled()) { MWScript::InterpreterContext interpreterContext (&ptr.getRefData().getLocals(), ptr); MWBase::Environment::get().getScriptManager()->run (script, interpreterContext); diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 41cc6b88a..93720aef6 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -444,5 +444,6 @@ op 0x20002fd: AddToLevItem op 0x20002fe: RemoveFromLevItem op 0x20002ff: SetFactionReaction op 0x2000300: EnableLevelupMenu +op 0x2000301: ToggleScripts -opcodes 0x2000301-0x3ffffff unused +opcodes 0x2000302-0x3ffffff unused diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index cdc9f58cf..52094947c 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -915,6 +915,19 @@ namespace MWScript } }; + class OpToggleScripts : public Interpreter::Opcode0 + { + public: + virtual void execute (Interpreter::Runtime& runtime) + { + InterpreterContext& context = static_cast (runtime.getContext()); + + bool enabled = MWBase::Environment::get().getWorld()->toggleScripts(); + + context.report(enabled ? "Scripts -> On" : "Scripts -> Off"); + } + }; + class OpToggleGodMode : public Interpreter::Opcode0 { public: @@ -1220,6 +1233,7 @@ namespace MWScript interpreter.installSegment5 (Compiler::Misc::opcodeShowVars, new OpShowVars); interpreter.installSegment5 (Compiler::Misc::opcodeShowVarsExplicit, new OpShowVars); interpreter.installSegment5 (Compiler::Misc::opcodeToggleGodMode, new OpToggleGodMode); + interpreter.installSegment5 (Compiler::Misc::opcodeToggleScripts, new OpToggleScripts); interpreter.installSegment5 (Compiler::Misc::opcodeDisableLevitation, new OpEnableLevitation); interpreter.installSegment5 (Compiler::Misc::opcodeEnableLevitation, new OpEnableLevitation); interpreter.installSegment5 (Compiler::Misc::opcodeCast, new OpCast); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0694a3da6..188f3cdad 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -151,7 +151,8 @@ namespace MWWorld mFallback(fallbackMap), mTeleportEnabled(true), mLevitationEnabled(true), mGodMode(false), mContentFiles (contentFiles), mGoToJail(false), mDaysInPrison(0), - mStartCell (startCell), mStartupScript(startupScript) + mStartCell (startCell), mStartupScript(startupScript), + mScriptsEnabled(true) { mPhysics = new PhysicsSystem(renderer); mPhysEngine = mPhysics->getEngine(); @@ -293,6 +294,7 @@ namespace MWWorld mDoorStates.clear(); mGodMode = false; + mScriptsEnabled = true; mSky = true; mTeleportEnabled = true; mLevitationEnabled = true; @@ -2587,6 +2589,17 @@ namespace MWWorld return mGodMode; } + bool World::toggleScripts() + { + mScriptsEnabled = !mScriptsEnabled; + return mScriptsEnabled; + } + + bool World::getScriptsEnabled() const + { + return mScriptsEnabled; + } + void World::loadContentFiles(const Files::Collections& fileCollections, const std::vector& content, ContentLoader& contentLoader) { @@ -3167,12 +3180,17 @@ namespace MWWorld breakInvisibility(actor); - if (!script.empty()) + if (mScriptsEnabled) { - getLocalScripts().setIgnore (object); - MWBase::Environment::get().getScriptManager()->run (script, interpreterContext); + if (!script.empty()) + { + getLocalScripts().setIgnore (object); + MWBase::Environment::get().getScriptManager()->run (script, interpreterContext); + } + if (!interpreterContext.hasActivationBeenHandled()) + interpreterContext.executeActivation(object, actor); } - if (!interpreterContext.hasActivationBeenHandled()) + else interpreterContext.executeActivation(object, actor); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 1d103c6a9..9980f6f90 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -82,6 +82,7 @@ namespace MWWorld boost::shared_ptr mProjectileManager; bool mGodMode; + bool mScriptsEnabled; std::vector mContentFiles; // not implemented @@ -572,6 +573,9 @@ namespace MWWorld virtual bool toggleGodMode(); + virtual bool toggleScripts(); + virtual bool getScriptsEnabled() const; + /** * @brief startSpellCast attempt to start casting a spell. Might fail immediately if conditions are not met. * @param actor diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index 70338669e..c56ee2ffb 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -303,6 +303,7 @@ namespace Compiler extensions.registerInstruction ("sv", "", opcodeShowVars, opcodeShowVarsExplicit); extensions.registerInstruction("tgm", "", opcodeToggleGodMode); extensions.registerInstruction("togglegodmode", "", opcodeToggleGodMode); + extensions.registerInstruction("togglescripts", "", opcodeToggleScripts); extensions.registerInstruction ("disablelevitation", "", opcodeDisableLevitation); extensions.registerInstruction ("enablelevitation", "", opcodeEnableLevitation); extensions.registerFunction ("getpcinjail", 'l', "", opcodeGetPcInJail); diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index e5cf2e965..a4aab8aa1 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -278,6 +278,7 @@ namespace Compiler const int opcodeShowVars = 0x200021d; const int opcodeShowVarsExplicit = 0x200021e; const int opcodeToggleGodMode = 0x200021f; + const int opcodeToggleScripts = 0x2000301; const int opcodeDisableLevitation = 0x2000220; const int opcodeEnableLevitation = 0x2000221; const int opcodeCast = 0x2000227; From bf1839b3701df0937e096f8aed2f2b1c9c1b8c32 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Feb 2015 22:01:57 +0100 Subject: [PATCH 443/740] Always print the exception to stderr --- apps/openmw/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 475fe63a2..82fda060e 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -390,12 +390,12 @@ int main(int argc, char**argv) catch (std::exception &e) { #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX || OGRE_PLATFORM == OGRE_PLATFORM_APPLE - if (isatty(fileno(stdin))) - std::cerr << "\nERROR: " << e.what() << std::endl; - else + if (!isatty(fileno(stdin))) #endif SDL_ShowSimpleMessageBox(0, "OpenMW: Fatal error", e.what(), NULL); + std::cerr << "\nERROR: " << e.what() << std::endl; + ret = 1; } From 9009889d240185fb50e251d175341288957852a8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Feb 2015 23:16:25 +0100 Subject: [PATCH 444/740] Don't rely on subrecord order when reading (Fixes #2361) --- components/esm/aipackage.cpp | 67 +++++++----- components/esm/aipackage.hpp | 12 ++- components/esm/loadarmo.cpp | 101 ++++++++++++------ components/esm/loadarmo.hpp | 4 + components/esm/loadbook.cpp | 68 ++++++++---- components/esm/loadclot.cpp | 47 ++++++-- components/esm/loadcont.cpp | 11 +- components/esm/loadcont.hpp | 4 + components/esm/loaddoor.cpp | 52 ++++++--- components/esm/loadmgef.cpp | 75 +++++++++---- components/esm/loadmisc.cpp | 55 +++++++--- components/esm/loadnpc.cpp | 200 +++++++++++++++++++++-------------- components/esm/loadrace.cpp | 32 +++++- components/esm/loadspel.cpp | 27 ++++- components/esm/loadweap.cpp | 62 +++++++---- components/esm/spelllist.cpp | 7 +- components/esm/spelllist.hpp | 5 + 17 files changed, 575 insertions(+), 254 deletions(-) diff --git a/components/esm/aipackage.cpp b/components/esm/aipackage.cpp index 209a1fe26..8ad64b797 100644 --- a/components/esm/aipackage.cpp +++ b/components/esm/aipackage.cpp @@ -11,36 +11,55 @@ namespace ESM mServices = 0; } + void AIPackageList::add(ESMReader &esm) + { + AIPackage pack; + if (esm.retSubName() == AI_CNDT) { + mList.back().mCellName = esm.getHString(); + } else if (esm.retSubName() == AI_Wander) { + pack.mType = AI_Wander; + esm.getHExact(&pack.mWander, 14); + mList.push_back(pack); + } else if (esm.retSubName() == AI_Travel) { + pack.mType = AI_Travel; + esm.getHExact(&pack.mTravel, 16); + mList.push_back(pack); + } else if (esm.retSubName() == AI_Escort || + esm.retSubName() == AI_Follow) + { + pack.mType = + (esm.retSubName() == AI_Escort) ? AI_Escort : AI_Follow; + esm.getHExact(&pack.mTarget, 48); + mList.push_back(pack); + } else if (esm.retSubName() == AI_Activate) { + pack.mType = AI_Activate; + esm.getHExact(&pack.mActivate, 33); + mList.push_back(pack); + } else { // not AI package related data, so leave + return; + } + + } + void AIPackageList::load(ESMReader &esm) { mList.clear(); while (esm.hasMoreSubs()) { // initialize every iteration - AIPackage pack; - esm.getSubName(); - if (esm.retSubName() == 0x54444e43) { // CNDT - mList.back().mCellName = esm.getHString(); - } else if (esm.retSubName() == AI_Wander) { - pack.mType = AI_Wander; - esm.getHExact(&pack.mWander, 14); - mList.push_back(pack); - } else if (esm.retSubName() == AI_Travel) { - pack.mType = AI_Travel; - esm.getHExact(&pack.mTravel, 16); - mList.push_back(pack); - } else if (esm.retSubName() == AI_Escort || - esm.retSubName() == AI_Follow) + esm.getSubName(); + switch (esm.retSubName().val) { - pack.mType = - (esm.retSubName() == AI_Escort) ? AI_Escort : AI_Follow; - esm.getHExact(&pack.mTarget, 48); - mList.push_back(pack); - } else if (esm.retSubName() == AI_Activate) { - pack.mType = AI_Activate; - esm.getHExact(&pack.mActivate, 33); - mList.push_back(pack); - } else { // not AI package related data, so leave - return; + case AI_Wander: + case AI_Activate: + case AI_Escort: + case AI_Follow: + case AI_Travel: + case AI_CNDT: + + add(esm); + break; + default: + return; } } } diff --git a/components/esm/aipackage.hpp b/components/esm/aipackage.hpp index cbe82f16e..30bd2ce04 100644 --- a/components/esm/aipackage.hpp +++ b/components/esm/aipackage.hpp @@ -63,7 +63,8 @@ namespace ESM AI_Travel = 0x545f4941, AI_Follow = 0x465f4941, AI_Escort = 0x455f4941, - AI_Activate = 0x415f4941 + AI_Activate = 0x415f4941, + AI_CNDT = 0x54444e43 }; /// \note Used for storaging packages in a single container @@ -90,11 +91,12 @@ namespace ESM { std::vector mList; - /// \note This breaks consistency of subrecords reading: - /// after calling it subrecord name is already read, so - /// it needs to use retSubName() if needed. But, hey, there - /// is only one field left (XSCL) and only two records uses AI + /// Add a single AIPackage, assumes subrecord name was already read + void add(ESMReader &esm); + + /// TODO: remove this method. The ESM format does not guarantee that all AI packages follow one another void load(ESMReader &esm); + void save(ESMWriter &esm) const; }; } diff --git a/components/esm/loadarmo.cpp b/components/esm/loadarmo.cpp index f8c3a4718..066551d6f 100644 --- a/components/esm/loadarmo.cpp +++ b/components/esm/loadarmo.cpp @@ -7,52 +7,87 @@ namespace ESM { -void PartReferenceList::load(ESMReader &esm) -{ - mParts.clear(); - while (esm.isNextSub("INDX")) + void PartReferenceList::add(ESMReader &esm) { PartReference pr; esm.getHT(pr.mPart); // The INDX byte pr.mMale = esm.getHNOString("BNAM"); pr.mFemale = esm.getHNOString("CNAM"); mParts.push_back(pr); + } -} -void PartReferenceList::save(ESMWriter &esm) const -{ - for (std::vector::const_iterator it = mParts.begin(); it != mParts.end(); ++it) + void PartReferenceList::load(ESMReader &esm) { - esm.writeHNT("INDX", it->mPart); - esm.writeHNOString("BNAM", it->mMale); - esm.writeHNOString("CNAM", it->mFemale); + mParts.clear(); + while (esm.isNextSub("INDX")) + { + add(esm); + } } -} -unsigned int Armor::sRecordId = REC_ARMO; + void PartReferenceList::save(ESMWriter &esm) const + { + for (std::vector::const_iterator it = mParts.begin(); it != mParts.end(); ++it) + { + esm.writeHNT("INDX", it->mPart); + esm.writeHNOString("BNAM", it->mMale); + esm.writeHNOString("CNAM", it->mFemale); + } + } -void Armor::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - mScript = esm.getHNOString("SCRI"); - esm.getHNT(mData, "AODT", 24); - mIcon = esm.getHNOString("ITEX"); - mParts.load(esm); - mEnchant = esm.getHNOString("ENAM"); -} + unsigned int Armor::sRecordId = REC_ARMO; -void Armor::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNT("AODT", mData, 24); - esm.writeHNOCString("ITEX", mIcon); - mParts.save(esm); - esm.writeHNOCString("ENAM", mEnchant); -} + void Armor::load(ESMReader &esm) + { + mParts.mParts.clear(); + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'A','O','D','T'>::value: + esm.getHT(mData, 24); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + case ESM::FourCC<'E','N','A','M'>::value: + mEnchant = esm.getHString(); + break; + case ESM::FourCC<'I','N','D','X'>::value: + mParts.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing CTDT subrecord"); + } + + void Armor::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNT("AODT", mData, 24); + esm.writeHNOCString("ITEX", mIcon); + mParts.save(esm); + esm.writeHNOCString("ENAM", mEnchant); + } void Armor::blank() { diff --git a/components/esm/loadarmo.hpp b/components/esm/loadarmo.hpp index 6be9dd971..356dfc1c5 100644 --- a/components/esm/loadarmo.hpp +++ b/components/esm/loadarmo.hpp @@ -55,6 +55,10 @@ struct PartReferenceList { std::vector mParts; + /// Load one part, assumes the subrecord name was already read + void add(ESMReader &esm); + + /// TODO: remove this method. The ESM format does not guarantee that all Part subrecords follow one another. void load(ESMReader &esm); void save(ESMWriter &esm) const; }; diff --git a/components/esm/loadbook.cpp b/components/esm/loadbook.cpp index c8b7e9478..47f52fc31 100644 --- a/components/esm/loadbook.cpp +++ b/components/esm/loadbook.cpp @@ -8,26 +8,54 @@ namespace ESM { unsigned int Book::sRecordId = REC_BOOK; -void Book::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "BKDT", 20); - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); - mText = esm.getHNOString("TEXT"); - mEnchant = esm.getHNOString("ENAM"); -} -void Book::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("BKDT", mData, 20); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNOCString("ITEX", mIcon); - esm.writeHNOString("TEXT", mText); - esm.writeHNOCString("ENAM", mEnchant); -} + void Book::load(ESMReader &esm) + { + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'B','K','D','T'>::value: + esm.getHT(mData, 20); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + case ESM::FourCC<'E','N','A','M'>::value: + mEnchant = esm.getHString(); + break; + case ESM::FourCC<'T','E','X','T'>::value: + mText = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing BKDT subrecord"); + } + void Book::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("BKDT", mData, 20); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); + esm.writeHNOString("TEXT", mText); + esm.writeHNOCString("ENAM", mEnchant); + } void Book::blank() { diff --git a/components/esm/loadclot.cpp b/components/esm/loadclot.cpp index 17ecdf3ae..5f49b5e70 100644 --- a/components/esm/loadclot.cpp +++ b/components/esm/loadclot.cpp @@ -10,17 +10,42 @@ namespace ESM void Clothing::load(ESMReader &esm) { - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "CTDT", 12); - - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); - - mParts.load(esm); - - - mEnchant = esm.getHNOString("ENAM"); + mParts.mParts.clear(); + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'C','T','D','T'>::value: + esm.getHT(mData, 12); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + case ESM::FourCC<'E','N','A','M'>::value: + mEnchant = esm.getHString(); + break; + case ESM::FourCC<'I','N','D','X'>::value: + mParts.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing CTDT subrecord"); } void Clothing::save(ESMWriter &esm) const diff --git a/components/esm/loadcont.cpp b/components/esm/loadcont.cpp index 51a385f06..f48f06930 100644 --- a/components/esm/loadcont.cpp +++ b/components/esm/loadcont.cpp @@ -7,14 +7,19 @@ namespace ESM { +void InventoryList::add(ESMReader &esm) +{ + ContItem ci; + esm.getHT(ci, 36); + mList.push_back(ci); +} + void InventoryList::load(ESMReader &esm) { mList.clear(); - ContItem ci; while (esm.isNextSub("NPCO")) { - esm.getHT(ci, 36); - mList.push_back(ci); + add(esm); } } diff --git a/components/esm/loadcont.hpp b/components/esm/loadcont.hpp index 2808b67b5..93db94759 100644 --- a/components/esm/loadcont.hpp +++ b/components/esm/loadcont.hpp @@ -26,6 +26,10 @@ struct InventoryList { std::vector mList; + /// Load one item, assumes subrecord name is already read + void add(ESMReader &esm); + + /// TODO: remove this method, the ESM format doesn't guarantee that all ContItems follow one another void load(ESMReader &esm); void save(ESMWriter &esm) const; }; diff --git a/components/esm/loaddoor.cpp b/components/esm/loaddoor.cpp index c56b06337..f446eed61 100644 --- a/components/esm/loaddoor.cpp +++ b/components/esm/loaddoor.cpp @@ -8,23 +8,43 @@ namespace ESM { unsigned int Door::sRecordId = REC_DOOR; -void Door::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - mScript = esm.getHNOString("SCRI"); - mOpenSound = esm.getHNOString("SNAM"); - mCloseSound = esm.getHNOString("ANAM"); -} + void Door::load(ESMReader &esm) + { + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'S','N','A','M'>::value: + mOpenSound = esm.getHString(); + break; + case ESM::FourCC<'A','N','A','M'>::value: + mCloseSound = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + } -void Door::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNOCString("SNAM", mOpenSound); - esm.writeHNOCString("ANAM", mCloseSound); -} + void Door::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("SNAM", mOpenSound); + esm.writeHNOCString("ANAM", mCloseSound); + } void Door::blank() { diff --git a/components/esm/loadmgef.cpp b/components/esm/loadmgef.cpp index cbdca3e31..3ec07a2a9 100644 --- a/components/esm/loadmgef.cpp +++ b/components/esm/loadmgef.cpp @@ -191,33 +191,64 @@ namespace ESM void MagicEffect::load(ESMReader &esm) { - esm.getHNT(mIndex, "INDX"); + esm.getHNT(mIndex, "INDX"); mId = indexToId (mIndex); - esm.getHNT(mData, "MEDT", 36); - if (esm.getFormat() == 0) - { - // don't allow mods to change fixed flags in the legacy format - mData.mFlags &= (AllowSpellmaking | AllowEnchanting | NegativeLight); - if (mIndex>=0 && mIndex=0 && mIndex::value: + mIcon = esm.getHString(); + break; + case ESM::FourCC<'P','T','E','X'>::value: + mParticle = esm.getHString(); + break; + case ESM::FourCC<'B','S','N','D'>::value: + mBoltSound = esm.getHString(); + break; + case ESM::FourCC<'C','S','N','D'>::value: + mCastSound = esm.getHString(); + break; + case ESM::FourCC<'H','S','N','D'>::value: + mHitSound = esm.getHString(); + break; + case ESM::FourCC<'A','S','N','D'>::value: + mAreaSound = esm.getHString(); + break; + case ESM::FourCC<'C','V','F','X'>::value: + mCasting = esm.getHString(); + break; + case ESM::FourCC<'B','V','F','X'>::value: + mBolt = esm.getHString(); + break; + case ESM::FourCC<'H','V','F','X'>::value: + mHit = esm.getHString(); + break; + case ESM::FourCC<'A','V','F','X'>::value: + mArea = esm.getHString(); + break; + case ESM::FourCC<'D','E','S','C'>::value: + mDescription = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord " + esm.retSubName().toString()); + } + } } void MagicEffect::save(ESMWriter &esm) const { diff --git a/components/esm/loadmisc.cpp b/components/esm/loadmisc.cpp index 2ca09e8ae..81c094f2b 100644 --- a/components/esm/loadmisc.cpp +++ b/components/esm/loadmisc.cpp @@ -8,22 +8,45 @@ namespace ESM { unsigned int Miscellaneous::sRecordId = REC_MISC; -void Miscellaneous::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "MCDT", 12); - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); -} -void Miscellaneous::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("MCDT", mData, 12); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNOCString("ITEX", mIcon); -} + void Miscellaneous::load(ESMReader &esm) + { + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'M','C','D','T'>::value: + esm.getHT(mData, 12); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + } + } + if (!hasData) + esm.fail("Missing MCDT subrecord"); + } + + void Miscellaneous::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("MCDT", mData, 12); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); + } void Miscellaneous::blank() { diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index 6ca070cf3..3d617241b 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -8,92 +8,136 @@ namespace ESM { unsigned int NPC::sRecordId = REC_NPC_; -void NPC::load(ESMReader &esm) -{ - mPersistent = esm.getRecordFlags() & 0x0400; - - mModel = esm.getHNOString("MODL"); - mName = esm.getHNOString("FNAM"); - - mRace = esm.getHNString("RNAM"); - mClass = esm.getHNString("CNAM"); - mFaction = esm.getHNString("ANAM"); - mHead = esm.getHNString("BNAM"); - mHair = esm.getHNString("KNAM"); - - mScript = esm.getHNOString("SCRI"); - - esm.getSubNameIs("NPDT"); - esm.getSubHeader(); - if (esm.getSubSize() == 52) - { - mNpdtType = NPC_DEFAULT; - esm.getExact(&mNpdt52, 52); - } - else if (esm.getSubSize() == 12) + void NPC::load(ESMReader &esm) { - mNpdtType = NPC_WITH_AUTOCALCULATED_STATS; - esm.getExact(&mNpdt12, 12); - } - else - esm.fail("NPC_NPDT must be 12 or 52 bytes long"); - - esm.getHNT(mFlags, "FLAG"); + mPersistent = esm.getRecordFlags() & 0x0400; - mInventory.load(esm); - mSpells.load(esm); + mSpells.mList.clear(); + mInventory.mList.clear(); + mTransport.clear(); + mAiPackage.mList.clear(); - if (esm.isNextSub("AIDT")) - { - esm.getHExact(&mAiData, sizeof(mAiData)); - mHasAI= true; - } - else + bool hasNpdt = false; + bool hasFlags = false; mHasAI = false; - - mTransport.clear(); - while (esm.isNextSub("DODT") || esm.isNextSub("DNAM")) { - if (esm.retSubName() == 0x54444f44) { // DODT struct - Dest dodt; - esm.getHExact(&dodt.mPos, 24); - mTransport.push_back(dodt); - } else if (esm.retSubName() == 0x4d414e44) { // DNAM struct - mTransport.back().mCellName = esm.getHString(); + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'R','N','A','M'>::value: + mRace = esm.getHString(); + break; + case ESM::FourCC<'C','N','A','M'>::value: + mClass = esm.getHString(); + break; + case ESM::FourCC<'A','N','A','M'>::value: + mFaction = esm.getHString(); + break; + case ESM::FourCC<'B','N','A','M'>::value: + mHead = esm.getHString(); + break; + case ESM::FourCC<'K','N','A','M'>::value: + mHair = esm.getHString(); + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'N','P','D','T'>::value: + hasNpdt = true; + esm.getSubHeader(); + if (esm.getSubSize() == 52) + { + mNpdtType = NPC_DEFAULT; + esm.getExact(&mNpdt52, 52); + } + else if (esm.getSubSize() == 12) + { + mNpdtType = NPC_WITH_AUTOCALCULATED_STATS; + esm.getExact(&mNpdt12, 12); + } + else + esm.fail("NPC_NPDT must be 12 or 52 bytes long"); + break; + case ESM::FourCC<'F','L','A','G'>::value: + hasFlags = true; + esm.getHT(mFlags); + break; + case ESM::FourCC<'N','P','C','S'>::value: + mSpells.add(esm); + break; + case ESM::FourCC<'N','P','C','O'>::value: + mInventory.add(esm); + break; + case ESM::FourCC<'A','I','D','T'>::value: + esm.getHExact(&mAiData, sizeof(mAiData)); + mHasAI= true; + break; + case ESM::FourCC<'D','O','D','T'>::value: + { + Dest dodt; + esm.getHExact(&dodt.mPos, 24); + mTransport.push_back(dodt); + break; + } + case ESM::FourCC<'D','N','A','M'>::value: + mTransport.back().mCellName = esm.getHString(); + break; + case AI_Wander: + case AI_Activate: + case AI_Escort: + case AI_Follow: + case AI_Travel: + case AI_CNDT: + mAiPackage.add(esm); + break; + default: + esm.fail("Unknown subrecord " + esm.retSubName().toString()); + } } + if (!hasNpdt) + esm.fail("Missing NPDT subrecord"); + if (!hasFlags) + esm.fail("Missing FLAG subrecord"); } - mAiPackage.load(esm); -} -void NPC::save(ESMWriter &esm) const -{ - esm.writeHNOCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNCString("RNAM", mRace); - esm.writeHNCString("CNAM", mClass); - esm.writeHNCString("ANAM", mFaction); - esm.writeHNCString("BNAM", mHead); - esm.writeHNCString("KNAM", mHair); - esm.writeHNOCString("SCRI", mScript); - - if (mNpdtType == NPC_DEFAULT) - esm.writeHNT("NPDT", mNpdt52, 52); - else if (mNpdtType == NPC_WITH_AUTOCALCULATED_STATS) - esm.writeHNT("NPDT", mNpdt12, 12); - - esm.writeHNT("FLAG", mFlags); - - mInventory.save(esm); - mSpells.save(esm); - if (mHasAI) { - esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); - } + void NPC::save(ESMWriter &esm) const + { + esm.writeHNOCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNCString("RNAM", mRace); + esm.writeHNCString("CNAM", mClass); + esm.writeHNCString("ANAM", mFaction); + esm.writeHNCString("BNAM", mHead); + esm.writeHNCString("KNAM", mHair); + esm.writeHNOCString("SCRI", mScript); + + if (mNpdtType == NPC_DEFAULT) + esm.writeHNT("NPDT", mNpdt52, 52); + else if (mNpdtType == NPC_WITH_AUTOCALCULATED_STATS) + esm.writeHNT("NPDT", mNpdt12, 12); + + esm.writeHNT("FLAG", mFlags); + + mInventory.save(esm); + mSpells.save(esm); + if (mHasAI) { + esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); + } - typedef std::vector::const_iterator DestIter; - for (DestIter it = mTransport.begin(); it != mTransport.end(); ++it) { - esm.writeHNT("DODT", it->mPos, sizeof(it->mPos)); - esm.writeHNOCString("DNAM", it->mCellName); + typedef std::vector::const_iterator DestIter; + for (DestIter it = mTransport.begin(); it != mTransport.end(); ++it) { + esm.writeHNT("DODT", it->mPos, sizeof(it->mPos)); + esm.writeHNOCString("DNAM", it->mCellName); + } + mAiPackage.save(esm); } - mAiPackage.save(esm); -} bool NPC::isMale() const { return (mFlags & Female) == 0; diff --git a/components/esm/loadrace.cpp b/components/esm/loadrace.cpp index 17f2e0267..211fd5ffb 100644 --- a/components/esm/loadrace.cpp +++ b/components/esm/loadrace.cpp @@ -20,10 +20,34 @@ namespace ESM void Race::load(ESMReader &esm) { - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "RADT", 140); - mPowers.load(esm); - mDescription = esm.getHNOString("DESC"); + mPowers.mList.clear(); + + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'R','A','D','T'>::value: + esm.getHT(mData, 140); + hasData = true; + break; + case ESM::FourCC<'D','E','S','C'>::value: + mDescription = esm.getHString(); + break; + case ESM::FourCC<'N','P','C','S'>::value: + mPowers.add(esm); + break; + default: + esm.fail("Unknown subrecord " + esm.retSubName().toString()); + } + } + if (!hasData) + esm.fail("Missing RADT subrecord"); } void Race::save(ESMWriter &esm) const { diff --git a/components/esm/loadspel.cpp b/components/esm/loadspel.cpp index 2c98d796d..716f47e71 100644 --- a/components/esm/loadspel.cpp +++ b/components/esm/loadspel.cpp @@ -10,9 +10,30 @@ namespace ESM void Spell::load(ESMReader &esm) { - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "SPDT", 12); - mEffects.load(esm); + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t val = esm.retSubName().val; + + switch (val) + { + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'S','P','D','T'>::value: + esm.getHT(mData, 12); + hasData = true; + break; + case ESM::FourCC<'E','N','A','M'>::value: + ENAMstruct s; + esm.getHT(s, 24); + mEffects.mList.push_back(s); + break; + } + } + if (!hasData) + esm.fail("Missing SPDT subrecord"); } void Spell::save(ESMWriter &esm) const diff --git a/components/esm/loadweap.cpp b/components/esm/loadweap.cpp index 1d0b149df..981a5815a 100644 --- a/components/esm/loadweap.cpp +++ b/components/esm/loadweap.cpp @@ -8,24 +8,50 @@ namespace ESM { unsigned int Weapon::sRecordId = REC_WEAP; -void Weapon::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "WPDT", 32); - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); - mEnchant = esm.getHNOString("ENAM"); -} -void Weapon::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("WPDT", mData, 32); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNOCString("ITEX", mIcon); - esm.writeHNOCString("ENAM", mEnchant); -} + void Weapon::load(ESMReader &esm) + { + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'W','P','D','T'>::value: + esm.getHT(mData, 32); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + case ESM::FourCC<'E','N','A','M'>::value: + mEnchant = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing WPDT subrecord"); + } + void Weapon::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("WPDT", mData, 32); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); + esm.writeHNOCString("ENAM", mEnchant); + } void Weapon::blank() { diff --git a/components/esm/spelllist.cpp b/components/esm/spelllist.cpp index 8ec386db4..98bd53ae6 100644 --- a/components/esm/spelllist.cpp +++ b/components/esm/spelllist.cpp @@ -9,10 +9,15 @@ void SpellList::load(ESMReader &esm) { mList.clear(); while (esm.isNextSub("NPCS")) { - mList.push_back(esm.getHString()); + add(esm); } } +void SpellList::add(ESMReader &esm) +{ + mList.push_back(esm.getHString()); +} + void SpellList::save(ESMWriter &esm) const { for (std::vector::const_iterator it = mList.begin(); it != mList.end(); ++it) { diff --git a/components/esm/spelllist.hpp b/components/esm/spelllist.hpp index bcd6ba798..9493199a8 100644 --- a/components/esm/spelllist.hpp +++ b/components/esm/spelllist.hpp @@ -19,6 +19,11 @@ namespace ESM /// Is this spell ID in mList? bool exists(const std::string& spell) const; + /// Load one spell, assumes the subrecord name was already read + void add(ESMReader &esm); + + /// Load all spells + /// TODO: remove this method, the ESM format doesn't guarantee that all spell subrecords follow one another void load(ESMReader &esm); void save(ESMWriter &esm) const; }; From 6b0ca73352efc386507ae7115ad3ed3ed6f0cf73 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Wed, 11 Feb 2015 10:04:00 +0200 Subject: [PATCH 445/740] CI: use Qt from our homebrew tap --- CI/before_install.osx.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CI/before_install.osx.sh b/CI/before_install.osx.sh index 165763efa..8bfe2b70f 100755 --- a/CI/before_install.osx.sh +++ b/CI/before_install.osx.sh @@ -6,4 +6,4 @@ export CC=clang brew tap openmw/openmw brew update brew unlink boost -brew install openmw-mygui openmw-bullet openmw-sdl2 openmw-ffmpeg qt unshield +brew install openmw-mygui openmw-bullet openmw-sdl2 openmw-ffmpeg openmw/openmw/qt unshield From ca53ca89261b46a907fc7d08391ee1e2e4b8cd6c Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Wed, 11 Feb 2015 10:08:29 +0200 Subject: [PATCH 446/740] CI: perform `make package` on OS X --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index f9c917bbb..042d4b8f1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,6 +31,7 @@ before_script: script: - cd ./build - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then make -j4; fi + - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && ["${TRAVIS_OS_NAME}" = "osx"]; then make package; fi after_script: - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi notifications: From dfaab1188f86c62d23f360ffebaa1f4a0c821900 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Feb 2015 12:10:46 +0100 Subject: [PATCH 447/740] Fix for broken levelled creature spawning (Fixes #2365) --- apps/openmw/mwclass/creaturelevlist.cpp | 2 +- apps/openmw/mwclass/creaturelevlist.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwclass/creaturelevlist.cpp b/apps/openmw/mwclass/creaturelevlist.cpp index b1e27c345..dbc4b6af7 100644 --- a/apps/openmw/mwclass/creaturelevlist.cpp +++ b/apps/openmw/mwclass/creaturelevlist.cpp @@ -52,7 +52,7 @@ namespace MWClass registerClass (typeid (ESM::CreatureLevList).name(), instance); } - void CreatureLevList::insertObjectRendering(const MWWorld::Ptr &ptr, MWRender::RenderingInterface &renderingInterface) const + void CreatureLevList::insertObjectRendering(const MWWorld::Ptr &ptr, const std::string& model, MWRender::RenderingInterface &renderingInterface) const { ensureCustomData(ptr); diff --git a/apps/openmw/mwclass/creaturelevlist.hpp b/apps/openmw/mwclass/creaturelevlist.hpp index 7016524eb..177aa7235 100644 --- a/apps/openmw/mwclass/creaturelevlist.hpp +++ b/apps/openmw/mwclass/creaturelevlist.hpp @@ -20,7 +20,7 @@ namespace MWClass static void registerSelf(); - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) From cfe81bafe82a5a396ad7d82c16e3dc229bae2999 Mon Sep 17 00:00:00 2001 From: slothlife Date: Wed, 11 Feb 2015 21:46:00 -0600 Subject: [PATCH 448/740] Remove setting CMAKE_BUILD_TYPE to Debug Setting was causing single-target configurations (ninja, make) to incorrectly link vs debug runtimes on Windows. --- apps/opencs/CMakeLists.txt | 2 -- components/CMakeLists.txt | 1 - 2 files changed, 3 deletions(-) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 0b83feb45..b65aee4cf 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -4,8 +4,6 @@ set (OPENCS_SRC main.cpp opencs_units (. editor) -set (CMAKE_BUILD_TYPE DEBUG) - opencs_units (model/doc document operation saving documentmanager loader runner ) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 6f8352ddb..a49e54dd3 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -1,5 +1,4 @@ project (Components) -set (CMAKE_BUILD_TYPE DEBUG) # Version file set (VERSION_HPP_IN ${CMAKE_CURRENT_SOURCE_DIR}/version/version.hpp.cmake) From 49d912e5b6b1d728bf10c92d0b803dfda7596b89 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Feb 2015 04:56:05 +0100 Subject: [PATCH 449/740] Don't rely on subrecord order part 2 Nice side effects: - Subrecord name comparison now uses magic number instead of string (faster) - Improves the error message for unknown subrecords: will print the record in question instead of failing to read the next record with a strange error --- components/esm/aipackage.cpp | 23 ------ components/esm/aipackage.hpp | 3 - components/esm/effectlist.cpp | 11 ++- components/esm/effectlist.hpp | 6 +- components/esm/loadacti.cpp | 40 +++++++---- components/esm/loadalch.cpp | 63 ++++++++++++----- components/esm/loadappa.cpp | 40 +++++++---- components/esm/loadbody.cpp | 27 ++++++- components/esm/loadbsgn.cpp | 28 ++++++-- components/esm/loadclas.cpp | 70 +++++++++++------- components/esm/loadcont.cpp | 105 +++++++++++++++------------ components/esm/loadcont.hpp | 3 +- components/esm/loadcrea.cpp | 125 +++++++++++++++++++++------------ components/esm/loadench.cpp | 24 ++++++- components/esm/loadfact.cpp | 53 +++++++++----- components/esm/loadingr.cpp | 88 +++++++++++++++-------- components/esm/loadlevlist.cpp | 75 ++++++++++---------- components/esm/loadligh.cpp | 63 ++++++++++++----- components/esm/loadlock.cpp | 58 ++++++++++----- components/esm/loadmgef.cpp | 2 +- components/esm/loadmgef.hpp | 4 +- components/esm/loadnpc.cpp | 2 +- components/esm/loadprob.cpp | 58 ++++++++++----- components/esm/loadrace.cpp | 2 +- components/esm/loadrepa.cpp | 36 ++++++++-- components/esm/loadscpt.cpp | 106 ++++++++++++++-------------- components/esm/loadscpt.hpp | 3 + components/esm/loadskil.cpp | 54 ++++++++++---- components/esm/loadsndg.cpp | 45 ++++++++---- components/esm/loadsoun.cpp | 45 +++++++----- components/esm/loadspel.cpp | 58 +++++++-------- components/esm/loadsscr.cpp | 42 ++++++++--- components/esm/loadstat.cpp | 19 ++--- components/esm/loadtes3.hpp | 4 +- components/esm/spelllist.cpp | 8 --- components/esm/spelllist.hpp | 4 +- 36 files changed, 889 insertions(+), 508 deletions(-) diff --git a/components/esm/aipackage.cpp b/components/esm/aipackage.cpp index 8ad64b797..efcd6651e 100644 --- a/components/esm/aipackage.cpp +++ b/components/esm/aipackage.cpp @@ -41,29 +41,6 @@ namespace ESM } - void AIPackageList::load(ESMReader &esm) - { - mList.clear(); - while (esm.hasMoreSubs()) { - // initialize every iteration - esm.getSubName(); - switch (esm.retSubName().val) - { - case AI_Wander: - case AI_Activate: - case AI_Escort: - case AI_Follow: - case AI_Travel: - case AI_CNDT: - - add(esm); - break; - default: - return; - } - } - } - void AIPackageList::save(ESMWriter &esm) const { typedef std::vector::const_iterator PackageIter; diff --git a/components/esm/aipackage.hpp b/components/esm/aipackage.hpp index 30bd2ce04..5e08806c8 100644 --- a/components/esm/aipackage.hpp +++ b/components/esm/aipackage.hpp @@ -94,9 +94,6 @@ namespace ESM /// Add a single AIPackage, assumes subrecord name was already read void add(ESMReader &esm); - /// TODO: remove this method. The ESM format does not guarantee that all AI packages follow one another - void load(ESMReader &esm); - void save(ESMWriter &esm) const; }; } diff --git a/components/esm/effectlist.cpp b/components/esm/effectlist.cpp index fc9acccf2..f6d5a6e07 100644 --- a/components/esm/effectlist.cpp +++ b/components/esm/effectlist.cpp @@ -8,13 +8,18 @@ namespace ESM { void EffectList::load(ESMReader &esm) { mList.clear(); - ENAMstruct s; while (esm.isNextSub("ENAM")) { - esm.getHT(s, 24); - mList.push_back(s); + add(esm); } } +void EffectList::add(ESMReader &esm) +{ + ENAMstruct s; + esm.getHT(s, 24); + mList.push_back(s); +} + void EffectList::save(ESMWriter &esm) const { for (std::vector::const_iterator it = mList.begin(); it != mList.end(); ++it) { diff --git a/components/esm/effectlist.hpp b/components/esm/effectlist.hpp index 04adcc5cd..d581f8337 100644 --- a/components/esm/effectlist.hpp +++ b/components/esm/effectlist.hpp @@ -29,11 +29,15 @@ namespace ESM }; #pragma pack(pop) + /// EffectList, ENAM subrecord struct EffectList { - std::vector mList; + /// Load one effect, assumes subrecord name was already read + void add(ESMReader &esm); + + /// Load all effects void load(ESMReader &esm); void save(ESMWriter &esm) const; }; diff --git a/components/esm/loadacti.cpp b/components/esm/loadacti.cpp index 8efea3302..b5adce550 100644 --- a/components/esm/loadacti.cpp +++ b/components/esm/loadacti.cpp @@ -8,18 +8,34 @@ namespace ESM { unsigned int Activator::sRecordId = REC_ACTI; -void Activator::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - mScript = esm.getHNOString("SCRI"); -} -void Activator::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNOCString("SCRI", mScript); -} + void Activator::load(ESMReader &esm) + { + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + } + void Activator::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNOCString("SCRI", mScript); + } void Activator::blank() { diff --git a/components/esm/loadalch.cpp b/components/esm/loadalch.cpp index aac88482f..18db512c0 100644 --- a/components/esm/loadalch.cpp +++ b/components/esm/loadalch.cpp @@ -8,24 +8,51 @@ namespace ESM { unsigned int Potion::sRecordId = REC_ALCH; -void Potion::load(ESMReader &esm) -{ - mModel = esm.getHNOString("MODL"); - mIcon = esm.getHNOString("TEXT"); // not ITEX here for some reason - mScript = esm.getHNOString("SCRI"); - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "ALDT", 12); - mEffects.load(esm); -} -void Potion::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("TEXT", mIcon); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("ALDT", mData, 12); - mEffects.save(esm); -} + void Potion::load(ESMReader &esm) + { + mEffects.mList.clear(); + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'T','E','X','T'>::value: // not ITEX here for some reason + mIcon = esm.getHString(); + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'A','L','D','T'>::value: + esm.getHT(mData, 12); + hasData = true; + break; + case ESM::FourCC<'E','N','A','M'>::value: + mEffects.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing ALDT"); + } + void Potion::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("TEXT", mIcon); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("ALDT", mData, 12); + mEffects.save(esm); + } void Potion::blank() { diff --git a/components/esm/loadappa.cpp b/components/esm/loadappa.cpp index 29ea78acc..f2c82aacf 100644 --- a/components/esm/loadappa.cpp +++ b/components/esm/loadappa.cpp @@ -10,25 +10,35 @@ namespace ESM void Apparatus::load(ESMReader &esm) { - // we will not treat duplicated subrecords as errors here + bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - NAME subName = esm.retSubName(); - - if (subName == "MODL") - mModel = esm.getHString(); - else if (subName == "FNAM") - mName = esm.getHString(); - else if (subName == "AADT") - esm.getHT(mData); - else if (subName == "SCRI") - mScript = esm.getHString(); - else if (subName == "ITEX") - mIcon = esm.getHString(); - else - esm.fail("wrong subrecord type " + subName.toString() + " for APPA record"); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'A','A','D','T'>::value: + esm.getHT(mData); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } } + if (!hasData) + esm.fail("Missing AADT"); } void Apparatus::save(ESMWriter &esm) const diff --git a/components/esm/loadbody.cpp b/components/esm/loadbody.cpp index 9a1164d04..ed24ded57 100644 --- a/components/esm/loadbody.cpp +++ b/components/esm/loadbody.cpp @@ -11,9 +11,30 @@ namespace ESM void BodyPart::load(ESMReader &esm) { - mModel = esm.getHNString("MODL"); - mRace = esm.getHNOString("FNAM"); - esm.getHNT(mData, "BYDT", 4); + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mRace = esm.getHString(); + break; + case ESM::FourCC<'B','Y','D','T'>::value: + esm.getHT(mData, 4); + hasData = true; + break; + default: + esm.fail("Unknown subrecord"); + } + } + + if (!hasData) + esm.fail("Missing BYDT subrecord"); } void BodyPart::save(ESMWriter &esm) const { diff --git a/components/esm/loadbsgn.cpp b/components/esm/loadbsgn.cpp index db1a72a36..e0cd83ea0 100644 --- a/components/esm/loadbsgn.cpp +++ b/components/esm/loadbsgn.cpp @@ -10,11 +10,29 @@ namespace ESM void BirthSign::load(ESMReader &esm) { - mName = esm.getHNOString("FNAM"); - mTexture = esm.getHNOString("TNAM"); - mDescription = esm.getHNOString("DESC"); - - mPowers.load(esm); + mPowers.mList.clear(); + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'T','N','A','M'>::value: + mTexture = esm.getHString(); + break; + case ESM::FourCC<'D','E','S','C'>::value: + mDescription = esm.getHString(); + break; + case ESM::FourCC<'N','P','C','S'>::value: + mPowers.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + } + } } void BirthSign::save(ESMWriter &esm) const diff --git a/components/esm/loadclas.cpp b/components/esm/loadclas.cpp index ec339bd15..66acaea72 100644 --- a/components/esm/loadclas.cpp +++ b/components/esm/loadclas.cpp @@ -10,17 +10,17 @@ namespace ESM { unsigned int Class::sRecordId = REC_CLAS; -const Class::Specialization Class::sSpecializationIds[3] = { - Class::Combat, - Class::Magic, - Class::Stealth -}; + const Class::Specialization Class::sSpecializationIds[3] = { + Class::Combat, + Class::Magic, + Class::Stealth + }; -const char *Class::sGmstSpecializationIds[3] = { - "sSpecializationCombat", - "sSpecializationMagic", - "sSpecializationStealth" -}; + const char *Class::sGmstSpecializationIds[3] = { + "sSpecializationCombat", + "sSpecializationMagic", + "sSpecializationStealth" + }; int& Class::CLDTstruct::getSkill (int index, bool major) @@ -39,22 +39,40 @@ const char *Class::sGmstSpecializationIds[3] = { return mSkills[index][major ? 1 : 0]; } -void Class::load(ESMReader &esm) -{ - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "CLDT", 60); - - if (mData.mIsPlayable > 1) - esm.fail("Unknown bool value"); - - mDescription = esm.getHNOString("DESC"); -} -void Class::save(ESMWriter &esm) const -{ - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("CLDT", mData, 60); - esm.writeHNOString("DESC", mDescription); -} + void Class::load(ESMReader &esm) + { + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'C','L','D','T'>::value: + esm.getHT(mData, 60); + if (mData.mIsPlayable > 1) + esm.fail("Unknown bool value"); + hasData = true; + break; + case ESM::FourCC<'D','E','S','C'>::value: + mDescription = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing CLDT subrecord"); + } + void Class::save(ESMWriter &esm) const + { + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("CLDT", mData, 60); + esm.writeHNOString("DESC", mDescription); + } void Class::blank() { diff --git a/components/esm/loadcont.cpp b/components/esm/loadcont.cpp index f48f06930..999c3f92a 100644 --- a/components/esm/loadcont.cpp +++ b/components/esm/loadcont.cpp @@ -7,60 +7,79 @@ namespace ESM { -void InventoryList::add(ESMReader &esm) -{ - ContItem ci; - esm.getHT(ci, 36); - mList.push_back(ci); -} - -void InventoryList::load(ESMReader &esm) -{ - mList.clear(); - while (esm.isNextSub("NPCO")) + void InventoryList::add(ESMReader &esm) { - add(esm); + ContItem ci; + esm.getHT(ci, 36); + mList.push_back(ci); } -} -void InventoryList::save(ESMWriter &esm) const -{ - for (std::vector::const_iterator it = mList.begin(); it != mList.end(); ++it) + void InventoryList::save(ESMWriter &esm) const { - esm.writeHNT("NPCO", *it, 36); + for (std::vector::const_iterator it = mList.begin(); it != mList.end(); ++it) + { + esm.writeHNT("NPCO", *it, 36); + } } -} unsigned int Container::sRecordId = REC_CONT; -void Container::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - esm.getHNT(mWeight, "CNDT", 4); - esm.getHNT(mFlags, "FLAG", 4); - - if (mFlags & 0xf4) - esm.fail("Unknown flags"); - if (!(mFlags & 0x8)) - esm.fail("Flag 8 not set"); - - mScript = esm.getHNOString("SCRI"); - - mInventory.load(esm); -} + void Container::load(ESMReader &esm) + { + mInventory.mList.clear(); + bool hasWeight = false; + bool hasFlags = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'C','N','D','T'>::value: + esm.getHT(mWeight, 4); + hasWeight = true; + break; + case ESM::FourCC<'F','L','A','G'>::value: + esm.getHT(mFlags, 4); + if (mFlags & 0xf4) + esm.fail("Unknown flags"); + if (!(mFlags & 0x8)) + esm.fail("Flag 8 not set"); + hasFlags = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'N','P','C','O'>::value: + mInventory.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasWeight) + esm.fail("Missing CNDT subrecord"); + if (!hasFlags) + esm.fail("Missing FLAG subrecord"); + } -void Container::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("CNDT", mWeight, 4); - esm.writeHNT("FLAG", mFlags, 4); + void Container::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("CNDT", mWeight, 4); + esm.writeHNT("FLAG", mFlags, 4); - esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("SCRI", mScript); - mInventory.save(esm); -} + mInventory.save(esm); + } void Container::blank() { diff --git a/components/esm/loadcont.hpp b/components/esm/loadcont.hpp index 93db94759..76c522d74 100644 --- a/components/esm/loadcont.hpp +++ b/components/esm/loadcont.hpp @@ -22,6 +22,7 @@ struct ContItem NAME32 mItem; }; +/// InventoryList, NPCO subrecord struct InventoryList { std::vector mList; @@ -29,8 +30,6 @@ struct InventoryList /// Load one item, assumes subrecord name is already read void add(ESMReader &esm); - /// TODO: remove this method, the ESM format doesn't guarantee that all ContItems follow one another - void load(ESMReader &esm); void save(ESMWriter &esm) const; }; diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index 650de0801..2e9f924b7 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -8,55 +8,94 @@ namespace ESM { unsigned int Creature::sRecordId = REC_CREA; -void Creature::load(ESMReader &esm) -{ - mPersistent = esm.getRecordFlags() & 0x0400; - - mModel = esm.getHNString("MODL"); - mOriginal = esm.getHNOString("CNAM"); - mName = esm.getHNOString("FNAM"); - mScript = esm.getHNOString("SCRI"); - - esm.getHNT(mData, "NPDT", 96); - - esm.getHNT(mFlags, "FLAG"); - mScale = 1.0; - esm.getHNOT(mScale, "XSCL"); - - mInventory.load(esm); - mSpells.load(esm); - - if (esm.isNextSub("AIDT")) + void Creature::load(ESMReader &esm) { - esm.getHExact(&mAiData, sizeof(mAiData)); - mHasAI = true; - } - else - mHasAI = false; + mPersistent = esm.getRecordFlags() & 0x0400; - mAiPackage.load(esm); - esm.skipRecord(); -} + mAiPackage.mList.clear(); + mInventory.mList.clear(); + mSpells.mList.clear(); -void Creature::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("CNAM", mOriginal); - esm.writeHNOCString("FNAM", mName); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNT("NPDT", mData, 96); - esm.writeHNT("FLAG", mFlags); - if (mScale != 1.0) { - esm.writeHNT("XSCL", mScale); + mScale = 1.f; + mHasAI = false; + bool hasNpdt = false; + bool hasFlags = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'C','N','A','M'>::value: + mOriginal = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'N','P','D','T'>::value: + esm.getHT(mData, 96); + hasNpdt = true; + break; + case ESM::FourCC<'F','L','A','G'>::value: + esm.getHT(mFlags); + hasFlags = true; + break; + case ESM::FourCC<'X','S','C','L'>::value: + esm.getHT(mScale); + break; + case ESM::FourCC<'N','P','C','O'>::value: + mInventory.add(esm); + break; + case ESM::FourCC<'N','P','C','S'>::value: + mSpells.add(esm); + break; + case ESM::FourCC<'A','I','D','T'>::value: + esm.getHExact(&mAiData, sizeof(mAiData)); + mHasAI = true; + break; + case AI_Wander: + case AI_Activate: + case AI_Escort: + case AI_Follow: + case AI_Travel: + case AI_CNDT: + mAiPackage.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasNpdt) + esm.fail("Missing NPDT subrecord"); + if (!hasFlags) + esm.fail("Missing FLAG subrecord"); } - mInventory.save(esm); - mSpells.save(esm); - if (mHasAI) { - esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); + void Creature::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("CNAM", mOriginal); + esm.writeHNOCString("FNAM", mName); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNT("NPDT", mData, 96); + esm.writeHNT("FLAG", mFlags); + if (mScale != 1.0) { + esm.writeHNT("XSCL", mScale); + } + + mInventory.save(esm); + mSpells.save(esm); + if (mHasAI) { + esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); + } + mAiPackage.save(esm); } - mAiPackage.save(esm); -} void Creature::blank() { diff --git a/components/esm/loadench.cpp b/components/esm/loadench.cpp index 243803833..54690d9a0 100644 --- a/components/esm/loadench.cpp +++ b/components/esm/loadench.cpp @@ -10,8 +10,28 @@ namespace ESM void Enchantment::load(ESMReader &esm) { - esm.getHNT(mData, "ENDT", 16); - mEffects.load(esm); + mEffects.mList.clear(); + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'E','N','D','T'>::value: + esm.getHT(mData, 16); + hasData = true; + break; + case ESM::FourCC<'E','N','A','M'>::value: + mEffects.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + break; + } + } + if (!hasData) + esm.fail("Missing ENDT subrecord"); } void Enchantment::save(ESMWriter &esm) const diff --git a/components/esm/loadfact.cpp b/components/esm/loadfact.cpp index db7e5b7b4..006ca0ce0 100644 --- a/components/esm/loadfact.cpp +++ b/components/esm/loadfact.cpp @@ -28,27 +28,46 @@ namespace ESM void Faction::load(ESMReader &esm) { - mName = esm.getHNOString("FNAM"); + mReactions.clear(); + for (int i=0;i<10;++i) + mRanks[i].clear(); - // Read rank names. These are optional. - int i = 0; - while (esm.isNextSub("RNAM") && i < 10) - mRanks[i++] = esm.getHString(); - - // Main data struct - esm.getHNT(mData, "FADT", 240); - - if (mData.mIsHidden > 1) - esm.fail("Unknown flag!"); - - // Read faction response values + int rankCounter=0; + bool hasData = false; while (esm.hasMoreSubs()) { - std::string faction = esm.getHNString("ANAM"); - int reaction; - esm.getHNT(reaction, "INTV"); - mReactions[faction] = reaction; + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'R','N','A','M'>::value: + if (rankCounter >= 10) + esm.fail("Rank out of range"); + mRanks[rankCounter++] = esm.getHString(); + break; + case ESM::FourCC<'F','A','D','T'>::value: + esm.getHT(mData, 240); + if (mData.mIsHidden > 1) + esm.fail("Unknown flag!"); + hasData = true; + break; + case ESM::FourCC<'A','N','A','M'>::value: + { + std::string faction = esm.getHString(); + int reaction; + esm.getHNT(reaction, "INTV"); + mReactions[faction] = reaction; + break; + } + default: + esm.fail("Unknown subrecord"); + } } + if (!hasData) + esm.fail("Missing FADT subrecord"); } void Faction::save(ESMWriter &esm) const { diff --git a/components/esm/loadingr.cpp b/components/esm/loadingr.cpp index 5c98cb8b9..7e0cc3168 100644 --- a/components/esm/loadingr.cpp +++ b/components/esm/loadingr.cpp @@ -8,45 +8,71 @@ namespace ESM { unsigned int Ingredient::sRecordId = REC_INGR; -void Ingredient::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "IRDT", 56); - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); - // horrible hack to fix broken data in records - for (int i=0; i<4; ++i) + void Ingredient::load(ESMReader &esm) { - if (mData.mEffectID[i] != 85 && - mData.mEffectID[i] != 22 && - mData.mEffectID[i] != 17 && - mData.mEffectID[i] != 79 && - mData.mEffectID[i] != 74) + bool hasData = false; + while (esm.hasMoreSubs()) { - mData.mAttributes[i] = -1; + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'I','R','D','T'>::value: + esm.getHT(mData, 56); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } } - // is this relevant in cycle from 0 to 4? - if (mData.mEffectID[i] != 89 && - mData.mEffectID[i] != 26 && - mData.mEffectID[i] != 21 && - mData.mEffectID[i] != 83 && - mData.mEffectID[i] != 78) + if (!hasData) + esm.fail("Missing IRDT subrecord"); + + // horrible hack to fix broken data in records + for (int i=0; i<4; ++i) { - mData.mSkills[i] = -1; + if (mData.mEffectID[i] != 85 && + mData.mEffectID[i] != 22 && + mData.mEffectID[i] != 17 && + mData.mEffectID[i] != 79 && + mData.mEffectID[i] != 74) + { + mData.mAttributes[i] = -1; + } + + // is this relevant in cycle from 0 to 4? + if (mData.mEffectID[i] != 89 && + mData.mEffectID[i] != 26 && + mData.mEffectID[i] != 21 && + mData.mEffectID[i] != 83 && + mData.mEffectID[i] != 78) + { + mData.mSkills[i] = -1; + } } } -} -void Ingredient::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("IRDT", mData, 56); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNOCString("ITEX", mIcon); -} + void Ingredient::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("IRDT", mData, 56); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); + } void Ingredient::blank() { diff --git a/components/esm/loadlevlist.cpp b/components/esm/loadlevlist.cpp index 2cbfac0b4..6080d1e1a 100644 --- a/components/esm/loadlevlist.cpp +++ b/components/esm/loadlevlist.cpp @@ -7,49 +7,50 @@ namespace ESM { -void LevelledListBase::load(ESMReader &esm) -{ - esm.getHNT(mFlags, "DATA"); - esm.getHNT(mChanceNone, "NNAM"); - - if (esm.isNextSub("INDX")) - { - int len; - esm.getHT(len); - mList.resize(len); - } - else + void LevelledListBase::load(ESMReader &esm) { - esm.skipRecord(); - return; - } + esm.getHNT(mFlags, "DATA"); + esm.getHNT(mChanceNone, "NNAM"); - // If this levelled list was already loaded by a previous content file, - // we overwrite the list. Merging lists should probably be left to external tools, - // with the limited amount of information there is in the records, all merging methods - // will be flawed in some way. For a proper fix the ESM format would have to be changed - // to actually track list changes instead of including the whole list for every file - // that does something with that list. + if (esm.isNextSub("INDX")) + { + int len; + esm.getHT(len); + mList.resize(len); + } + else + { + // Original engine ignores rest of the record, even if there are items following + esm.skipRecord(); + return; + } - for (size_t i = 0; i < mList.size(); i++) - { - LevelItem &li = mList[i]; - li.mId = esm.getHNString(mRecName); - esm.getHNT(li.mLevel, "INTV"); - } -} -void LevelledListBase::save(ESMWriter &esm) const -{ - esm.writeHNT("DATA", mFlags); - esm.writeHNT("NNAM", mChanceNone); - esm.writeHNT("INDX", mList.size()); + // If this levelled list was already loaded by a previous content file, + // we overwrite the list. Merging lists should probably be left to external tools, + // with the limited amount of information there is in the records, all merging methods + // will be flawed in some way. For a proper fix the ESM format would have to be changed + // to actually track list changes instead of including the whole list for every file + // that does something with that list. - for (std::vector::const_iterator it = mList.begin(); it != mList.end(); ++it) + for (size_t i = 0; i < mList.size(); i++) + { + LevelItem &li = mList[i]; + li.mId = esm.getHNString(mRecName); + esm.getHNT(li.mLevel, "INTV"); + } + } + void LevelledListBase::save(ESMWriter &esm) const { - esm.writeHNCString(mRecName, it->mId); - esm.writeHNT("INTV", it->mLevel); + esm.writeHNT("DATA", mFlags); + esm.writeHNT("NNAM", mChanceNone); + esm.writeHNT("INDX", mList.size()); + + for (std::vector::const_iterator it = mList.begin(); it != mList.end(); ++it) + { + esm.writeHNCString(mRecName, it->mId); + esm.writeHNT("INTV", it->mLevel); + } } -} void LevelledListBase::blank() { diff --git a/components/esm/loadligh.cpp b/components/esm/loadligh.cpp index f88ff09d6..26d70d964 100644 --- a/components/esm/loadligh.cpp +++ b/components/esm/loadligh.cpp @@ -8,25 +8,50 @@ namespace ESM { unsigned int Light::sRecordId = REC_LIGH; -void Light::load(ESMReader &esm) -{ - mModel = esm.getHNOString("MODL"); - mName = esm.getHNOString("FNAM"); - mIcon = esm.getHNOString("ITEX"); - assert(sizeof(mData) == 24); - esm.getHNT(mData, "LHDT", 24); - mScript = esm.getHNOString("SCRI"); - mSound = esm.getHNOString("SNAM"); -} -void Light::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNOCString("ITEX", mIcon); - esm.writeHNT("LHDT", mData, 24); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNOCString("SNAM", mSound); -} + void Light::load(ESMReader &esm) + { + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + case ESM::FourCC<'L','H','D','T'>::value: + esm.getHT(mData, 24); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'S','N','A','M'>::value: + mSound = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing LHDT subrecord"); + } + void Light::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNOCString("ITEX", mIcon); + esm.writeHNT("LHDT", mData, 24); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("SNAM", mSound); + } void Light::blank() { diff --git a/components/esm/loadlock.cpp b/components/esm/loadlock.cpp index 42677a22b..2747a6f78 100644 --- a/components/esm/loadlock.cpp +++ b/components/esm/loadlock.cpp @@ -8,26 +8,48 @@ namespace ESM { unsigned int Lockpick::sRecordId = REC_LOCK; -void Lockpick::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - - esm.getHNT(mData, "LKDT", 16); - - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); -} + void Lockpick::load(ESMReader &esm) + { + bool hasData = true; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'L','K','D','T'>::value: + esm.getHT(mData, 16); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing LKDT subrecord"); + } -void Lockpick::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); + void Lockpick::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); - esm.writeHNT("LKDT", mData, 16); - esm.writeHNOString("SCRI", mScript); - esm.writeHNOCString("ITEX", mIcon); -} + esm.writeHNT("LKDT", mData, 16); + esm.writeHNOString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); + } void Lockpick::blank() { diff --git a/components/esm/loadmgef.cpp b/components/esm/loadmgef.cpp index 3ec07a2a9..6f859ab3c 100644 --- a/components/esm/loadmgef.cpp +++ b/components/esm/loadmgef.cpp @@ -246,7 +246,7 @@ void MagicEffect::load(ESMReader &esm) mDescription = esm.getHString(); break; default: - esm.fail("Unknown subrecord " + esm.retSubName().toString()); + esm.fail("Unknown subrecord"); } } } diff --git a/components/esm/loadmgef.hpp b/components/esm/loadmgef.hpp index 4c7ac938a..e66322832 100644 --- a/components/esm/loadmgef.hpp +++ b/components/esm/loadmgef.hpp @@ -57,9 +57,9 @@ struct MagicEffect // Glow color for enchanted items with this effect int mRed, mGreen, mBlue; - float mUnknown1; + float mUnknown1; // Called "Size X" in CS float mSpeed; // Speed of fired projectile - float mUnknown2; + float mUnknown2; // Called "Size Cap" in CS }; // 36 bytes static const std::map sNames; diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index 3d617241b..d90b4816d 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -99,7 +99,7 @@ namespace ESM mAiPackage.add(esm); break; default: - esm.fail("Unknown subrecord " + esm.retSubName().toString()); + esm.fail("Unknown subrecord"); } } if (!hasNpdt) diff --git a/components/esm/loadprob.cpp b/components/esm/loadprob.cpp index b736bb64b..c5f80c584 100644 --- a/components/esm/loadprob.cpp +++ b/components/esm/loadprob.cpp @@ -8,26 +8,48 @@ namespace ESM { unsigned int Probe::sRecordId = REC_PROB; -void Probe::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - - esm.getHNT(mData, "PBDT", 16); - - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); -} + void Probe::load(ESMReader &esm) + { + bool hasData = true; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'P','B','D','T'>::value: + esm.getHT(mData, 16); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing PBDT subrecord"); + } -void Probe::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); + void Probe::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); - esm.writeHNT("PBDT", mData, 16); - esm.writeHNOString("SCRI", mScript); - esm.writeHNOCString("ITEX", mIcon); -} + esm.writeHNT("PBDT", mData, 16); + esm.writeHNOString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); + } void Probe::blank() { diff --git a/components/esm/loadrace.cpp b/components/esm/loadrace.cpp index 211fd5ffb..967c0d0d7 100644 --- a/components/esm/loadrace.cpp +++ b/components/esm/loadrace.cpp @@ -43,7 +43,7 @@ void Race::load(ESMReader &esm) mPowers.add(esm); break; default: - esm.fail("Unknown subrecord " + esm.retSubName().toString()); + esm.fail("Unknown subrecord"); } } if (!hasData) diff --git a/components/esm/loadrepa.cpp b/components/esm/loadrepa.cpp index 4e6cd7794..f90f9e39d 100644 --- a/components/esm/loadrepa.cpp +++ b/components/esm/loadrepa.cpp @@ -10,13 +10,35 @@ namespace ESM void Repair::load(ESMReader &esm) { - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - - esm.getHNT(mData, "RIDT", 16); - - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); + bool hasData = true; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'R','I','D','T'>::value: + esm.getHT(mData, 16); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing RIDT subrecord"); } void Repair::save(ESMWriter &esm) const diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index 2df8e66ce..0c2bdd42f 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -9,17 +9,7 @@ namespace ESM unsigned int Script::sRecordId = REC_SCPT; -void Script::load(ESMReader &esm) -{ - SCHD data; - esm.getHNT(data, "SCHD", 52); - mData = data.mData; - mId = data.mName.toString(); - - mVarNames.clear(); - - // List of local variables - if (esm.isNextSub("SCVR")) + void Script::loadSCVR(ESMReader &esm) { int s = mData.mStringTableSize; @@ -66,58 +56,70 @@ void Script::load(ESMReader &esm) } } - // Script mData - if (esm.isNextSub("SCDT")) + void Script::load(ESMReader &esm) { - mScriptData.resize(mData.mScriptDataSize); - esm.getHExact(&mScriptData[0], mScriptData.size()); - } + SCHD data; + esm.getHNT(data, "SCHD", 52); + mData = data.mData; + mId = data.mName.toString(); + + mVarNames.clear(); - // Script text - mScriptText = esm.getHNOString("SCTX"); - - // NOTE: A minor hack/workaround... - // - // MAO_Containers.esp from Morrowind Acoustic Overhaul has SCVR records - // at the end (see Bug #1849). Since OpenMW does not use SCVR subrecords - // for variable names just skip these as a quick fix. An alternative - // solution would be to decode and validate SCVR subrecords even if they - // appear here. - if (esm.isNextSub("SCVR")) { - esm.skipHSub(); + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'S','C','V','R'>::value: + // list of local variables + loadSCVR(esm); + break; + case ESM::FourCC<'S','C','D','T'>::value: + // compiled script + mScriptData.resize(mData.mScriptDataSize); + esm.getHExact(&mScriptData[0], mScriptData.size()); + break; + case ESM::FourCC<'S','C','T','X'>::value: + mScriptText = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } } -} -void Script::save(ESMWriter &esm) const -{ - std::string varNameString; - if (!mVarNames.empty()) - for (std::vector::const_iterator it = mVarNames.begin(); it != mVarNames.end(); ++it) - varNameString.append(*it); - SCHD data; - memset(&data, 0, sizeof(data)); + void Script::save(ESMWriter &esm) const + { + std::string varNameString; + if (!mVarNames.empty()) + for (std::vector::const_iterator it = mVarNames.begin(); it != mVarNames.end(); ++it) + varNameString.append(*it); - data.mData = mData; - memcpy(data.mName.name, mId.c_str(), mId.size()); + SCHD data; + memset(&data, 0, sizeof(data)); - esm.writeHNT("SCHD", data, 52); + data.mData = mData; + memcpy(data.mName.name, mId.c_str(), mId.size()); - if (!mVarNames.empty()) - { - esm.startSubRecord("SCVR"); - for (std::vector::const_iterator it = mVarNames.begin(); it != mVarNames.end(); ++it) + esm.writeHNT("SCHD", data, 52); + + if (!mVarNames.empty()) { - esm.writeHCString(*it); + esm.startSubRecord("SCVR"); + for (std::vector::const_iterator it = mVarNames.begin(); it != mVarNames.end(); ++it) + { + esm.writeHCString(*it); + } + esm.endRecord("SCVR"); } - esm.endRecord("SCVR"); - } - esm.startSubRecord("SCDT"); - esm.write(reinterpret_cast(&mScriptData[0]), mData.mScriptDataSize); - esm.endRecord("SCDT"); + esm.startSubRecord("SCDT"); + esm.write(reinterpret_cast(&mScriptData[0]), mData.mScriptDataSize); + esm.endRecord("SCDT"); - esm.writeHNOString("SCTX", mScriptText); -} + esm.writeHNOString("SCTX", mScriptText); + } void Script::blank() { diff --git a/components/esm/loadscpt.hpp b/components/esm/loadscpt.hpp index d5b87b5dc..deb71de6a 100644 --- a/components/esm/loadscpt.hpp +++ b/components/esm/loadscpt.hpp @@ -53,6 +53,9 @@ public: void blank(); ///< Set record to default state (does not touch the ID/index). + +private: + void loadSCVR(ESMReader &esm); }; } #endif diff --git a/components/esm/loadskil.cpp b/components/esm/loadskil.cpp index b6724e938..7883b8a1a 100644 --- a/components/esm/loadskil.cpp +++ b/components/esm/loadskil.cpp @@ -129,23 +129,47 @@ namespace ESM unsigned int Skill::sRecordId = REC_SKIL; -void Skill::load(ESMReader &esm) -{ - esm.getHNT(mIndex, "INDX"); - esm.getHNT(mData, "SKDT", 24); - mDescription = esm.getHNOString("DESC"); + void Skill::load(ESMReader &esm) + { + bool hasIndex = false; + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'I','N','D','X'>::value: + esm.getHT(mIndex); + hasIndex = true; + break; + case ESM::FourCC<'S','K','D','T'>::value: + esm.getHT(mData, 24); + hasData = true; + break; + case ESM::FourCC<'D','E','S','C'>::value: + mDescription = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasIndex) + esm.fail("Missing INDX"); + if (!hasData) + esm.fail("Missing SKDT"); - // create an ID from the index and the name (only used in the editor and likely to change in the - // future) - mId = indexToId (mIndex); -} + // create an ID from the index and the name (only used in the editor and likely to change in the + // future) + mId = indexToId (mIndex); + } -void Skill::save(ESMWriter &esm) const -{ - esm.writeHNT("INDX", mIndex); - esm.writeHNT("SKDT", mData, 24); - esm.writeHNOString("DESC", mDescription); -} + void Skill::save(ESMWriter &esm) const + { + esm.writeHNT("INDX", mIndex); + esm.writeHNT("SKDT", mData, 24); + esm.writeHNOString("DESC", mDescription); + } void Skill::blank() { diff --git a/components/esm/loadsndg.cpp b/components/esm/loadsndg.cpp index 9ab061ec2..5ee6f5245 100644 --- a/components/esm/loadsndg.cpp +++ b/components/esm/loadsndg.cpp @@ -8,19 +8,38 @@ namespace ESM { unsigned int SoundGenerator::sRecordId = REC_SNDG; -void SoundGenerator::load(ESMReader &esm) -{ - esm.getHNT(mType, "DATA", 4); - - mCreature = esm.getHNOString("CNAM"); - mSound = esm.getHNOString("SNAM"); -} -void SoundGenerator::save(ESMWriter &esm) const -{ - esm.writeHNT("DATA", mType, 4); - esm.writeHNOCString("CNAM", mCreature); - esm.writeHNOCString("SNAM", mSound); -} + void SoundGenerator::load(ESMReader &esm) + { + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'D','A','T','A'>::value: + esm.getHT(mType, 4); + hasData = true; + break; + case ESM::FourCC<'C','N','A','M'>::value: + mCreature = esm.getHString(); + break; + case ESM::FourCC<'S','N','A','M'>::value: + mSound = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing DATA"); + } + void SoundGenerator::save(ESMWriter &esm) const + { + esm.writeHNT("DATA", mType, 4); + esm.writeHNOCString("CNAM", mCreature); + esm.writeHNOCString("SNAM", mSound); + } void SoundGenerator::blank() { diff --git a/components/esm/loadsoun.cpp b/components/esm/loadsoun.cpp index 28e4d7d9c..690c1b448 100644 --- a/components/esm/loadsoun.cpp +++ b/components/esm/loadsoun.cpp @@ -8,22 +8,35 @@ namespace ESM { unsigned int Sound::sRecordId = REC_SOUN; -void Sound::load(ESMReader &esm) -{ - mSound = esm.getHNOString("FNAM"); - esm.getHNT(mData, "DATA", 3); - /* - cout << "vol=" << (int)data.volume - << " min=" << (int)data.minRange - << " max=" << (int)data.maxRange - << endl; - */ -} -void Sound::save(ESMWriter &esm) const -{ - esm.writeHNOCString("FNAM", mSound); - esm.writeHNT("DATA", mData, 3); -} + void Sound::load(ESMReader &esm) + { + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'F','N','A','M'>::value: + mSound = esm.getHString(); + break; + case ESM::FourCC<'D','A','T','A'>::value: + esm.getHT(mData, 3); + hasData = true; + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing DATA"); + } + + void Sound::save(ESMWriter &esm) const + { + esm.writeHNOCString("FNAM", mSound); + esm.writeHNT("DATA", mData, 3); + } void Sound::blank() { diff --git a/components/esm/loadspel.cpp b/components/esm/loadspel.cpp index 716f47e71..cd630d6ab 100644 --- a/components/esm/loadspel.cpp +++ b/components/esm/loadspel.cpp @@ -8,40 +8,40 @@ namespace ESM { unsigned int Spell::sRecordId = REC_SPEL; -void Spell::load(ESMReader &esm) -{ - bool hasData = false; - while (esm.hasMoreSubs()) + void Spell::load(ESMReader &esm) { - esm.getSubName(); - uint32_t val = esm.retSubName().val; - - switch (val) + bool hasData = false; + while (esm.hasMoreSubs()) { - case ESM::FourCC<'F','N','A','M'>::value: - mName = esm.getHString(); - break; - case ESM::FourCC<'S','P','D','T'>::value: - esm.getHT(mData, 12); - hasData = true; - break; - case ESM::FourCC<'E','N','A','M'>::value: - ENAMstruct s; - esm.getHT(s, 24); - mEffects.mList.push_back(s); - break; + esm.getSubName(); + uint32_t val = esm.retSubName().val; + + switch (val) + { + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'S','P','D','T'>::value: + esm.getHT(mData, 12); + hasData = true; + break; + case ESM::FourCC<'E','N','A','M'>::value: + ENAMstruct s; + esm.getHT(s, 24); + mEffects.mList.push_back(s); + break; + } } + if (!hasData) + esm.fail("Missing SPDT subrecord"); } - if (!hasData) - esm.fail("Missing SPDT subrecord"); -} -void Spell::save(ESMWriter &esm) const -{ - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("SPDT", mData, 12); - mEffects.save(esm); -} + void Spell::save(ESMWriter &esm) const + { + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("SPDT", mData, 12); + mEffects.save(esm); + } void Spell::blank() { diff --git a/components/esm/loadsscr.cpp b/components/esm/loadsscr.cpp index 69b04bb23..816075b7e 100644 --- a/components/esm/loadsscr.cpp +++ b/components/esm/loadsscr.cpp @@ -8,15 +8,37 @@ namespace ESM { unsigned int StartScript::sRecordId = REC_SSCR; -void StartScript::load(ESMReader &esm) -{ - mData = esm.getHNString("DATA"); - mScript = esm.getHNString("NAME"); -} -void StartScript::save(ESMWriter &esm) const -{ - esm.writeHNString("DATA", mData); - esm.writeHNString("NAME", mScript); -} + void StartScript::load(ESMReader &esm) + { + bool hasData = false; + bool hasName = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'D','A','T','A'>::value: + mData = esm.getHString(); + hasData = true; + break; + case ESM::FourCC<'N','A','M','E'>::value: + mScript = esm.getHString(); + hasName = true; + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing DATA"); + if (!hasName) + esm.fail("Missing NAME"); + } + void StartScript::save(ESMWriter &esm) const + { + esm.writeHNString("DATA", mData); + esm.writeHNString("NAME", mScript); + } } diff --git a/components/esm/loadstat.cpp b/components/esm/loadstat.cpp index 53d1b4bb5..2bb817332 100644 --- a/components/esm/loadstat.cpp +++ b/components/esm/loadstat.cpp @@ -8,15 +8,16 @@ namespace ESM { unsigned int Static::sRecordId = REC_STAT; -void Static::load(ESMReader &esm) -{ - mPersistent = esm.getRecordFlags() & 0x0400; - mModel = esm.getHNString("MODL"); -} -void Static::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); -} + void Static::load(ESMReader &esm) + { + mPersistent = esm.getRecordFlags() & 0x0400; + + mModel = esm.getHNString("MODL"); + } + void Static::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + } void Static::blank() { diff --git a/components/esm/loadtes3.hpp b/components/esm/loadtes3.hpp index 2c63e3691..f2dde4d1f 100644 --- a/components/esm/loadtes3.hpp +++ b/components/esm/loadtes3.hpp @@ -50,8 +50,8 @@ namespace ESM NAME32 mPlayerName; }; GMDT mGameData; // Used in .ess savegames only - std::vector mSCRD; // Used in .ess savegames only, screenshot? - std::vector mSCRS; // Used in .ess savegames only, screenshot? + std::vector mSCRD; // Used in .ess savegames only, unknown + std::vector mSCRS; // Used in .ess savegames only, screenshot Data mData; int mFormat; diff --git a/components/esm/spelllist.cpp b/components/esm/spelllist.cpp index 98bd53ae6..71c7b340d 100644 --- a/components/esm/spelllist.cpp +++ b/components/esm/spelllist.cpp @@ -5,14 +5,6 @@ namespace ESM { -void SpellList::load(ESMReader &esm) -{ - mList.clear(); - while (esm.isNextSub("NPCS")) { - add(esm); - } -} - void SpellList::add(ESMReader &esm) { mList.push_back(esm.getHString()); diff --git a/components/esm/spelllist.hpp b/components/esm/spelllist.hpp index 9493199a8..6fb098065 100644 --- a/components/esm/spelllist.hpp +++ b/components/esm/spelllist.hpp @@ -11,6 +11,7 @@ namespace ESM /** A list of references to spells and spell effects. This is shared between the records BSGN, NPC and RACE. + NPCS subrecord. */ struct SpellList { @@ -22,9 +23,6 @@ namespace ESM /// Load one spell, assumes the subrecord name was already read void add(ESMReader &esm); - /// Load all spells - /// TODO: remove this method, the ESM format doesn't guarantee that all spell subrecords follow one another - void load(ESMReader &esm); void save(ESMWriter &esm) const; }; } From e1314d62117a31d3bd77912c6c70f67b26262a6f Mon Sep 17 00:00:00 2001 From: Kamil Bar Date: Fri, 13 Feb 2015 04:11:36 +0100 Subject: [PATCH 450/740] Implement OpenCS reference validation (Feature #831) --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/tools/referencecheck.cpp | 103 +++++++++++++++++++++ apps/opencs/model/tools/referencecheck.hpp | 28 ++++++ apps/opencs/model/tools/tools.cpp | 3 + 4 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/tools/referencecheck.cpp create mode 100644 apps/opencs/model/tools/referencecheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 0b83feb45..d29546208 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -41,7 +41,7 @@ opencs_units (model/tools opencs_units_noqt (model/tools mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck - birthsigncheck spellcheck referenceablecheck scriptcheck bodypartcheck + birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck ) diff --git a/apps/opencs/model/tools/referencecheck.cpp b/apps/opencs/model/tools/referencecheck.cpp new file mode 100644 index 000000000..eb97645eb --- /dev/null +++ b/apps/opencs/model/tools/referencecheck.cpp @@ -0,0 +1,103 @@ +#include "referencecheck.hpp" + +#include + +CSMTools::ReferenceCheckStage::ReferenceCheckStage( + const CSMWorld::RefCollection& references, + const CSMWorld::RefIdCollection& referencables, + const CSMWorld::IdCollection& cells, + const CSMWorld::IdCollection& factions) + : + mReferences(references), + mReferencables(referencables), + mCells(cells), + mFactions(factions) +{ +} + +void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &messages) +{ + const CSMWorld::Record& record = mReferences.getRecord(stage); + + if (record.isDeleted()) + return; + + const CSMWorld::CellRef& cellRef = record.get(); + const CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Reference, cellRef.mId); + + // Check for empty reference id + if (cellRef.mRefID.empty()) + messages.push_back(std::make_pair(id, " is an empty reference")); + + // Check for non existing referenced object + if (mReferencables.searchId(cellRef.mRefID) == -1) + messages.push_back(std::make_pair(id, " is referencing non existing object " + cellRef.mRefID)); + + // Check if referenced object is in valid cell + if (mCells.searchId(cellRef.mCell) == -1) + messages.push_back(std::make_pair(id, " is referencing object from non existing cell " + cellRef.mCell)); + + // If object have owner, check if that owner reference is valid + if (!cellRef.mOwner.empty() and mReferencables.searchId(cellRef.mOwner) == -1) + messages.push_back(std::make_pair(id, " has non existing owner " + cellRef.mOwner)); + + // If object have creature soul trapped, check if that creature reference is valid + if (!cellRef.mSoul.empty()) + if (mReferencables.searchId(cellRef.mSoul) == -1) + messages.push_back(std::make_pair(id, " has non existing trapped soul " + cellRef.mSoul)); + + bool hasFaction = !cellRef.mFaction.empty(); + + // If object have faction, check if that faction reference is valid + if (hasFaction) + if (mFactions.searchId(cellRef.mFaction) == -1) + messages.push_back(std::make_pair(id, " has non existing faction " + cellRef.mFaction)); + + // Check item's faction rank + if (hasFaction && cellRef.mFactionRank < -1) + messages.push_back(std::make_pair(id, " has faction set but has invalid faction rank " + cellRef.mFactionRank)); + else if (!hasFaction && cellRef.mFactionRank != -2) + messages.push_back(std::make_pair(id, " has invalid faction rank " + cellRef.mFactionRank)); + + // If door have destination cell, check if that reference is valid + if (!cellRef.mDestCell.empty()) + if (mCells.searchId(cellRef.mDestCell) == -1) + messages.push_back(std::make_pair(id, " has non existing destination cell " + cellRef.mDestCell)); + + // Check if scale isn't negative + if (cellRef.mScale < 0) + { + std::string str = " has negative scale "; + str += boost::lexical_cast(cellRef.mScale); + messages.push_back(std::make_pair(id, id.getId() + str)); + } + + // Check if charge isn't negative + if (cellRef.mChargeFloat < 0) + { + std::string str = " has negative charges "; + str += boost::lexical_cast(cellRef.mChargeFloat); + messages.push_back(std::make_pair(id, id.getId() + str)); + } + + // Check if enchantement points aren't negative or are at full (-1) + if (cellRef.mEnchantmentCharge < 0 && cellRef.mEnchantmentCharge != -1) + { + std::string str = " has negative enchantment points "; + str += boost::lexical_cast(cellRef.mEnchantmentCharge); + messages.push_back(std::make_pair(id, id.getId() + str)); + } + + // Check if gold value isn't negative + if (cellRef.mGoldValue < 0) + { + std::string str = " has negative gold value "; + str += cellRef.mGoldValue; + messages.push_back(std::make_pair(id, id.getId() + str)); + } +} + +int CSMTools::ReferenceCheckStage::setup() +{ + return mReferences.getSize(); +} \ No newline at end of file diff --git a/apps/opencs/model/tools/referencecheck.hpp b/apps/opencs/model/tools/referencecheck.hpp new file mode 100644 index 000000000..d1eacb5b5 --- /dev/null +++ b/apps/opencs/model/tools/referencecheck.hpp @@ -0,0 +1,28 @@ +#ifndef CSM_TOOLS_REFERENCECHECK_H +#define CSM_TOOLS_REFERENCECHECK_H + +#include "../doc/state.hpp" +#include "../doc/document.hpp" + +namespace CSMTools +{ + class ReferenceCheckStage : public CSMDoc::Stage + { + public: + ReferenceCheckStage (const CSMWorld::RefCollection& references, + const CSMWorld::RefIdCollection& referencables, + const CSMWorld::IdCollection& cells, + const CSMWorld::IdCollection& factions); + + virtual void perform(int stage, CSMDoc::Messages& messages); + virtual int setup(); + + private: + const CSMWorld::RefCollection& mReferences; + const CSMWorld::RefIdCollection& mReferencables; + const CSMWorld::IdCollection& mCells; + const CSMWorld::IdCollection& mFactions; + }; +} + +#endif // CSM_TOOLS_REFERENCECHECK_H \ No newline at end of file diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 6e157f664..0c20bd17b 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -23,6 +23,7 @@ #include "referenceablecheck.hpp" #include "scriptcheck.hpp" #include "bodypartcheck.hpp" +#include "referencecheck.hpp" CSMDoc::Operation *CSMTools::Tools::get (int type) { @@ -82,6 +83,8 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier() mVerifier->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions())); + mVerifier->appendStage (new ReferenceCheckStage(mData.getReferences(), mData.getReferenceables(), mData.getCells(), mData.getFactions())); + mVerifier->appendStage (new ScriptCheckStage (mDocument)); mVerifier->appendStage( From 1d18d3ff4cb5a6f28b7f0d7ca03f076a5794a447 Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Thu, 12 Feb 2015 22:27:47 -0600 Subject: [PATCH 451/740] Add a full search to findInteriorPositionInWorldSpace. Part of OMW Bug #1533 Implement a search for one of the 'nearest' exterior cells. In this case, 'nearest' means the fewest number of cells away via door markers. This causes the world map position to update immediately after teleporting, unless the new cell has no connecting path to an exterior. Intervention spells and Jail travel will be much closer to vanialla Morrowind, except for in Mournhold. --- apps/openmw/mwworld/worldimp.cpp | 49 +++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 188f3cdad..23cef1596 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2784,18 +2784,45 @@ namespace MWWorld { if (cell->isExterior()) return false; - MWWorld::CellRefList& doors = cell->get(); - CellRefList::List& refList = doors.mList; - // Check if any door in the cell leads to an exterior directly - for (CellRefList::List::iterator it = refList.begin(); it != refList.end(); ++it) - { - MWWorld::LiveCellRef& ref = *it; - if (ref.mRef.getTeleport() && ref.mRef.getDestCell().empty()) - { - ESM::Position pos = ref.mRef.getDoorDest(); - result = Ogre::Vector3(pos.pos); - return true; + // Search for a 'nearest' exterior, counting each cell between the starting + // cell and the exterior as a distance of 1. Will fail for isolated interiors. + std::set< std::string >checkedCells; + std::set< std::string >currentCells; + std::set< std::string >nextCells; + nextCells.insert( cell->getCell()->mName ); + + while ( !nextCells.empty() ) { + currentCells = nextCells; + nextCells.clear(); + for( std::set< std::string >::const_iterator i = currentCells.begin(); i != currentCells.end(); ++i ) { + MWWorld::CellStore *next = getInterior( *i ); + if ( !next ) continue; + + MWWorld::CellRefList& doors = next->get(); + CellRefList::List& refList = doors.mList; + + // Check if any door in the cell leads to an exterior directly + for (CellRefList::List::iterator it = refList.begin(); it != refList.end(); ++it) + { + MWWorld::LiveCellRef& ref = *it; + if (!ref.mRef.getTeleport()) continue; + + if (ref.mRef.getDestCell().empty()) + { + ESM::Position pos = ref.mRef.getDoorDest(); + result = Ogre::Vector3(pos.pos); + return true; + } + else + { + std::string dest = ref.mRef.getDestCell(); + if ( !checkedCells.count(dest) && !currentCells.count(dest) ) + nextCells.insert(dest); + } + } + + checkedCells.insert( *i ); } } From 52a064afc39a205eb0b893862b76d331dc6063cf Mon Sep 17 00:00:00 2001 From: Kamil Bar Date: Fri, 13 Feb 2015 12:13:40 +0100 Subject: [PATCH 452/740] Fixed charges checking --- apps/opencs/model/tools/referencecheck.cpp | 40 +++++++++++++++------- apps/opencs/model/tools/referencecheck.hpp | 1 + 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/apps/opencs/model/tools/referencecheck.cpp b/apps/opencs/model/tools/referencecheck.cpp index eb97645eb..f1d092be5 100644 --- a/apps/opencs/model/tools/referencecheck.cpp +++ b/apps/opencs/model/tools/referencecheck.cpp @@ -10,6 +10,7 @@ CSMTools::ReferenceCheckStage::ReferenceCheckStage( : mReferences(references), mReferencables(referencables), + mDataSet(referencables.getDataSet()), mCells(cells), mFactions(factions) { @@ -26,12 +27,33 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message const CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Reference, cellRef.mId); // Check for empty reference id - if (cellRef.mRefID.empty()) + if (cellRef.mRefID.empty()) { messages.push_back(std::make_pair(id, " is an empty reference")); - - // Check for non existing referenced object - if (mReferencables.searchId(cellRef.mRefID) == -1) - messages.push_back(std::make_pair(id, " is referencing non existing object " + cellRef.mRefID)); + } else { + // Check for non existing referenced object + if (mReferencables.searchId(cellRef.mRefID) == -1) { + messages.push_back(std::make_pair(id, " is referencing non existing object " + cellRef.mRefID)); + } else { + // Check if reference charge isn't negative if it's proper type + CSMWorld::RefIdData::LocalIndex localIndex = mDataSet.searchId(cellRef.mRefID); + if (localIndex.second == CSMWorld::UniversalId::Type_Armor || + localIndex.second == CSMWorld::UniversalId::Type_Weapon) { + if (cellRef.mChargeFloat < 0) { + std::string str = " has negative durability "; + str += boost::lexical_cast(cellRef.mChargeFloat); + messages.push_back(std::make_pair(id, id.getId() + str)); + } + } else if (localIndex.second == CSMWorld::UniversalId::Type_Lockpick || + localIndex.second == CSMWorld::UniversalId::Type_Probe || + localIndex.second == CSMWorld::UniversalId::Type_Repair) { + if (cellRef.mChargeInt < -1) { + std::string str = " has invalid charges "; + str += boost::lexical_cast(cellRef.mChargeFloat); + messages.push_back(std::make_pair(id, id.getId() + str)); + } + } + } + } // Check if referenced object is in valid cell if (mCells.searchId(cellRef.mCell) == -1) @@ -72,14 +94,6 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message messages.push_back(std::make_pair(id, id.getId() + str)); } - // Check if charge isn't negative - if (cellRef.mChargeFloat < 0) - { - std::string str = " has negative charges "; - str += boost::lexical_cast(cellRef.mChargeFloat); - messages.push_back(std::make_pair(id, id.getId() + str)); - } - // Check if enchantement points aren't negative or are at full (-1) if (cellRef.mEnchantmentCharge < 0 && cellRef.mEnchantmentCharge != -1) { diff --git a/apps/opencs/model/tools/referencecheck.hpp b/apps/opencs/model/tools/referencecheck.hpp index d1eacb5b5..9cf685b3a 100644 --- a/apps/opencs/model/tools/referencecheck.hpp +++ b/apps/opencs/model/tools/referencecheck.hpp @@ -20,6 +20,7 @@ namespace CSMTools private: const CSMWorld::RefCollection& mReferences; const CSMWorld::RefIdCollection& mReferencables; + const CSMWorld::RefIdData& mDataSet; const CSMWorld::IdCollection& mCells; const CSMWorld::IdCollection& mFactions; }; From 9628415e21aca4cc7649f2f32fab3fb2b52ad209 Mon Sep 17 00:00:00 2001 From: Kamil Bar Date: Fri, 13 Feb 2015 12:16:46 +0100 Subject: [PATCH 453/740] Missing change & changed comments to represent actual code --- apps/opencs/model/tools/referencecheck.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/tools/referencecheck.cpp b/apps/opencs/model/tools/referencecheck.cpp index f1d092be5..d8e056a76 100644 --- a/apps/opencs/model/tools/referencecheck.cpp +++ b/apps/opencs/model/tools/referencecheck.cpp @@ -34,7 +34,7 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message if (mReferencables.searchId(cellRef.mRefID) == -1) { messages.push_back(std::make_pair(id, " is referencing non existing object " + cellRef.mRefID)); } else { - // Check if reference charge isn't negative if it's proper type + // Check if reference charge is valid for it's proper referenced type CSMWorld::RefIdData::LocalIndex localIndex = mDataSet.searchId(cellRef.mRefID); if (localIndex.second == CSMWorld::UniversalId::Type_Armor || localIndex.second == CSMWorld::UniversalId::Type_Weapon) { @@ -48,7 +48,7 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message localIndex.second == CSMWorld::UniversalId::Type_Repair) { if (cellRef.mChargeInt < -1) { std::string str = " has invalid charges "; - str += boost::lexical_cast(cellRef.mChargeFloat); + str += boost::lexical_cast(cellRef.mChargeInt); messages.push_back(std::make_pair(id, id.getId() + str)); } } From 3b7a23aa725935cb69ebd23ded4bfe36510e8333 Mon Sep 17 00:00:00 2001 From: Kamil Bar Date: Fri, 13 Feb 2015 13:11:10 +0100 Subject: [PATCH 454/740] Fixed charge checks for light and other objects, corrected CellRef charge union comments --- apps/opencs/model/tools/referencecheck.cpp | 19 ++++++------------- components/esm/cellref.hpp | 6 ++++-- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/apps/opencs/model/tools/referencecheck.cpp b/apps/opencs/model/tools/referencecheck.cpp index d8e056a76..aae83bd5e 100644 --- a/apps/opencs/model/tools/referencecheck.cpp +++ b/apps/opencs/model/tools/referencecheck.cpp @@ -36,21 +36,14 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message } else { // Check if reference charge is valid for it's proper referenced type CSMWorld::RefIdData::LocalIndex localIndex = mDataSet.searchId(cellRef.mRefID); - if (localIndex.second == CSMWorld::UniversalId::Type_Armor || - localIndex.second == CSMWorld::UniversalId::Type_Weapon) { - if (cellRef.mChargeFloat < 0) { - std::string str = " has negative durability "; + bool isLight = localIndex.second == CSMWorld::UniversalId::Type_Light; + if ((isLight && cellRef.mChargeFloat < -1) || (!isLight && cellRef.mChargeInt < -1)) { + std::string str = " has invalid charge "; + if (localIndex.second == CSMWorld::UniversalId::Type_Light) str += boost::lexical_cast(cellRef.mChargeFloat); - messages.push_back(std::make_pair(id, id.getId() + str)); - } - } else if (localIndex.second == CSMWorld::UniversalId::Type_Lockpick || - localIndex.second == CSMWorld::UniversalId::Type_Probe || - localIndex.second == CSMWorld::UniversalId::Type_Repair) { - if (cellRef.mChargeInt < -1) { - std::string str = " has invalid charges "; + else str += boost::lexical_cast(cellRef.mChargeInt); - messages.push_back(std::make_pair(id, id.getId() + str)); - } + messages.push_back(std::make_pair(id, id.getId() + str)); } } } diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index 56932aa4d..01b6a8473 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -59,10 +59,12 @@ namespace ESM // For weapon or armor, this is the remaining item health. // For tools (lockpicks, probes, repair hammer) it is the remaining uses. + // For lights it is remaining time. + // This could be -1 if the charge was not touched yet (i.e. full). union { - int mChargeInt; - float mChargeFloat; + int mChargeInt; // Used by everything except lights + float mChargeFloat; // Used only by lights }; // Remaining enchantment charge. This could be -1 if the charge was not touched yet (i.e. full). From a139e4efb08c102edf7afeb4d46cdafed8f2d98f Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 13 Feb 2015 16:51:34 +0100 Subject: [PATCH 455/740] Grey out completed quests in journal quests list --- apps/openmw/mwgui/journalviewmodel.cpp | 4 ++-- apps/openmw/mwgui/journalviewmodel.hpp | 4 ++-- apps/openmw/mwgui/journalwindow.cpp | 22 +++++++++++++++++++++- components/widgets/list.cpp | 4 ++-- components/widgets/list.hpp | 2 +- files/mygui/openmw_journal.skin.xml | 6 +++--- 6 files changed, 31 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index 3a86613f6..9a47070c2 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -199,7 +199,7 @@ struct JournalViewModelImpl : JournalViewModel }; - void visitQuestNames (bool active_only, boost::function visitor) const + void visitQuestNames (bool active_only, boost::function visitor) const { MWBase::Journal * journal = MWBase::Environment::get ().getJournal (); @@ -231,7 +231,7 @@ struct JournalViewModelImpl : JournalViewModel if (visitedQuests.find(quest.getName()) != visitedQuests.end()) continue; - visitor (quest.getName()); + visitor (quest.getName(), isFinished); visitedQuests.insert(quest.getName()); } diff --git a/apps/openmw/mwgui/journalviewmodel.hpp b/apps/openmw/mwgui/journalviewmodel.hpp index 5f0189b59..b3c6b0183 100644 --- a/apps/openmw/mwgui/journalviewmodel.hpp +++ b/apps/openmw/mwgui/journalviewmodel.hpp @@ -67,8 +67,8 @@ namespace MWGui /// returns true if their are no journal entries to display virtual bool isEmpty () const = 0; - /// walks the active and optionally completed, quests providing the name - virtual void visitQuestNames (bool active_only, boost::function visitor) const = 0; + /// walks the active and optionally completed, quests providing the name and completed status + virtual void visitQuestNames (bool active_only, boost::function visitor) const = 0; /// walks over the journal entries related to all quests with the given name /// If \a questName is empty, simply visits all journal entries diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index d7e27a277..4cfcc8064 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -428,11 +429,24 @@ namespace AddNamesToList(Gui::MWList* list) : mList(list) {} Gui::MWList* mList; - void operator () (const std::string& name) + void operator () (const std::string& name, bool finished=false) { mList->addItem(name); } }; + struct SetNamesInactive + { + SetNamesInactive(Gui::MWList* list) : mList(list) {} + + Gui::MWList* mList; + void operator () (const std::string& name, bool finished) + { + if (finished) + { + mList->getItemWidget(name)->setStateSelected(true); + } + } + }; void notifyQuests(MyGUI::Widget* _sender) { @@ -453,6 +467,12 @@ namespace mModel->visitQuestNames(!mAllQuests, add); list->adjustSize(); + + if (mAllQuests) + { + SetNamesInactive setInactive(list); + mModel->visitQuestNames(!mAllQuests, setInactive); + } } void notifyShowAll(MyGUI::Widget* _sender) diff --git a/components/widgets/list.cpp b/components/widgets/list.cpp index 28271e87d..f3d3a2c28 100644 --- a/components/widgets/list.cpp +++ b/components/widgets/list.cpp @@ -152,9 +152,9 @@ namespace Gui eventWidgetSelected(_sender); } - MyGUI::Widget* MWList::getItemWidget(const std::string& name) + MyGUI::Button *MWList::getItemWidget(const std::string& name) { - return mScrollView->findWidget (getName() + "_item_" + name); + return mScrollView->findWidget (getName() + "_item_" + name)->castType(); } } diff --git a/components/widgets/list.hpp b/components/widgets/list.hpp index 093cd8c18..72c8a733c 100644 --- a/components/widgets/list.hpp +++ b/components/widgets/list.hpp @@ -43,7 +43,7 @@ namespace Gui std::string getItemNameAt(unsigned int at); ///< \attention if there are separators, this method will return "" at the place where the separator is void clear(); - MyGUI::Widget* getItemWidget(const std::string& name); + MyGUI::Button* getItemWidget(const std::string& name); ///< get widget for an item name, useful to set up tooltip virtual void setPropertyOverride(const std::string& _key, const std::string& _value); diff --git a/files/mygui/openmw_journal.skin.xml b/files/mygui/openmw_journal.skin.xml index 942c9a4d4..42be2bb62 100644 --- a/files/mygui/openmw_journal.skin.xml +++ b/files/mygui/openmw_journal.skin.xml @@ -28,9 +28,9 @@ - - - + + +
From 8b417c06db7fcfd0c44e88a07b5e4f2b2ea4c868 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 13 Feb 2015 17:26:33 +0100 Subject: [PATCH 456/740] Fix missing clear in ESM::Spell::load (Fixes #2368) --- components/esm/loadspel.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/esm/loadspel.cpp b/components/esm/loadspel.cpp index cd630d6ab..96c048e0a 100644 --- a/components/esm/loadspel.cpp +++ b/components/esm/loadspel.cpp @@ -10,6 +10,7 @@ namespace ESM void Spell::load(ESMReader &esm) { + mEffects.mList.clear(); bool hasData = false; while (esm.hasMoreSubs()) { From 96a295c44f33926756d6bff35cc7982919561cc6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 13 Feb 2015 17:37:56 +0100 Subject: [PATCH 457/740] Fix for deleting all items in a levelled list --- components/esm/loadlevlist.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/esm/loadlevlist.cpp b/components/esm/loadlevlist.cpp index 6080d1e1a..ca5c5d74d 100644 --- a/components/esm/loadlevlist.cpp +++ b/components/esm/loadlevlist.cpp @@ -21,6 +21,7 @@ namespace ESM else { // Original engine ignores rest of the record, even if there are items following + mList.clear(); esm.skipRecord(); return; } From 74232b90fcf928ad6f07a92886245bf6937f07b2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 13 Feb 2015 18:26:36 +0100 Subject: [PATCH 458/740] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 59aa42721..540c0ede5 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -78,6 +78,7 @@ Programmers naclander Narmo Nathan Jeffords (blunted2night) + NeveHanter Nikolay Kasyanov (corristo) nobrakal Nolan Poe (nopoe) From a1ee26922e2aca1c975e9095de93f56a10d9e6ce Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Feb 2015 12:00:16 +0100 Subject: [PATCH 459/740] ESSImport: note location of corpse clear countdown --- apps/essimporter/importacdt.hpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/essimporter/importacdt.hpp b/apps/essimporter/importacdt.hpp index 47055092d..eacb2edf1 100644 --- a/apps/essimporter/importacdt.hpp +++ b/apps/essimporter/importacdt.hpp @@ -43,13 +43,17 @@ namespace ESSImport float mMagicEffects[27]; // Effect attributes: https://wiki.openmw.org/index.php?title=Research:Magic#Effect_attributes unsigned char mUnknown4[4]; unsigned int mGoldPool; - unsigned char mUnknown5[4]; + unsigned char mCountDown; // seen the same value as in ACSC.mCorpseClearCountdown, maybe + // this one is for respawning? + unsigned char mUnknown5[3]; }; struct ACSC { unsigned char mUnknown1[17]; unsigned char mFlags; // ACSCFlags - unsigned char mUnknown2[94]; + unsigned char mUnknown2[22]; + unsigned char mCorpseClearCountdown; // hours? + unsigned char mUnknown3[71]; }; #pragma pack(pop) From 0e88fb3dca206ce61d938db7d70f96bfb26b1a2d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Feb 2015 12:25:52 +0100 Subject: [PATCH 460/740] ESSImport: read AiPackages --- apps/essimporter/importcrec.cpp | 4 ++-- apps/essimporter/importcrec.hpp | 2 ++ apps/essimporter/importnpcc.cpp | 3 +-- apps/essimporter/importnpcc.hpp | 1 + 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/essimporter/importcrec.cpp b/apps/essimporter/importcrec.cpp index 7a8a3eb00..64879f2af 100644 --- a/apps/essimporter/importcrec.cpp +++ b/apps/essimporter/importcrec.cpp @@ -14,10 +14,10 @@ namespace ESSImport float scale; esm.getHNOT(scale, "XSCL"); - // FIXME: use AiPackageList, need to fix getSubName() + while (esm.isNextSub("AI_W") || esm.isNextSub("AI_E") || esm.isNextSub("AI_T") || esm.isNextSub("AI_F") || esm.isNextSub("AI_A")) - esm.skipHSub(); + mAiPackages.add(esm); mInventory.load(esm); } diff --git a/apps/essimporter/importcrec.hpp b/apps/essimporter/importcrec.hpp index 16b752807..5110fbc68 100644 --- a/apps/essimporter/importcrec.hpp +++ b/apps/essimporter/importcrec.hpp @@ -2,6 +2,7 @@ #define OPENMW_ESSIMPORT_CREC_H #include "importinventory.hpp" +#include namespace ESM { @@ -17,6 +18,7 @@ namespace ESSImport int mIndex; Inventory mInventory; + ESM::AIPackageList mAiPackages; void load(ESM::ESMReader& esm); }; diff --git a/apps/essimporter/importnpcc.cpp b/apps/essimporter/importnpcc.cpp index 547b01441..3cbd749ce 100644 --- a/apps/essimporter/importnpcc.cpp +++ b/apps/essimporter/importnpcc.cpp @@ -9,10 +9,9 @@ namespace ESSImport { esm.getHNT(mNPDT, "NPDT"); - // FIXME: use AiPackageList, need to fix getSubName() while (esm.isNextSub("AI_W") || esm.isNextSub("AI_E") || esm.isNextSub("AI_T") || esm.isNextSub("AI_F") || esm.isNextSub("AI_A")) - esm.skipHSub(); + mAiPackages.add(esm); mInventory.load(esm); } diff --git a/apps/essimporter/importnpcc.hpp b/apps/essimporter/importnpcc.hpp index c69fa3e03..a23ab1e50 100644 --- a/apps/essimporter/importnpcc.hpp +++ b/apps/essimporter/importnpcc.hpp @@ -27,6 +27,7 @@ namespace ESSImport } mNPDT; Inventory mInventory; + ESM::AIPackageList mAiPackages; void load(ESM::ESMReader &esm); }; From 93ffdb427c3d4faafb59f0317a112baba680fada Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Feb 2015 15:53:01 +0100 Subject: [PATCH 461/740] Small tweak to ripples --- apps/openmw/mwrender/ripplesimulation.cpp | 1 - files/materials/ripples.particle | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index 84794162f..dcafcb79f 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -113,7 +113,6 @@ void RippleSimulation::update(float dt, Ogre::Vector2 position) position.z = 0; // Z is set by the Scene Node rotSpeed = mRippleRotSpeed; rotation = Ogre::Radian(Ogre::Math::RangeRandom(-Ogre::Math::PI, Ogre::Math::PI)); - created->setDimensions(50,50); } } diff --git a/files/materials/ripples.particle b/files/materials/ripples.particle index e8402b691..58045f6d7 100644 --- a/files/materials/ripples.particle +++ b/files/materials/ripples.particle @@ -1,8 +1,8 @@ particle_system openmw/Ripples { material openmw/Ripple - particle_width 50 - particle_height 50 + particle_width 30 + particle_height 30 // To make the particles move with the scene node when the waterlevel changes local_space true quota 300 @@ -17,7 +17,7 @@ particle_system openmw/Ripples affector Scaler { - rate 100 + rate 120 } affector Rotator From 37a85e31d6681141e341bb62fc072328c35e1a2c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Feb 2015 16:51:47 +0100 Subject: [PATCH 462/740] Ripples fix --- apps/openmw/mwrender/ripplesimulation.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index dcafcb79f..bb1bccc0a 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -113,6 +113,7 @@ void RippleSimulation::update(float dt, Ogre::Vector2 position) position.z = 0; // Z is set by the Scene Node rotSpeed = mRippleRotSpeed; rotation = Ogre::Radian(Ogre::Math::RangeRandom(-Ogre::Math::PI, Ogre::Math::PI)); + created->setDimensions(mParticleSystem->getDefaultWidth(), mParticleSystem->getDefaultHeight()); } } From 81925645a34b4591d6be7ccf0b8ce13d6efa536b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Feb 2015 16:51:54 +0100 Subject: [PATCH 463/740] Unreachable enemies combat AI fix (Fixes #2271) --- apps/openmw/mwmechanics/aicombat.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index f2b125add..fd4fd293d 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -207,16 +207,6 @@ namespace MWMechanics const MWWorld::Class& actorClass = actor.getClass(); MWBase::World* world = MWBase::Environment::get().getWorld(); - // can't fight if attacker can't go where target is. E.g. A fish can't attack person on land. - if (!actorClass.isNpc() && !MWMechanics::isEnvironmentCompatible(actor, target)) - { - actorClass.getCreatureStats(actor).setAttackingOrSpell(false); - return true; - } - - - - //Update every frame bool& combatMove = storage.mCombatMove; @@ -476,6 +466,19 @@ namespace MWMechanics // for distant combat we should know if target is in LOS even if distToTarget < rangeAttack bool inLOS = distantCombat ? world->getLOS(actor, target) : true; + // can't fight if attacker can't go where target is. E.g. A fish can't attack person on land. + if (distToTarget >= rangeAttack + && !actorClass.isNpc() && !MWMechanics::isEnvironmentCompatible(actor, target)) + { + // TODO: start fleeing? + movement.mPosition[0] = 0; + movement.mPosition[1] = 0; + movement.mPosition[2] = 0; + readyToAttack = false; + actorClass.getCreatureStats(actor).setAttackingOrSpell(false); + return false; + } + // (within attack dist) || (not quite attack dist while following) if(inLOS && (distToTarget < rangeAttack || (distToTarget <= rangeFollow && followTarget && !isStuck))) { From 5ef78903dc28554ad58784ac13f9aba1a135c5ad Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Sat, 14 Feb 2015 15:43:09 -0600 Subject: [PATCH 464/740] Teleportation: Support markers in Mournhold. OMW Bug #1533 Note: the 'stolen goods' search is not yet correct for Mournhald. --- apps/openmw/mwworld/worldimp.cpp | 104 +++++++++++++++++++++++++------ apps/openmw/mwworld/worldimp.hpp | 2 + 2 files changed, 87 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 23cef1596..fda73238a 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2830,33 +2830,99 @@ namespace MWWorld return false; } - void World::teleportToClosestMarker (const MWWorld::Ptr& ptr, - const std::string& id) + MWWorld::Ptr World::getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id ) { - Ogre::Vector3 worldPos; - if (!findInteriorPositionInWorldSpace(ptr.getCell(), worldPos)) - worldPos = mPlayer->getLastKnownExteriorPosition(); + // Search for a 'nearest' marker, counting each cell between the starting + // cell and the exterior as a distance of 1. If an exterior is found, jump + // to the nearest exterior marker, without further interior searching. + std::set< std::string >checkedCells; + std::set< std::string >currentCells; + std::set< std::string >nextCells; + nextCells.insert( ptr.getCell()->getCell()->mName ); + while ( !nextCells.empty() ) { + currentCells = nextCells; + nextCells.clear(); + for( std::set< std::string >::const_iterator i = currentCells.begin(); i != currentCells.end(); ++i ) { + MWWorld::CellStore *next = getInterior( *i ); + checkedCells.insert( *i ); + if ( !next ) continue; - MWWorld::Ptr closestMarker; - float closestDistance = FLT_MAX; + MWWorld::CellRefList& statics = next->get(); + CellRefList::List& staticList = statics.mList; + for (CellRefList::List::iterator it = staticList.begin(); it != staticList.end(); ++it) + { + MWWorld::LiveCellRef& ref = *it; + if ( id == ref.mRef.getRefId() ) { + return MWWorld::Ptr( &ref, next ); + } + } - std::vector markers; - mCells.getExteriorPtrs(id, markers); + MWWorld::CellRefList& doors = next->get(); + CellRefList::List& doorList = doors.mList; - for (std::vector::iterator it = markers.begin(); it != markers.end(); ++it) - { - ESM::Position pos = it->getRefData().getPosition(); - Ogre::Vector3 markerPos = Ogre::Vector3(pos.pos); - float distance = worldPos.squaredDistance(markerPos); - if (distance < closestDistance) - { - closestDistance = distance; - closestMarker = *it; + // Check if any door in the cell leads to an exterior directly + for (CellRefList::List::iterator it = doorList.begin(); it != doorList.end(); ++it) + { + MWWorld::LiveCellRef& ref = *it; + + if ( id == ref.mRef.getRefId() ) { + return MWWorld::Ptr( &ref, next ); + } + + if (!ref.mRef.getTeleport()) continue; + + if (ref.mRef.getDestCell().empty()) + { + Ogre::Vector3 worldPos = Ogre::Vector3(ref.mRef.getDoorDest().pos); + float closestDistance = FLT_MAX; + + MWWorld::Ptr closestMarker; + std::vector markers; + mCells.getExteriorPtrs(id, markers); + for (std::vector::iterator it2 = markers.begin(); it2 != markers.end(); ++it2) + { + ESM::Position pos = it2->getRefData().getPosition(); + Ogre::Vector3 markerPos = Ogre::Vector3(pos.pos); + float distance = worldPos.squaredDistance(markerPos); + if (distance < closestDistance) + { + closestDistance = distance; + closestMarker = *it2; + } + + } + + return closestMarker; + } + else + { + std::string dest = ref.mRef.getDestCell(); + if ( !checkedCells.count(dest) && !currentCells.count(dest) ) + nextCells.insert(dest); + } + } } + } + return MWWorld::Ptr(); + } + + void World::teleportToClosestMarker (const MWWorld::Ptr& ptr, + const std::string& id) + { + MWWorld::Ptr closestMarker = getClosestMarker( ptr, id ); + + if ( closestMarker.isEmpty() ) + { + std::cerr << "Failed to teleport: no closest marker found" << std::endl; + return; } - MWWorld::ActionTeleport action("", closestMarker.getRefData().getPosition()); + std::string cellName; + if ( !closestMarker.mCell->isExterior() ) + cellName = closestMarker.mCell->getCell()->mName; + + MWWorld::ActionTeleport action(cellName, closestMarker.getRefData().getPosition()); action.execute(ptr); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 9980f6f90..7a3505fd4 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -151,6 +151,8 @@ namespace MWWorld float feetToGameUnits(float feet); + MWWorld::Ptr getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id ); + public: World (OEngine::Render::OgreRenderer& renderer, From 6d1aec6970ef753e08e687c06eb80cdfd403cc9a Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Sat, 14 Feb 2015 16:09:17 -0600 Subject: [PATCH 465/740] Confiscate stolen goods: Support Mournhold prisons. OMW Bug #1533 --- apps/openmw/mwworld/worldimp.cpp | 37 ++++++++++++++++---------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index fda73238a..54385cf83 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3071,28 +3071,29 @@ namespace MWWorld void World::confiscateStolenItems(const Ptr &ptr) { - Ogre::Vector3 playerPos; - if (!findInteriorPositionInWorldSpace(ptr.getCell(), playerPos)) - playerPos = mPlayer->getLastKnownExteriorPosition(); + MWWorld::Ptr prisonMarker = getClosestMarker( ptr, "prisonmarker" ); + std::string prisonName = prisonMarker.mRef->mRef.getDestCell(); + if ( prisonName.empty() ) + { + std::cerr << "Failed to confiscate items: prison marker not linked to prison interior" << std::endl; + return; + } + MWWorld::CellStore *prison = getInterior( prisonName ); + if ( !prison ) + { + std::cerr << "Failed to confiscate items: failed to load cell " << prisonName << std::endl; + return; + } MWWorld::Ptr closestChest; - float closestDistance = FLT_MAX; - - //Find closest stolen_goods chest - std::vector chests; - mCells.getInteriorPtrs("stolen_goods", chests); - Ogre::Vector3 chestPos; - for (std::vector::iterator it = chests.begin(); it != chests.end(); ++it) + MWWorld::CellRefList& containers = prison->get(); + CellRefList::List& refList = containers.mList; + for (CellRefList::List::iterator it = refList.begin(); it != refList.end(); ++it) { - if (!findInteriorPositionInWorldSpace(it->getCell(), chestPos)) - continue; - - float distance = playerPos.squaredDistance(chestPos); - if (distance < closestDistance) - { - closestDistance = distance; - closestChest = *it; + MWWorld::LiveCellRef& ref = *it; + if ( ref.mRef.getRefId() == "stolen_goods" ) { + closestChest = MWWorld::Ptr( &ref, prison ); } } From a61019dfa804fc2d1a6d54ec7e6600cacda22116 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Sun, 15 Feb 2015 04:47:25 +0100 Subject: [PATCH 466/740] Update referencecheck.cpp MSVC does not allow for the usage of 'and' or 'or' literals --- apps/opencs/model/tools/referencecheck.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/tools/referencecheck.cpp b/apps/opencs/model/tools/referencecheck.cpp index aae83bd5e..0c1d7d38f 100644 --- a/apps/opencs/model/tools/referencecheck.cpp +++ b/apps/opencs/model/tools/referencecheck.cpp @@ -53,7 +53,7 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message messages.push_back(std::make_pair(id, " is referencing object from non existing cell " + cellRef.mCell)); // If object have owner, check if that owner reference is valid - if (!cellRef.mOwner.empty() and mReferencables.searchId(cellRef.mOwner) == -1) + if (!cellRef.mOwner.empty() && mReferencables.searchId(cellRef.mOwner) == -1) messages.push_back(std::make_pair(id, " has non existing owner " + cellRef.mOwner)); // If object have creature soul trapped, check if that creature reference is valid @@ -107,4 +107,4 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message int CSMTools::ReferenceCheckStage::setup() { return mReferences.getSize(); -} \ No newline at end of file +} From f1fd27aeaf2585348b46b526e0267fb36443e8f3 Mon Sep 17 00:00:00 2001 From: slothlife Date: Sat, 14 Feb 2015 23:34:43 -0600 Subject: [PATCH 467/740] Select CMAKE_BUILD_TYPE if not specified A suggestion by kcat to ensure CMake selects a reasonable default for the build type if users don't set it themselves. --- CMakeLists.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 37f8552cd..c8682dace 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,12 @@ project(OpenMW) +# If the user doesn't supply a CMAKE_BUILD_TYPE via command line, choose one for them. +IF(NOT CMAKE_BUILD_TYPE) + SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING + "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." + FORCE) +ENDIF() + if (APPLE) set(APP_BUNDLE_NAME "${CMAKE_PROJECT_NAME}.app") From 0e955124003b29f1fc201cc946bdf4763d13cb9f Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Sun, 15 Feb 2015 16:02:49 +0200 Subject: [PATCH 468/740] CI: fix `make package` condition by adding missing spaces --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 042d4b8f1..1be8aa59c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,7 +31,7 @@ before_script: script: - cd ./build - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then make -j4; fi - - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && ["${TRAVIS_OS_NAME}" = "osx"]; then make package; fi + - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "osx" ]; then make package; fi after_script: - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi notifications: From a9b74671a6c7a8aea6f575313e9696886c2b3574 Mon Sep 17 00:00:00 2001 From: slothlife Date: Sun, 15 Feb 2015 20:10:21 -0600 Subject: [PATCH 469/740] Fix various MSVC warnings --- CMakeLists.txt | 13 ++++++++++--- apps/openmw/mwmechanics/magiceffects.hpp | 2 ++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a117d42d..0c3d7c378 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -672,6 +672,7 @@ if (WIN32) 4193 # #pragma warning(pop) : no matching '#pragma warning(push)' 4251 # class 'XXXX' needs to have dll-interface to be used by clients of class 'YYYY' 4275 # non dll-interface struct 'XXXX' used as base for dll-interface class 'YYYY' + 4315 # undocumented, 'this' pointer for member might not be aligned (OgreMemoryStlAllocator.h) # caused by boost 4191 # 'type cast' : unsafe conversion (1.56, thread_primitives.hpp, normally off) @@ -679,6 +680,7 @@ if (WIN32) # OpenMW specific warnings 4099 # Type mismatch, declared class or struct is defined with other type 4100 # Unreferenced formal parameter (-Wunused-parameter) + 4101 # Unreferenced local variable (-Wunused-variable) 4127 # Conditional expression is constant 4242 # Storing value in a variable of a smaller type, possible loss of data 4244 # Storing value of one type in variable of another (size_t in int, for example) @@ -700,14 +702,16 @@ if (WIN32) # boost::wave has a few issues with signed / unsigned conversions, so we suppress those here set(SHINY_WARNINGS "${WARNINGS} /wd4245") set_target_properties(shiny PROPERTIES COMPILE_FLAGS "${SHINY_WARNINGS} ${MT_BUILD}") - # there's an unreferenced local variable in the ogre platform, suppress it - set(SHINY_OGRE_WARNINGS "${WARNINGS} /wd4101") - set_target_properties(shiny.OgrePlatform PROPERTIES COMPILE_FLAGS "${SHINY_OGRE_WARNINGS} ${MT_BUILD}") + set_target_properties(shiny.OgrePlatform PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") set_target_properties(sdl4ogre PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") # oics uses tinyxml, which has an initialized but unused variable set(OICS_WARNINGS "${WARNINGS} /wd4189") set_target_properties(oics PROPERTIES COMPILE_FLAGS "${OICS_WARNINGS} ${MT_BUILD}") set_target_properties(components PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + set_target_properties(ogre-ffmpeg-videoplayer PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + if (BUILD_MYGUI_PLUGIN) + set_target_properties(Plugin_MyGUI_OpenMW_Resources PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + endif (BUILD_MYGUI_PLUGIN) if (BUILD_LAUNCHER) set_target_properties(openmw-launcher PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") endif (BUILD_LAUNCHER) @@ -726,6 +730,9 @@ if (WIN32) set(OPENCS_WARNINGS "${WARNINGS} ${MT_BUILD} /wd4435") set_target_properties(openmw-cs PROPERTIES COMPILE_FLAGS ${OPENCS_WARNINGS}) endif (BUILD_OPENCS) + if (BUILD_ESSIMPORTER) + set_target_properties(openmw-essimporter PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + endif (BUILD_ESSIMPORTER) if (BUILD_MWINIIMPORTER) set_target_properties(openmw-iniimporter PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") endif (BUILD_MWINIIMPORTER) diff --git a/apps/openmw/mwmechanics/magiceffects.hpp b/apps/openmw/mwmechanics/magiceffects.hpp index c384d0857..86f5a1804 100644 --- a/apps/openmw/mwmechanics/magiceffects.hpp +++ b/apps/openmw/mwmechanics/magiceffects.hpp @@ -72,6 +72,8 @@ namespace MWMechanics // Used by effect management classes (ActiveSpells, InventoryStore, Spells) to list active effect sources for GUI display struct EffectSourceVisitor { + virtual ~EffectSourceVisitor() { } + virtual void visit (MWMechanics::EffectKey key, const std::string& sourceName, const std::string& sourceId, int casterActorId, float magnitude, float remainingTime = -1, float totalTime = -1) = 0; From e5c1c316480c3d5f7daa1ca3010004a7a21a37ef Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 16 Feb 2015 14:27:25 +1100 Subject: [PATCH 470/740] Ignore case when detecting legacy extensions (.esm or .exp). Should resolve bug #2227. --- apps/opencs/view/doc/adjusterwidget.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/doc/adjusterwidget.cpp b/apps/opencs/view/doc/adjusterwidget.cpp index 09e58690f..6571ad7c8 100644 --- a/apps/opencs/view/doc/adjusterwidget.cpp +++ b/apps/opencs/view/doc/adjusterwidget.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -72,8 +73,11 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon) { boost::filesystem::path path (name.toUtf8().data()); - bool isLegacyPath = (path.extension() == ".esm" || - path.extension() == ".esp"); + std::string extension = path.extension().string(); + boost::algorithm::to_lower(extension); + + bool isLegacyPath = (extension == ".esm" || + extension == ".esp"); bool isFilePathChanged = (path.parent_path().string() != mLocalData.string()); From efdee1947765bb796bda5182e6cd193c03d90377 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 16 Feb 2015 16:41:53 +1100 Subject: [PATCH 471/740] Suppress warning about the lack of virtual destructor. --- apps/openmw/mwmechanics/summoning.cpp | 4 ++++ apps/openmw/mwmechanics/summoning.hpp | 1 + 2 files changed, 5 insertions(+) diff --git a/apps/openmw/mwmechanics/summoning.cpp b/apps/openmw/mwmechanics/summoning.cpp index ec9bd0ea0..668031141 100644 --- a/apps/openmw/mwmechanics/summoning.cpp +++ b/apps/openmw/mwmechanics/summoning.cpp @@ -51,6 +51,10 @@ namespace MWMechanics } + UpdateSummonedCreatures::~UpdateSummonedCreatures() + { + } + void UpdateSummonedCreatures::visit(EffectKey key, const std::string &sourceName, const std::string &sourceId, int casterActorId, float magnitude, float remainingTime, float totalTime) { if (isSummoningEffect(key.mId) && magnitude > 0) diff --git a/apps/openmw/mwmechanics/summoning.hpp b/apps/openmw/mwmechanics/summoning.hpp index b8fe37783..8e418cdeb 100644 --- a/apps/openmw/mwmechanics/summoning.hpp +++ b/apps/openmw/mwmechanics/summoning.hpp @@ -14,6 +14,7 @@ namespace MWMechanics struct UpdateSummonedCreatures : public EffectSourceVisitor { UpdateSummonedCreatures(const MWWorld::Ptr& actor); + virtual ~UpdateSummonedCreatures(); virtual void visit (MWMechanics::EffectKey key, const std::string& sourceName, const std::string& sourceId, int casterActorId, From 8d7de7d1ece744356fee88f7e8613089725fcd67 Mon Sep 17 00:00:00 2001 From: dteviot Date: Tue, 17 Feb 2015 22:14:25 +1300 Subject: [PATCH 472/740] Telekinesis allows safe opening of traps (Fixes #1916) When trap activated at beyond normal activation distance, assume telekinesis used and detonate trap at trapped object's location. Also some minor code refactoring of spellcasting. 1. Corrected parameter passed to explodeSpell(). 2. For loop now correctly does an early exit. 3. Removed duplicated tests. --- apps/openmw/mwbase/world.hpp | 4 +++- apps/openmw/mwmechanics/spellcasting.cpp | 16 ++++++------- apps/openmw/mwworld/actiontrap.cpp | 29 +++++++++++++++++++++--- apps/openmw/mwworld/worldimp.cpp | 4 ++-- apps/openmw/mwworld/worldimp.hpp | 2 +- 5 files changed, 39 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index f58ef0809..f71975433 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -269,6 +269,8 @@ namespace MWBase virtual MWWorld::Ptr getFacedObject() = 0; ///< Return pointer to the object the player is looking at, if it is within activation range + virtual float getMaxActivationDistance() = 0; + /// Returns a pointer to the object the provided object would hit (if within the /// specified distance), and the point where the hit occurs. This will attempt to /// use the "Head" node, or alternatively the "Bip01 Head" node as a basis. @@ -548,7 +550,7 @@ namespace MWBase virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const Ogre::Vector3& worldPos) = 0; virtual void explodeSpell (const Ogre::Vector3& origin, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, int rangeType, const std::string& id, const std::string& sourceName) = 0; + const MWWorld::Ptr& caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName) = 0; virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) = 0; diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 49887e560..4ce3fcaf5 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -309,9 +309,11 @@ namespace MWMechanics for (std::vector::const_iterator iter (effects.mList.begin()); iter!=effects.mList.end(); ++iter) { - if (iter->mRange != range) - continue; - found = true; + if (iter->mRange == range) + { + found = true; + break; + } } if (!found) return; @@ -766,8 +768,7 @@ namespace MWMechanics if (!mTarget.isEmpty()) { - if (!mTarget.getClass().isActor() || !mTarget.getClass().getCreatureStats(mTarget).isDead()) - inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Touch); + inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Touch); } std::string projectileModel; @@ -851,10 +852,7 @@ namespace MWMechanics if (!mTarget.isEmpty()) { - if (!mTarget.getClass().isActor() || !mTarget.getClass().getCreatureStats(mTarget).isDead()) - { - inflict(mTarget, mCaster, spell->mEffects, ESM::RT_Touch); - } + inflict(mTarget, mCaster, spell->mEffects, ESM::RT_Touch); } diff --git a/apps/openmw/mwworld/actiontrap.cpp b/apps/openmw/mwworld/actiontrap.cpp index 1472afc08..d153b7e61 100644 --- a/apps/openmw/mwworld/actiontrap.cpp +++ b/apps/openmw/mwworld/actiontrap.cpp @@ -1,16 +1,39 @@ #include "actiontrap.hpp" #include "../mwmechanics/spellcasting.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" namespace MWWorld { void ActionTrap::executeImp(const Ptr &actor) { - MWMechanics::CastSpell cast(mTrapSource, actor); - cast.mHitPosition = Ogre::Vector3(actor.getRefData().getPosition().pos); - cast.cast(mSpellId); + Ogre::Vector3 actorPosition(actor.getRefData().getPosition().pos); + Ogre::Vector3 trapPosition(mTrapSource.getRefData().getPosition().pos); + float activationDistance = MWBase::Environment::get().getWorld()->getMaxActivationDistance(); + // GUI calcs if object in activation distance include object and player geometry + const float fudgeFactor = 1.25f; + + // Hack: if actor is beyond activation range, then assume actor is using telekinesis + // to open door/container. + // Note, can't just detonate the trap at the trapped object's location and use the blast + // radius, because for most trap spells this is 1 foot, much less than the activation distance. + if (trapPosition.distance(actorPosition) < (activationDistance * fudgeFactor)) + { + // assume actor touched trap + MWMechanics::CastSpell cast(mTrapSource, actor); + cast.mHitPosition = actorPosition; + cast.cast(mSpellId); + } + else + { + // assume telekinesis used + MWMechanics::CastSpell cast(mTrapSource, mTrapSource); + cast.mHitPosition = trapPosition; + cast.cast(mSpellId); + } mTrapSource.getCellRef().setTrap(""); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 8bcfcb421..333f172b9 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3128,7 +3128,7 @@ namespace MWWorld mRendering->spawnEffect(model, textureOverride, worldPos); } - void World::explodeSpell(const Vector3 &origin, const ESM::EffectList &effects, const Ptr &caster, int rangeType, + void World::explodeSpell(const Vector3 &origin, const ESM::EffectList &effects, const Ptr &caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName) { std::map > toApply; @@ -3187,7 +3187,7 @@ namespace MWWorld cast.mStack = false; ESM::EffectList effects; effects.mList = apply->second; - cast.inflict(apply->first, caster, effects, (ESM::RangeType)rangeType, false, true); + cast.inflict(apply->first, caster, effects, rangeType, false, true); } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 9834015ac..84da984f8 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -627,7 +627,7 @@ namespace MWWorld virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const Ogre::Vector3& worldPos); virtual void explodeSpell (const Ogre::Vector3& origin, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, int rangeType, const std::string& id, const std::string& sourceName); + const MWWorld::Ptr& caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName); virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor); From 6e2d6a028200df830b2ca90c95987f873e7c5199 Mon Sep 17 00:00:00 2001 From: dteviot Date: Tue, 17 Feb 2015 22:51:30 +1300 Subject: [PATCH 473/740] Minor correction, MWWorld::getMaxActivationDistance() is now public. --- apps/openmw/mwworld/worldimp.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 84da984f8..1636980cb 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -114,7 +114,6 @@ namespace MWWorld void performUpdateSceneQueries (); void getFacedHandle(std::string& facedHandle, float maxDistance, bool ignorePlayer=true); - float getMaxActivationDistance (); float getNpcActivationDistance (); float getObjectActivationDistance (); @@ -361,6 +360,8 @@ namespace MWWorld virtual MWWorld::Ptr safePlaceObject(const MWWorld::Ptr& ptr, MWWorld::CellStore* cell, ESM::Position pos); ///< place an object in a "safe" location (ie not in the void, etc). Makes a copy of the Ptr. + virtual float getMaxActivationDistance(); + virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false) const; ///< Convert cell numbers to position. From 6d62aa754445931fad3d7e5bc7389f8b6e6ccc36 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 18 Feb 2015 19:06:36 +0100 Subject: [PATCH 474/740] Don't prompt for spell deletion when using cycling keys (Fixes #2382) --- apps/openmw/mwgui/spellwindow.cpp | 71 +++++++++++++++++-------------- apps/openmw/mwgui/spellwindow.hpp | 1 + 2 files changed, 39 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 69365c108..cc032691e 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -102,52 +102,53 @@ namespace MWGui updateSpells(); } - void SpellWindow::onModelIndexSelected(SpellModel::ModelIndex index) + void SpellWindow::askDeleteSpell(const std::string &spellId) { - const Spell& spell = mSpellView->getModel()->getItem(index); - if (spell.mType == Spell::Type_EnchantedItem) + // delete spell, if allowed + const ESM::Spell* spell = + MWBase::Environment::get().getWorld()->getStore().get().find(spellId); + + if (spell->mData.mFlags & ESM::Spell::F_Always + || spell->mData.mType == ESM::Spell::ST_Power) { - onEnchantedItemSelected(spell.mItem, spell.mActive); + MWBase::Environment::get().getWindowManager()->messageBox("#{sDeleteSpellError}"); } else { - onSpellSelected(spell.mId); + // ask for confirmation + mSpellToDelete = spellId; + ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); + std::string question = MWBase::Environment::get().getWindowManager()->getGameSettingString("sQuestionDeleteSpell", "Delete %s?"); + question = boost::str(boost::format(question) % spell->mName); + dialog->open(question); + dialog->eventOkClicked.clear(); + dialog->eventOkClicked += MyGUI::newDelegate(this, &SpellWindow::onDeleteSpellAccept); + dialog->eventCancelClicked.clear(); } } - void SpellWindow::onSpellSelected(const std::string& spellId) + void SpellWindow::onModelIndexSelected(SpellModel::ModelIndex index) { - if (MyGUI::InputManager::getInstance().isShiftPressed()) + const Spell& spell = mSpellView->getModel()->getItem(index); + if (spell.mType == Spell::Type_EnchantedItem) { - // delete spell, if allowed - const ESM::Spell* spell = - MWBase::Environment::get().getWorld()->getStore().get().find(spellId); - - if (spell->mData.mFlags & ESM::Spell::F_Always - || spell->mData.mType == ESM::Spell::ST_Power) - { - MWBase::Environment::get().getWindowManager()->messageBox("#{sDeleteSpellError}"); - } - else - { - // ask for confirmation - mSpellToDelete = spellId; - ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); - std::string question = MWBase::Environment::get().getWindowManager()->getGameSettingString("sQuestionDeleteSpell", "Delete %s?"); - question = boost::str(boost::format(question) % spell->mName); - dialog->open(question); - dialog->eventOkClicked.clear(); - dialog->eventOkClicked += MyGUI::newDelegate(this, &SpellWindow::onDeleteSpellAccept); - dialog->eventCancelClicked.clear(); - } + onEnchantedItemSelected(spell.mItem, spell.mActive); } else { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); - store.setSelectedEnchantItem(store.end()); - MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); + if (MyGUI::InputManager::getInstance().isShiftPressed()) + askDeleteSpell(spell.mId); + else + onSpellSelected(spell.mId); } + } + + void SpellWindow::onSpellSelected(const std::string& spellId) + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); + store.setSelectedEnchantItem(store.end()); + MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); updateSpells(); } @@ -184,6 +185,10 @@ namespace MWGui return; selected = (selected + itemcount) % itemcount; - onModelIndexSelected(selected); + const Spell& spell = mSpellView->getModel()->getItem(selected); + if (spell.mType == Spell::Type_EnchantedItem) + onEnchantedItemSelected(spell.mItem, spell.mActive); + else + onSpellSelected(spell.mId); } } diff --git a/apps/openmw/mwgui/spellwindow.hpp b/apps/openmw/mwgui/spellwindow.hpp index 650218d30..8b5474f58 100644 --- a/apps/openmw/mwgui/spellwindow.hpp +++ b/apps/openmw/mwgui/spellwindow.hpp @@ -33,6 +33,7 @@ namespace MWGui void onSpellSelected(const std::string& spellId); void onModelIndexSelected(SpellModel::ModelIndex index); void onDeleteSpellAccept(); + void askDeleteSpell(const std::string& spellId); virtual void onPinToggled(); virtual void onTitleDoubleClicked(); From a5847afdac83fb28e0c22fa3388ca49b077adaf9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Feb 2015 00:00:13 +0100 Subject: [PATCH 475/740] Fix ignored clicks on HUD mini-map (Fixes #2388) --- apps/openmw/mwgui/hud.cpp | 10 ++++++++++ apps/openmw/mwgui/hud.hpp | 4 ++++ files/mygui/openmw_hud.layout | 3 ++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 1f7ead6f5..a4e67e9b1 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -671,4 +671,14 @@ namespace MWGui mEnemyHealthTimer = -1; } + void HUD::customMarkerCreated(MyGUI::Widget *marker) + { + marker->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMapClicked); + } + + void HUD::doorMarkerCreated(MyGUI::Widget *marker) + { + marker->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMapClicked); + } + } diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 41a535a08..263c08774 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -119,6 +119,10 @@ namespace MWGui void onMagicClicked(MyGUI::Widget* _sender); void onMapClicked(MyGUI::Widget* _sender); + // LocalMapBase + virtual void customMarkerCreated(MyGUI::Widget* marker); + virtual void doorMarkerCreated(MyGUI::Widget* marker); + void updateEnemyHealthBar(); void updatePositions(); diff --git a/files/mygui/openmw_hud.layout b/files/mygui/openmw_hud.layout index 84fd9d247..8334e34b9 100644 --- a/files/mygui/openmw_hud.layout +++ b/files/mygui/openmw_hud.layout @@ -112,7 +112,8 @@
- + + From 539e8276c814c44bf84525c5c569641c0be6849e Mon Sep 17 00:00:00 2001 From: Nathan Aclander Date: Thu, 19 Feb 2015 19:05:19 -0800 Subject: [PATCH 476/740] Silenced clang warning by converting int to string --- apps/opencs/model/tools/referencecheck.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/tools/referencecheck.cpp b/apps/opencs/model/tools/referencecheck.cpp index 0c1d7d38f..8f80c066e 100644 --- a/apps/opencs/model/tools/referencecheck.cpp +++ b/apps/opencs/model/tools/referencecheck.cpp @@ -66,18 +66,18 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message // If object have faction, check if that faction reference is valid if (hasFaction) if (mFactions.searchId(cellRef.mFaction) == -1) - messages.push_back(std::make_pair(id, " has non existing faction " + cellRef.mFaction)); + messages.push_back(std::make_pair(id, " has non existing faction " + boost::lexical_cast(cellRef.mFaction))); // Check item's faction rank if (hasFaction && cellRef.mFactionRank < -1) messages.push_back(std::make_pair(id, " has faction set but has invalid faction rank " + cellRef.mFactionRank)); else if (!hasFaction && cellRef.mFactionRank != -2) - messages.push_back(std::make_pair(id, " has invalid faction rank " + cellRef.mFactionRank)); + messages.push_back(std::make_pair(id, " has invalid faction rank " + boost::lexical_cast(cellRef.mFactionRank))); // If door have destination cell, check if that reference is valid if (!cellRef.mDestCell.empty()) if (mCells.searchId(cellRef.mDestCell) == -1) - messages.push_back(std::make_pair(id, " has non existing destination cell " + cellRef.mDestCell)); + messages.push_back(std::make_pair(id, " has non existing destination cell " + boost::lexical_cast(cellRef.mDestCell))); // Check if scale isn't negative if (cellRef.mScale < 0) From 6d7e1242cc62a3e9ac527e0c007829ee1c47952e Mon Sep 17 00:00:00 2001 From: Nathan Aclander Date: Fri, 20 Feb 2015 20:18:31 -0800 Subject: [PATCH 477/740] Fixed incorrect casting Only cast to strings things that are ints. Also I missed an mFactionRank to cast. --- apps/opencs/model/tools/referencecheck.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/tools/referencecheck.cpp b/apps/opencs/model/tools/referencecheck.cpp index 8f80c066e..68de87d80 100644 --- a/apps/opencs/model/tools/referencecheck.cpp +++ b/apps/opencs/model/tools/referencecheck.cpp @@ -66,18 +66,18 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message // If object have faction, check if that faction reference is valid if (hasFaction) if (mFactions.searchId(cellRef.mFaction) == -1) - messages.push_back(std::make_pair(id, " has non existing faction " + boost::lexical_cast(cellRef.mFaction))); + messages.push_back(std::make_pair(id, " has non existing faction " + cellRef.mFaction)); // Check item's faction rank if (hasFaction && cellRef.mFactionRank < -1) - messages.push_back(std::make_pair(id, " has faction set but has invalid faction rank " + cellRef.mFactionRank)); + messages.push_back(std::make_pair(id, " has faction set but has invalid faction rank " + boost::lexical_cast(cellRef.mFactionRank))); else if (!hasFaction && cellRef.mFactionRank != -2) messages.push_back(std::make_pair(id, " has invalid faction rank " + boost::lexical_cast(cellRef.mFactionRank))); // If door have destination cell, check if that reference is valid if (!cellRef.mDestCell.empty()) if (mCells.searchId(cellRef.mDestCell) == -1) - messages.push_back(std::make_pair(id, " has non existing destination cell " + boost::lexical_cast(cellRef.mDestCell))); + messages.push_back(std::make_pair(id, " has non existing destination cell " + cellRef.mDestCell)); // Check if scale isn't negative if (cellRef.mScale < 0) From accc078e0efa55538eb1dad341acdff4843498c0 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 22 Feb 2015 08:46:12 +1300 Subject: [PATCH 478/740] Morrowind.ini import progress bar. (Fixes #2344) 1. Show a "bouncing ball" Progress bar when importing from morrowind.ini. 2. Removed dialog that asks for content list name when import game files from morrowind.ini. Instead, name is time stamp. 3. Removed commented out code. 4. Additional bugfix. No longer create a empty content list when OpenMW.cfg has no content files. --- apps/launcher/maindialog.cpp | 18 +------- apps/launcher/settingspage.cpp | 59 ++++++++++++++------------ apps/launcher/settingspage.hpp | 4 +- components/config/launchersettings.cpp | 6 +++ files/ui/settingspage.ui | 7 +++ 5 files changed, 49 insertions(+), 45 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index b93d55c17..e4aa3e526 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -238,24 +238,8 @@ void Launcher::MainDialog::changePage(QListWidgetItem *current, QListWidgetItem current = previous; int currentIndex = iconWidget->row(current); -// int previousIndex = iconWidget->row(previous); - pagesWidget->setCurrentIndex(currentIndex); - - // DataFilesPage *previousPage = dynamic_cast(pagesWidget->widget(previousIndex)); - // DataFilesPage *currentPage = dynamic_cast(pagesWidget->widget(currentIndex)); - - // //special call to update/save data files page list view when it's displayed/hidden. - // if (previousPage) - // { - // if (previousPage->objectName() == "DataFilesPage") - // previousPage->saveSettings(); - // } - // else if (currentPage) - // { - // if (currentPage->objectName() == "DataFilesPage") - // currentPage->loadSettings(); - // } + mSettingsPage->resetProgressBar(); } bool Launcher::MainDialog::setupLauncherSettings() diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index c172a3121..a1f6fb0c2 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -39,6 +40,7 @@ Launcher::SettingsPage::SettingsPage(Files::ConfigurationManager &cfg, mWizardInvoker = new ProcessInvoker(); mImporterInvoker = new ProcessInvoker(); + resetProgressBar(); connect(mWizardInvoker->getProcess(), SIGNAL(started()), this, SLOT(wizardStarted())); @@ -141,8 +143,13 @@ void Launcher::SettingsPage::on_importerButton_clicked() qDebug() << "arguments " << arguments; + // start the progress bar as a "bouncing ball" + progressBar->setMaximum(0); + progressBar->setValue(0); if (!mImporterInvoker->startProcess(QLatin1String("openmw-iniimporter"), arguments, false)) - return; + { + resetProgressBar(); + } } void Launcher::SettingsPage::on_browseButton_clicked() @@ -197,38 +204,36 @@ void Launcher::SettingsPage::importerStarted() void Launcher::SettingsPage::importerFinished(int exitCode, QProcess::ExitStatus exitStatus) { if (exitCode != 0 || exitStatus == QProcess::CrashExit) - return; - - // Importer may have changed settings, so refresh - mMain->reloadSettings(); - - // Import selected data files from openmw.cfg - if (addonsCheckBox->isChecked()) { - // Because we've reloaded settings, the current content list matches content in OpenMW.cfg - QString oldContentListName = mLauncherSettings.getCurrentContentListName(); - if (mProfileDialog->exec() == QDialog::Accepted) - { - // remove the current content list to prevent duplication - //... except, not allowed to delete the Default content list - if (oldContentListName.compare(DataFilesPage::mDefaultContentListName) != 0) - { - mLauncherSettings.removeContentList(oldContentListName); - } - - const QString newContentListName(mProfileDialog->lineEdit()->text()); - const QStringList files(mGameSettings.getContentList()); - mLauncherSettings.setCurrentContentListName(newContentListName); - mLauncherSettings.setContentList(newContentListName, files); - - // Make DataFiles Page load the new content list. - mMain->reloadSettings(); - } + resetProgressBar(); + + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Importer finished")); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setIcon(QMessageBox::Warning); + msgBox.setText(tr("Failed to import settings from INI file.")); + msgBox.exec(); + } + else + { + // indicate progress finished + progressBar->setMaximum(1); + progressBar->setValue(1); + + // Importer may have changed settings, so refresh + mMain->reloadSettings(); } importerButton->setEnabled(true); } +void Launcher::SettingsPage::resetProgressBar() +{ + // set progress bar to 0 % + progressBar->setMaximum(1); + progressBar->setValue(0); +} + void Launcher::SettingsPage::updateOkButton(const QString &text) { // We do this here because we need to access the profiles diff --git a/apps/launcher/settingspage.hpp b/apps/launcher/settingspage.hpp index 124c80600..ccc2061dd 100644 --- a/apps/launcher/settingspage.hpp +++ b/apps/launcher/settingspage.hpp @@ -29,6 +29,9 @@ namespace Launcher void saveSettings(); bool loadSettings(); + + /// set progress bar on page to 0% + void resetProgressBar(); private slots: @@ -57,7 +60,6 @@ namespace Launcher MainDialog *mMain; TextInputDialog *mProfileDialog; - }; } diff --git a/components/config/launchersettings.cpp b/components/config/launchersettings.cpp index 66f05f691..1d4b428c9 100644 --- a/components/config/launchersettings.cpp +++ b/components/config/launchersettings.cpp @@ -105,6 +105,12 @@ void Config::LauncherSettings::setContentList(const GameSettings& gameSettings) // obtain content list from game settings (if present) const QStringList files(gameSettings.getContentList()); + // if openmw.cfg has no content, exit so we don't create an empty content list. + if (files.isEmpty()) + { + return; + } + // if any existing profile in launcher matches the content list, make that profile the default foreach(const QString &listName, getContentLists()) { diff --git a/files/ui/settingspage.ui b/files/ui/settingspage.ui index 6c873ea92..7f5e4a7de 100644 --- a/files/ui/settingspage.ui +++ b/files/ui/settingspage.ui @@ -131,6 +131,13 @@
+ + + + 4 + + + From 9708e8529fd4253bf34ee3243a68e562efd39368 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 22 Feb 2015 08:58:17 +1300 Subject: [PATCH 479/740] Removed unneeded include. --- apps/launcher/settingspage.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index a1f6fb0c2..5b26b01b9 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include From 514fba5f733f296d995fb6fd6004addd7c20fedc Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 22 Feb 2015 10:02:25 +1300 Subject: [PATCH 480/740] On Windows content list imported from morrowind.ini is sorted by file modified time stamps. --- apps/mwiniimporter/importer.cpp | 42 +++++++++++++++++++++++++-------- apps/mwiniimporter/importer.hpp | 12 +++++++--- apps/mwiniimporter/main.cpp | 6 ++--- 3 files changed, 44 insertions(+), 16 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 80f186b1f..6b8424da6 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include #include namespace bfs = boost::filesystem; @@ -660,7 +660,7 @@ std::string MwIniImporter::numberToString(int n) { return str.str(); } -MwIniImporter::multistrmap MwIniImporter::loadIniFile(const std::string& filename) const { +MwIniImporter::multistrmap MwIniImporter::loadIniFile(const boost::filesystem::path& filename) const { std::cout << "load ini file: " << filename << std::endl; std::string section(""); @@ -719,7 +719,7 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(const std::string& filenam return map; } -MwIniImporter::multistrmap MwIniImporter::loadCfgFile(const std::string& filename) { +MwIniImporter::multistrmap MwIniImporter::loadCfgFile(const boost::filesystem::path& filename) { std::cout << "load cfg file: " << filename << std::endl; MwIniImporter::multistrmap map; @@ -825,10 +825,14 @@ void MwIniImporter::importArchives(multistrmap &cfg, const multistrmap &ini) con } } -void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini) const { - std::vector contentFiles; +void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, const boost::filesystem::path& iniFilename) const { + std::vector > contentFiles; std::string baseGameFile("Game Files:GameFile"); std::string gameFile(""); + std::time_t defaultTime = 0; + + // assume the Game Files are all in a "Data Files" directory under the directory holding Morrowind.ini + const boost::filesystem::path gameFilesDir(iniFilename.parent_path() /= "Data Files"); multistrmap::const_iterator it = ini.begin(); for(int i=0; it != ini.end(); i++) { @@ -845,18 +849,20 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini) co Misc::StringUtils::toLower(filetype); if(filetype.compare("esm") == 0 || filetype.compare("esp") == 0) { - contentFiles.push_back(*entry); + boost::filesystem::path filepath(gameFilesDir); + filepath /= *entry; + contentFiles.push_back(std::make_pair(lastWriteTime(filepath, defaultTime), *entry)); } } - - gameFile = ""; } cfg.erase("content"); cfg.insert( std::make_pair("content", std::vector() ) ); - for(std::vector::const_iterator it=contentFiles.begin(); it!=contentFiles.end(); ++it) { - cfg["content"].push_back(*it); + // this will sort files by time order first, then alphabetical (maybe), I suspect non ASCII filenames will be stuffed. + sort(contentFiles.begin(), contentFiles.end()); + for(std::vector >::const_iterator it=contentFiles.begin(); it!=contentFiles.end(); ++it) { + cfg["content"].push_back(it->second); } } @@ -873,3 +879,19 @@ void MwIniImporter::setInputEncoding(const ToUTF8::FromType &encoding) { mEncoding = encoding; } + +std::time_t MwIniImporter::lastWriteTime(const boost::filesystem::path& filename, std::time_t defaultTime) +{ + std::time_t writeTime(defaultTime); + if (boost::filesystem::exists(filename)) + { + writeTime = boost::filesystem::last_write_time(filename); + std::cout << "content file: " << filename << " timestamp = (" << writeTime << + ") " << asctime(localtime(&writeTime)) << std::endl; + } + else + { + std::cout << "content file: " << filename << " not found" << std::endl; + } + return writeTime; +} \ No newline at end of file diff --git a/apps/mwiniimporter/importer.hpp b/apps/mwiniimporter/importer.hpp index 72b14ba75..c73cc65b5 100644 --- a/apps/mwiniimporter/importer.hpp +++ b/apps/mwiniimporter/importer.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -17,17 +18,22 @@ class MwIniImporter { MwIniImporter(); void setInputEncoding(const ToUTF8::FromType& encoding); void setVerbose(bool verbose); - multistrmap loadIniFile(const std::string& filename) const; - static multistrmap loadCfgFile(const std::string& filename); + multistrmap loadIniFile(const boost::filesystem::path& filename) const; + static multistrmap loadCfgFile(const boost::filesystem::path& filename); void merge(multistrmap &cfg, const multistrmap &ini) const; void mergeFallback(multistrmap &cfg, const multistrmap &ini) const; - void importGameFiles(multistrmap &cfg, const multistrmap &ini) const; + void importGameFiles(multistrmap &cfg, const multistrmap &ini, + const boost::filesystem::path& iniFilename) const; void importArchives(multistrmap &cfg, const multistrmap &ini) const; static void writeToFile(std::ostream &out, const multistrmap &cfg); private: static void insertMultistrmap(multistrmap &cfg, const std::string& key, const std::string& value); static std::string numberToString(int n); + + /// \return file's "last modified time", used in original MW to determine plug-in load order + static std::time_t lastWriteTime(const boost::filesystem::path& filename, std::time_t defaultTime); + bool mVerbose; strmap mMergeMap; std::vector mMergeFallback; diff --git a/apps/mwiniimporter/main.cpp b/apps/mwiniimporter/main.cpp index f108678f3..3c48fedc9 100644 --- a/apps/mwiniimporter/main.cpp +++ b/apps/mwiniimporter/main.cpp @@ -93,8 +93,8 @@ int wmain(int argc, wchar_t *wargv[]) { bpo::notify(vm); - std::string iniFile = vm["ini"].as(); - std::string cfgFile = vm["cfg"].as(); + boost::filesystem::path iniFile(vm["ini"].as()); + boost::filesystem::path cfgFile(vm["cfg"].as()); // if no output is given, write back to cfg file std::string outputFile(vm["output"].as()); @@ -123,7 +123,7 @@ int wmain(int argc, wchar_t *wargv[]) { importer.mergeFallback(cfg, ini); if(vm.count("game-files")) { - importer.importGameFiles(cfg, ini); + importer.importGameFiles(cfg, ini, iniFile); } if(!vm.count("no-archives")) { From 5eadffd0c49c045eb5bca39a02f4bce311420833 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Feb 2015 00:13:03 +0100 Subject: [PATCH 481/740] Make launcher's version label selectable so it can be copy-pasted into issue reports --- apps/launcher/maindialog.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index b93d55c17..64cd034cb 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -61,6 +61,7 @@ Launcher::MainDialog::MainDialog(QWidget *parent) QString revision(OPENMW_VERSION_COMMITHASH); QString tag(OPENMW_VERSION_TAGHASH); + versionLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); if (!revision.isEmpty() && !tag.isEmpty()) { if (revision == tag) { From c21b59ecff764b774a3db95778c6434c04e0f8d5 Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Sat, 21 Feb 2015 15:55:22 -0600 Subject: [PATCH 482/740] Teleportation: Avoid marking searched cells as changed. OMW Bug #1533 Only mark cells with the target marker / evidence chest as 'changed'. --- apps/openmw/mwworld/cellstore.hpp | 11 +++++++++++ apps/openmw/mwworld/worldimp.cpp | 33 ++++++++----------------------- 2 files changed, 19 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index f6f2a3b48..1d4e99532 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -184,6 +184,11 @@ namespace MWWorld throw std::runtime_error ("Storage for this type not exist in cells"); } + template + CellRefList& getReadOnly() { + throw std::runtime_error ("Read Only access not available for this type"); + } + bool isPointConnected(const int start, const int end) const; std::list aStarSearch(const int start, const int end) const; @@ -357,6 +362,12 @@ namespace MWWorld return mWeapons; } + template<> + inline CellRefList& CellStore::getReadOnly() + { + return mDoors; + } + bool operator== (const CellStore& left, const CellStore& right); bool operator!= (const CellStore& left, const CellStore& right); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 54385cf83..dd730b32a 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2799,7 +2799,7 @@ namespace MWWorld MWWorld::CellStore *next = getInterior( *i ); if ( !next ) continue; - MWWorld::CellRefList& doors = next->get(); + MWWorld::CellRefList& doors = next->getReadOnly(); CellRefList::List& refList = doors.mList; // Check if any door in the cell leads to an exterior directly @@ -2838,6 +2838,8 @@ namespace MWWorld std::set< std::string >checkedCells; std::set< std::string >currentCells; std::set< std::string >nextCells; + MWWorld::Ptr closestMarker; + nextCells.insert( ptr.getCell()->getCell()->mName ); while ( !nextCells.empty() ) { currentCells = nextCells; @@ -2847,17 +2849,13 @@ namespace MWWorld checkedCells.insert( *i ); if ( !next ) continue; - MWWorld::CellRefList& statics = next->get(); - CellRefList::List& staticList = statics.mList; - for (CellRefList::List::iterator it = staticList.begin(); it != staticList.end(); ++it) + closestMarker = next->search( id ); + if ( !closestMarker.isEmpty() ) { - MWWorld::LiveCellRef& ref = *it; - if ( id == ref.mRef.getRefId() ) { - return MWWorld::Ptr( &ref, next ); - } + return closestMarker; } - MWWorld::CellRefList& doors = next->get(); + MWWorld::CellRefList& doors = next->getReadOnly(); CellRefList::List& doorList = doors.mList; // Check if any door in the cell leads to an exterior directly @@ -2865,10 +2863,6 @@ namespace MWWorld { MWWorld::LiveCellRef& ref = *it; - if ( id == ref.mRef.getRefId() ) { - return MWWorld::Ptr( &ref, next ); - } - if (!ref.mRef.getTeleport()) continue; if (ref.mRef.getDestCell().empty()) @@ -3085,18 +3079,7 @@ namespace MWWorld return; } - MWWorld::Ptr closestChest; - - MWWorld::CellRefList& containers = prison->get(); - CellRefList::List& refList = containers.mList; - for (CellRefList::List::iterator it = refList.begin(); it != refList.end(); ++it) - { - MWWorld::LiveCellRef& ref = *it; - if ( ref.mRef.getRefId() == "stolen_goods" ) { - closestChest = MWWorld::Ptr( &ref, prison ); - } - } - + MWWorld::Ptr closestChest = prison->search( "stolen_goods" ); if (!closestChest.isEmpty()) //Found a close chest { MWBase::Environment::get().getMechanicsManager()->confiscateStolenItems(ptr, closestChest); From f6128a85b2531806e2ef01b6d0c6f5ffd68ec6f5 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 22 Feb 2015 13:48:44 +1300 Subject: [PATCH 483/740] resolve symlinks when searching for file's last modified time. --- apps/mwiniimporter/importer.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 6b8424da6..b71ebd2b8 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -883,15 +883,16 @@ void MwIniImporter::setInputEncoding(const ToUTF8::FromType &encoding) std::time_t MwIniImporter::lastWriteTime(const boost::filesystem::path& filename, std::time_t defaultTime) { std::time_t writeTime(defaultTime); - if (boost::filesystem::exists(filename)) + boost::filesystem::path resolved = boost::filesystem::canonical(filename); + if (boost::filesystem::exists(resolved)) { - writeTime = boost::filesystem::last_write_time(filename); - std::cout << "content file: " << filename << " timestamp = (" << writeTime << + writeTime = boost::filesystem::last_write_time(resolved); + std::cout << "content file: " << resolved << " timestamp = (" << writeTime << ") " << asctime(localtime(&writeTime)) << std::endl; } else { - std::cout << "content file: " << filename << " not found" << std::endl; + std::cout << "content file: " << resolved << " not found" << std::endl; } return writeTime; } \ No newline at end of file From 387969bf4250f95c9cffd5d5ccd8ae8a5b5a55bd Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Feb 2015 18:05:46 +0100 Subject: [PATCH 484/740] Remove an old .gitignore --- components/nif/.gitignore | 1 - 1 file changed, 1 deletion(-) delete mode 100644 components/nif/.gitignore diff --git a/components/nif/.gitignore b/components/nif/.gitignore deleted file mode 100644 index 731498d9a..000000000 --- a/components/nif/.gitignore +++ /dev/null @@ -1 +0,0 @@ -old_d From 399259a95cb1632ec1f183602c4dc77564786308 Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Sun, 22 Feb 2015 12:12:54 -0600 Subject: [PATCH 485/740] Improve CellStore exception messages. --- apps/openmw/mwworld/cellstore.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 1d4e99532..cd7af5ad6 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -3,6 +3,8 @@ #include #include +#include +#include #include #include "livecellref.hpp" @@ -181,12 +183,12 @@ namespace MWWorld template CellRefList& get() { - throw std::runtime_error ("Storage for this type not exist in cells"); + throw std::runtime_error ("Storage for type " + std::string(typeid(T).name())+ " does not exist in cells"); } template CellRefList& getReadOnly() { - throw std::runtime_error ("Read Only access not available for this type"); + throw std::runtime_error ("Read Only CellRefList access not available for type " + std::string(typeid(T).name()) ); } bool isPointConnected(const int start, const int end) const; From 5edafc2a4cf50afb0ef083df70ae245779219697 Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Sun, 22 Feb 2015 12:25:10 -0600 Subject: [PATCH 486/740] Cleanup: Add const to read-only CellRefList access. OMW Bug #1533 --- apps/openmw/mwworld/cellstore.hpp | 4 ++-- apps/openmw/mwworld/worldimp.cpp | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index cd7af5ad6..d7036d6b1 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -187,7 +187,7 @@ namespace MWWorld } template - CellRefList& getReadOnly() { + const CellRefList& getReadOnly() { throw std::runtime_error ("Read Only CellRefList access not available for type " + std::string(typeid(T).name()) ); } @@ -365,7 +365,7 @@ namespace MWWorld } template<> - inline CellRefList& CellStore::getReadOnly() + inline const CellRefList& CellStore::getReadOnly() { return mDoors; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index dd730b32a..5f42a5379 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2799,13 +2799,13 @@ namespace MWWorld MWWorld::CellStore *next = getInterior( *i ); if ( !next ) continue; - MWWorld::CellRefList& doors = next->getReadOnly(); - CellRefList::List& refList = doors.mList; + const MWWorld::CellRefList& doors = next->getReadOnly(); + const CellRefList::List& refList = doors.mList; // Check if any door in the cell leads to an exterior directly - for (CellRefList::List::iterator it = refList.begin(); it != refList.end(); ++it) + for (CellRefList::List::const_iterator it = refList.begin(); it != refList.end(); ++it) { - MWWorld::LiveCellRef& ref = *it; + const MWWorld::LiveCellRef& ref = *it; if (!ref.mRef.getTeleport()) continue; if (ref.mRef.getDestCell().empty()) @@ -2855,13 +2855,13 @@ namespace MWWorld return closestMarker; } - MWWorld::CellRefList& doors = next->getReadOnly(); - CellRefList::List& doorList = doors.mList; + const MWWorld::CellRefList& doors = next->getReadOnly(); + const CellRefList::List& doorList = doors.mList; // Check if any door in the cell leads to an exterior directly - for (CellRefList::List::iterator it = doorList.begin(); it != doorList.end(); ++it) + for (CellRefList::List::const_iterator it = doorList.begin(); it != doorList.end(); ++it) { - MWWorld::LiveCellRef& ref = *it; + const MWWorld::LiveCellRef& ref = *it; if (!ref.mRef.getTeleport()) continue; From 68f89318e755d55e8e51bc3bdf079682cf2283fa Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Feb 2015 20:56:47 +0100 Subject: [PATCH 487/740] Fix canvas align in skill view --- files/mygui/openmw_stats_window.layout | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/files/mygui/openmw_stats_window.layout b/files/mygui/openmw_stats_window.layout index 11119c404..1d9b75b9b 100644 --- a/files/mygui/openmw_stats_window.layout +++ b/files/mygui/openmw_stats_window.layout @@ -235,7 +235,9 @@ - + + + From 47c053444f2ed3011372cdd385601020975d6475 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Mon, 23 Feb 2015 00:23:09 +0100 Subject: [PATCH 488/740] Make the jail progress last one second --- apps/openmw/mwgui/jailscreen.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index 548b1b604..58873c566 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -17,7 +17,7 @@ namespace MWGui { JailScreen::JailScreen() : WindowBase("openmw_jail_screen.layout"), - mTimeAdvancer(0.0125), + mTimeAdvancer(0.01), mDays(1), mFadeTimeRemaining(0) { @@ -39,7 +39,7 @@ namespace MWGui mFadeTimeRemaining = 0.5; setVisible(false); - mProgressBar->setScrollRange(days*24+1); + mProgressBar->setScrollRange(100+1); mProgressBar->setScrollPosition(0); mProgressBar->setTrackSize(0); } @@ -59,7 +59,7 @@ namespace MWGui MWBase::Environment::get().getWorld()->teleportToClosestMarker(player, "prisonmarker"); setVisible(true); - mTimeAdvancer.run(mDays*24); + mTimeAdvancer.run(100); } } From 84762c4eb8f49bddbb5947a54cb2321cde86f421 Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 23 Feb 2015 19:30:46 +1300 Subject: [PATCH 489/740] Progress bar at 0% shows no text. --- apps/launcher/settingspage.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index 5b26b01b9..c228aba50 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -229,8 +229,7 @@ void Launcher::SettingsPage::importerFinished(int exitCode, QProcess::ExitStatus void Launcher::SettingsPage::resetProgressBar() { // set progress bar to 0 % - progressBar->setMaximum(1); - progressBar->setValue(0); + progressBar->reset(); } void Launcher::SettingsPage::updateOkButton(const QString &text) From 6dc202cba337416e68a54100ee76931abbbca60e Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 23 Feb 2015 19:41:41 +1300 Subject: [PATCH 490/740] Removed unneeded parameter from ContentModel::setContentList() --- components/contentselector/model/contentmodel.cpp | 4 ++-- components/contentselector/model/contentmodel.hpp | 2 +- components/contentselector/view/contentselector.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index ec1fcc21e..02a260022 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -536,13 +536,13 @@ bool ContentSelectorModel::ContentModel::isLoadOrderError(const EsmFile *file) c return mPluginsWithLoadOrderError.contains(file->filePath()); } -void ContentSelectorModel::ContentModel::setContentList(const QStringList &fileList, bool isChecked) +void ContentSelectorModel::ContentModel::setContentList(const QStringList &fileList) { mPluginsWithLoadOrderError.clear(); int previousPosition = -1; foreach (const QString &filepath, fileList) { - if (setCheckState(filepath, isChecked)) + if (setCheckState(filepath, true)) { // as necessary, move plug-ins in visible list to match sequence of supplied filelist const EsmFile* file = item(filepath); diff --git a/components/contentselector/model/contentmodel.hpp b/components/contentselector/model/contentmodel.hpp index 6af5425c7..3d8229aeb 100644 --- a/components/contentselector/model/contentmodel.hpp +++ b/components/contentselector/model/contentmodel.hpp @@ -51,7 +51,7 @@ namespace ContentSelectorModel bool isEnabled (QModelIndex index) const; bool isChecked(const QString &filepath) const; bool setCheckState(const QString &filepath, bool isChecked); - void setContentList(const QStringList &fileList, bool isChecked); + void setContentList(const QStringList &fileList); ContentFileList checkedItems() const; void uncheckAll(); diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index ad023e5b2..3aa5ddf80 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -113,7 +113,7 @@ void ContentSelectorView::ContentSelector::setContentList(const QStringList &lis slotCurrentGameFileIndexChanged (ui.gameFileView->currentIndex()); } else - mContentModel->setContentList(list, true); + mContentModel->setContentList(list); } ContentSelectorModel::ContentFileList From 63af9d848a5ca9dba169ff2cd4c957cdd0957cdd Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 23 Feb 2015 19:58:31 +1300 Subject: [PATCH 491/740] Add constraint: Bloodmoon.esm requires Tribunal.esm. --- components/contentselector/model/contentmodel.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 02a260022..a4fbdcf06 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -467,6 +467,14 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path) file->setFilePath (info.absoluteFilePath()); file->setDescription(QString::fromUtf8(fileReader.getDesc().c_str())); + // HACK + // Bloodmoon.esm requires Tribunal.esm, but this requirement is missing + // from the file supplied by Bethesda, so we have to add it ourselves + if (file->fileName().compare("Bloodmoon.esm", Qt::CaseInsensitive) == 0) + { + file->addGameFile(QString::fromUtf8("Tribunal.esm")); + } + // Put the file in the table addFile(file); From 77bb77b367a39bae791449500c212dd39493d227 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Feb 2015 19:07:12 +0100 Subject: [PATCH 492/740] Fix for instant restore effects (Fixes #2392) --- apps/openmw/mwmechanics/spellcasting.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 4ce3fcaf5..105fa5866 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -594,6 +594,7 @@ namespace MWMechanics value.restore(magnitude); target.getClass().getCreatureStats(target).setAttribute(attribute, value); } + // TODO: refactor the effect tick functions in Actors so they can be reused here else if (effectId == ESM::MagicEffect::DamageHealth) { applyDynamicStatsEffect(0, target, magnitude * -1); @@ -683,7 +684,7 @@ namespace MWMechanics void CastSpell::applyDynamicStatsEffect(int attribute, const MWWorld::Ptr& target, float magnitude) { DynamicStat value = target.getClass().getCreatureStats(target).getDynamic(attribute); - value.modify(magnitude); + value.setCurrent(value.getCurrent()+magnitude, attribute == 2); target.getClass().getCreatureStats(target).setDynamic(attribute, value); } From 6878e317a7c9c64ac9916ade1e9864dca5db6815 Mon Sep 17 00:00:00 2001 From: dteviot Date: Tue, 24 Feb 2015 20:06:06 +1300 Subject: [PATCH 493/740] launcher: decouple Combo Box model from Plug-ins model. fixes bug reported by scrawl 1. openmw.cfg had content files in order 'Bloodmoon.esm, Tribunal.esm, Morrowind.esm' 2. Blank_ESM_2.0.esm is in the Data Files directory 3. Do an ini file import. 4. Imported profile will have Blank_ESM_2.0.esm as the game file. Should be Morrowind.esm. Root cause: Game File combo box and Plugins Grid shared same data model, so changing plug-in file order also changed order of Game File combo box. --- .../contentselector/model/contentmodel.cpp | 15 ++++++- .../contentselector/model/contentmodel.hpp | 1 + .../contentselector/view/contentselector.cpp | 42 +++++++++++-------- .../contentselector/view/contentselector.hpp | 2 +- 4 files changed, 41 insertions(+), 19 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index a4fbdcf06..485510df4 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -489,6 +489,19 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path) sortFiles(); } +QStringList ContentSelectorModel::ContentModel::gameFiles() const +{ + QStringList gameFiles; + foreach(const ContentSelectorModel::EsmFile *file, mFiles) + { + if (file->isGameFile()) + { + gameFiles.append(file->fileName()); + } + } + return gameFiles; +} + void ContentSelectorModel::ContentModel::sortFiles() { //first, sort the model such that all dependencies are ordered upstream (gamefile) first. @@ -589,7 +602,7 @@ void ContentSelectorModel::ContentModel::checkForLoadOrderErrors() QList ContentSelectorModel::ContentModel::checkForLoadOrderErrors(const EsmFile *file, int row) const { QList errors = QList(); - foreach(QString dependentfileName, file->gameFiles()) + foreach(const QString &dependentfileName, file->gameFiles()) { const EsmFile* dependentFile = item(dependentfileName); diff --git a/components/contentselector/model/contentmodel.hpp b/components/contentselector/model/contentmodel.hpp index 3d8229aeb..658555852 100644 --- a/components/contentselector/model/contentmodel.hpp +++ b/components/contentselector/model/contentmodel.hpp @@ -47,6 +47,7 @@ namespace ContentSelectorModel QModelIndex indexFromItem(const EsmFile *item) const; const EsmFile *item(const QString &name) const; + QStringList gameFiles() const; bool isEnabled (QModelIndex index) const; bool isChecked(const QString &filepath) const; diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index 3aa5ddf80..2363ae477 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include ContentSelectorView::ContentSelector::ContentSelector(QWidget *parent) : @@ -33,13 +34,7 @@ void ContentSelectorView::ContentSelector::buildGameFileView() { ui.gameFileView->setVisible (true); - mGameFileProxyModel = new QSortFilterProxyModel(this); - mGameFileProxyModel->setFilterRegExp(QString::number((int)ContentSelectorModel::ContentType_GameFile)); - mGameFileProxyModel->setFilterRole (Qt::UserRole); - mGameFileProxyModel->setSourceModel (mContentModel); - ui.gameFileView->setPlaceholderText(QString("Select a game file...")); - ui.gameFileView->setModel(mGameFileProxyModel); connect (ui.gameFileView, SIGNAL (currentIndexChanged(int)), this, SLOT (slotCurrentGameFileIndexChanged(int))); @@ -129,6 +124,15 @@ void ContentSelectorView::ContentSelector::addFiles(const QString &path) { mContentModel->addFiles(path); + // add any game files to the combo box + foreach(const QString gameFileName, mContentModel->gameFiles()) + { + if (ui.gameFileView->findText(gameFileName) == -1) + { + ui.gameFileView->addItem(gameFileName); + } + } + if (ui.gameFileView->currentIndex() != -1) ui.gameFileView->setCurrentIndex(-1); @@ -150,29 +154,33 @@ void ContentSelectorView::ContentSelector::slotCurrentGameFileIndexChanged(int i { static int oldIndex = -1; - QAbstractItemModel *const model = ui.gameFileView->model(); - QSortFilterProxyModel *proxy = dynamic_cast(model); - - if (proxy) - proxy->setDynamicSortFilter(false); - if (index != oldIndex) { if (oldIndex > -1) - model->setData(model->index(oldIndex, 0), false, Qt::UserRole + 1); + { + setGameFileSelected(oldIndex, false); + } oldIndex = index; - model->setData(model->index(index, 0), true, Qt::UserRole + 1); + setGameFileSelected(index, true); mContentModel->checkForLoadOrderErrors(); } - if (proxy) - proxy->setDynamicSortFilter(true); - emit signalCurrentGamefileIndexChanged (index); } +void ContentSelectorView::ContentSelector::setGameFileSelected(int index, bool selected) +{ + QString fileName = ui.gameFileView->itemText(index); + const ContentSelectorModel::EsmFile* file = mContentModel->item(fileName); + if (file != NULL) + { + QModelIndex index(mContentModel->indexFromItem(file)); + mContentModel->setData(index, selected, Qt::UserRole + 1); + } +} + void ContentSelectorView::ContentSelector::slotAddonTableItemActivated(const QModelIndex &index) { QModelIndex sourceIndex = mAddonProxyModel->mapToSource (index); diff --git a/components/contentselector/view/contentselector.hpp b/components/contentselector/view/contentselector.hpp index 8651dac2e..2507cf6ad 100644 --- a/components/contentselector/view/contentselector.hpp +++ b/components/contentselector/view/contentselector.hpp @@ -19,7 +19,6 @@ namespace ContentSelectorView protected: ContentSelectorModel::ContentModel *mContentModel; - QSortFilterProxyModel *mGameFileProxyModel; QSortFilterProxyModel *mAddonProxyModel; public: @@ -52,6 +51,7 @@ namespace ContentSelectorView void buildContentModel(); void buildGameFileView(); void buildAddonView(); + void setGameFileSelected(int index, bool selected); signals: void signalCurrentGamefileIndexChanged (int); From cc815c63f18407de5ffc684e3282a53479ecf348 Mon Sep 17 00:00:00 2001 From: dteviot Date: Tue, 24 Feb 2015 20:14:18 +1300 Subject: [PATCH 494/740] Fix: no longer loose changes when run install wizard or iniimport. --- apps/launcher/settingspage.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index c228aba50..34b4b41a9 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -95,7 +95,7 @@ Launcher::SettingsPage::~SettingsPage() void Launcher::SettingsPage::on_wizardButton_clicked() { - saveSettings(); + mMain->writeSettings(); if (!mWizardInvoker->startProcess(QLatin1String("openmw-wizard"), false)) return; @@ -103,7 +103,7 @@ void Launcher::SettingsPage::on_wizardButton_clicked() void Launcher::SettingsPage::on_importerButton_clicked() { - saveSettings(); + mMain->writeSettings(); // Create the file if it doesn't already exist, else the importer will fail QString path(QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str())); From e1032620959de5c4d04c87d92cd420000774d084 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 24 Feb 2015 18:15:41 +0100 Subject: [PATCH 495/740] updated credits file --- AUTHORS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AUTHORS.md b/AUTHORS.md index 540c0ede5..90c543ada 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -39,6 +39,7 @@ Programmers Eli2 Emanuel Guével (potatoesmaster) eroen + Evgeniy Mineev (sandstranger) Fil Krynicki (filkry) Gašper Sedej gugus/gus @@ -91,7 +92,6 @@ Programmers Rohit Nirmal Roman Melnik (Kromgart) Roman Proskuryakov (humbug) - sandstranger Sandy Carter (bwrsandman) Scott Howard Sebastian Wick (swick) From 24de6ba27e06a381a56abdc7913586b75634569e Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 24 Feb 2015 17:09:49 +0100 Subject: [PATCH 496/740] Fix crash for LAND records without data --- apps/openmw/mwworld/scene.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 72d475f16..f03f65b36 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -230,7 +230,7 @@ namespace MWWorld cell->getCell()->getGridX(), cell->getCell()->getGridY() ); - if (land) { + if (land && land->mDataTypes&ESM::Land::DATA_VHGT) { // Actually only VHGT is needed here, but we'll need the rest for rendering anyway. // Load everything now to reduce IO overhead. const int flags = ESM::Land::DATA_VCLR|ESM::Land::DATA_VHGT|ESM::Land::DATA_VNML|ESM::Land::DATA_VTEX; From 5672c86924fe8aa9c104e9d0d23714ac1230640a Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Tue, 24 Feb 2015 23:37:53 +0100 Subject: [PATCH 497/740] Rename window title for OpenMW-CS --- apps/opencs/view/doc/startup.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/doc/startup.cpp b/apps/opencs/view/doc/startup.cpp index 799a07e14..58a46c603 100644 --- a/apps/opencs/view/doc/startup.cpp +++ b/apps/opencs/view/doc/startup.cpp @@ -96,7 +96,7 @@ QWidget *CSVDoc::StartupDialogue::createTools() CSVDoc::StartupDialogue::StartupDialogue() : mWidth (0), mColumn (2) { - setWindowTitle ("Open CS"); + setWindowTitle ("OpenMW-CS"); QVBoxLayout *layout = new QVBoxLayout (this); From 691ebd237215e502f8e096a8f5f5b8253fb9275c Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Tue, 24 Feb 2015 20:51:57 -0600 Subject: [PATCH 498/740] Correction to teleportation changes. OMW Bug #2400 Related to OMW Bug #1533 Don't crash when finding the closest marker to an exterior position. --- apps/openmw/mwworld/worldimp.cpp | 47 +++++++++++++++++++------------- apps/openmw/mwworld/worldimp.hpp | 1 + 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6462629f4..4cafab41d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2832,6 +2832,10 @@ namespace MWWorld MWWorld::Ptr World::getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id ) { + if ( ptr.getCell()->isExterior() ) { + return getClosestMarkerFromExteriorPosition(mPlayer->getLastKnownExteriorPosition(), id); + } + // Search for a 'nearest' marker, counting each cell between the starting // cell and the exterior as a distance of 1. If an exterior is found, jump // to the nearest exterior marker, without further interior searching. @@ -2868,25 +2872,7 @@ namespace MWWorld if (ref.mRef.getDestCell().empty()) { Ogre::Vector3 worldPos = Ogre::Vector3(ref.mRef.getDoorDest().pos); - float closestDistance = FLT_MAX; - - MWWorld::Ptr closestMarker; - std::vector markers; - mCells.getExteriorPtrs(id, markers); - for (std::vector::iterator it2 = markers.begin(); it2 != markers.end(); ++it2) - { - ESM::Position pos = it2->getRefData().getPosition(); - Ogre::Vector3 markerPos = Ogre::Vector3(pos.pos); - float distance = worldPos.squaredDistance(markerPos); - if (distance < closestDistance) - { - closestDistance = distance; - closestMarker = *it2; - } - - } - - return closestMarker; + return getClosestMarkerFromExteriorPosition(worldPos, id); } else { @@ -2901,6 +2887,29 @@ namespace MWWorld return MWWorld::Ptr(); } + MWWorld::Ptr World::getClosestMarkerFromExteriorPosition( const Ogre::Vector3 worldPos, const std::string &id ) { + MWWorld::Ptr closestMarker; + float closestDistance = FLT_MAX; + + std::vector markers; + mCells.getExteriorPtrs(id, markers); + for (std::vector::iterator it2 = markers.begin(); it2 != markers.end(); ++it2) + { + ESM::Position pos = it2->getRefData().getPosition(); + Ogre::Vector3 markerPos = Ogre::Vector3(pos.pos); + float distance = worldPos.squaredDistance(markerPos); + if (distance < closestDistance) + { + closestDistance = distance; + closestMarker = *it2; + } + + } + + return closestMarker; + } + + void World::teleportToClosestMarker (const MWWorld::Ptr& ptr, const std::string& id) { diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 22509f801..1db86f738 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -151,6 +151,7 @@ namespace MWWorld float feetToGameUnits(float feet); MWWorld::Ptr getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id ); + MWWorld::Ptr getClosestMarkerFromExteriorPosition( const Ogre::Vector3 worldPos, const std::string &id ); public: From 659a8ba279e1affc6ef954c4cbae9ba76eea92cb Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Tue, 24 Feb 2015 21:10:01 -0600 Subject: [PATCH 499/740] Correction to teleportation changes. OMW Bug #2400 Related to OMW Bug #1533 Don't crash on confiscating items if a prison marker cannot be found. --- apps/openmw/mwworld/worldimp.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 4cafab41d..fe56fc3bb 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3075,6 +3075,11 @@ namespace MWWorld void World::confiscateStolenItems(const Ptr &ptr) { MWWorld::Ptr prisonMarker = getClosestMarker( ptr, "prisonmarker" ); + if ( prisonMarker.isEmpty() ) + { + std::cerr << "Failed to confiscate items: no closest prison marker found." << std::endl; + return; + } std::string prisonName = prisonMarker.mRef->mRef.getDestCell(); if ( prisonName.empty() ) { From 9d61457956e35b56dfbf24e9cab8a532cad61591 Mon Sep 17 00:00:00 2001 From: dteviot Date: Wed, 25 Feb 2015 20:54:52 +1300 Subject: [PATCH 500/740] AddOn files can be checked if game file is checked, but dependencies do not exist. --- .../contentselector/model/contentmodel.cpp | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 485510df4..cd0c67ee7 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -110,15 +110,14 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index if (!file) return Qt::NoItemFlags; - //game files can always be checked + //game files are not shown if (file->isGameFile()) - return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable; + return Qt::NoItemFlags; Qt::ItemFlags returnFlags; - bool allDependenciesFound = true; bool gamefileChecked = false; - //addon can be checked if its gamefile is and all other dependencies exist + // addon can be checked if its gamefile is foreach (const QString &fileName, file->gameFiles()) { bool depFound = false; @@ -144,16 +143,11 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index if (gamefileChecked || !(dependency->isGameFile())) break; } - - allDependenciesFound = allDependenciesFound && depFound; } if (gamefileChecked) { - if (allDependenciesFound) - returnFlags = returnFlags | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled; - else - returnFlags = Qt::ItemIsSelectable; + returnFlags = Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled; } return returnFlags; @@ -468,7 +462,7 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path) file->setDescription(QString::fromUtf8(fileReader.getDesc().c_str())); // HACK - // Bloodmoon.esm requires Tribunal.esm, but this requirement is missing + // Load order constraint of Bloodmoon.esm needing Tribunal.esm is missing // from the file supplied by Bethesda, so we have to add it ourselves if (file->fileName().compare("Bloodmoon.esm", Qt::CaseInsensitive) == 0) { From 931c95d0b130e07a4f9e8fb2f41c99235607cc41 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 26 Feb 2015 06:17:29 +1300 Subject: [PATCH 501/740] workaround for not building on Linux version of Travis. --- apps/mwiniimporter/importer.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index b71ebd2b8..00774d798 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -883,16 +883,23 @@ void MwIniImporter::setInputEncoding(const ToUTF8::FromType &encoding) std::time_t MwIniImporter::lastWriteTime(const boost::filesystem::path& filename, std::time_t defaultTime) { std::time_t writeTime(defaultTime); - boost::filesystem::path resolved = boost::filesystem::canonical(filename); - if (boost::filesystem::exists(resolved)) + if (boost::filesystem::exists(filename)) { + // FixMe: remove #if when Boost on Travis Linux updated + // Travis seems to be using older version of boost for Linux + // This should allow things to build until fixed +#if BOOST_FILESYSTEM_VERSION == 3 + boost::filesystem::path resolved = boost::filesystem::canonical(filename); +#else + boost::filesystem::path resolved = filename; +#endif writeTime = boost::filesystem::last_write_time(resolved); std::cout << "content file: " << resolved << " timestamp = (" << writeTime << ") " << asctime(localtime(&writeTime)) << std::endl; } else { - std::cout << "content file: " << resolved << " not found" << std::endl; + std::cout << "content file: " << filename << " not found" << std::endl; } return writeTime; } \ No newline at end of file From 3158d34abb3da8f6a22a4ea7bbf962eb0ccb51f3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 25 Feb 2015 20:25:41 +0100 Subject: [PATCH 502/740] Fix for incorrect OpenCS verifier warning: pcvampire and pcwerewolf are not required, pcyear does not exist at all. --- apps/opencs/model/tools/tools.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 0c20bd17b..e78758bb6 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -58,9 +58,6 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier() mandatoryIds.push_back ("GameHour"); mandatoryIds.push_back ("Month"); mandatoryIds.push_back ("PCRace"); - mandatoryIds.push_back ("PCVampire"); - mandatoryIds.push_back ("PCWerewolf"); - mandatoryIds.push_back ("PCYear"); mVerifier->appendStage (new MandatoryIdStage (mData.getGlobals(), CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Globals), mandatoryIds)); From e7989a197d8e3b2d81d7aea63012f575a373ee4c Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 25 Feb 2015 20:32:11 +0100 Subject: [PATCH 503/740] Add defaults for some required globals (Fixes #2397) --- apps/openmw/mwworld/worldimp.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6462629f4..f78323be6 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -423,6 +423,19 @@ namespace MWWorld globals["werewolfclawmult"] = ESM::Variant(25.f); globals["pcknownwerewolf"] = ESM::Variant(0); + // following should exist in all versions of MW, but not necessarily in TCs + globals["gamehour"] = ESM::Variant(0.f); + globals["timescale"] = ESM::Variant(30.f); + globals["day"] = ESM::Variant(1); + globals["month"] = ESM::Variant(1); + globals["year"] = ESM::Variant(1); + globals["pcrace"] = ESM::Variant(0); + globals["pchascrimegold"] = ESM::Variant(0); + globals["pchasgolddiscount"] = ESM::Variant(0); + globals["crimegolddiscount"] = ESM::Variant(0); + globals["crimegoldturnin"] = ESM::Variant(0); + globals["pchasturnin"] = ESM::Variant(0); + for (std::map::iterator it = gmst.begin(); it != gmst.end(); ++it) { if (!mStore.get().search(it->first)) From 72e94380be20aab94e23d6503a2983f76d74e174 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 26 Feb 2015 20:07:23 +1300 Subject: [PATCH 504/740] fix: boost::filesystem::canonical() available from version 1.48. --- apps/mwiniimporter/importer.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 00774d798..efebe5a4d 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -885,10 +886,10 @@ std::time_t MwIniImporter::lastWriteTime(const boost::filesystem::path& filename std::time_t writeTime(defaultTime); if (boost::filesystem::exists(filename)) { - // FixMe: remove #if when Boost on Travis Linux updated - // Travis seems to be using older version of boost for Linux - // This should allow things to build until fixed -#if BOOST_FILESYSTEM_VERSION == 3 + // FixMe: remove #if when Boost dependency for Linux builds updated + // This allows Linux to build until then +#if (BOOST_VERSION >= 104800) + // need to resolve any symlinks so that we get time of file, not symlink boost::filesystem::path resolved = boost::filesystem::canonical(filename); #else boost::filesystem::path resolved = filename; From 1bb29f610fe25dff6ae26fba0310dfab407c2da7 Mon Sep 17 00:00:00 2001 From: sylar Date: Thu, 26 Feb 2015 18:29:38 +0400 Subject: [PATCH 505/740] enable mipmapping for Android again --- apps/openmw/mwrender/renderingmanager.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index b83a078ba..05b43d54f 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -120,14 +120,12 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b // Set default texture filtering options TextureFilterOptions tfo; std::string filter = Settings::Manager::getString("texture filtering", "General"); -#ifndef ANDROID + if (filter == "anisotropic") tfo = TFO_ANISOTROPIC; else if (filter == "trilinear") tfo = TFO_TRILINEAR; else if (filter == "bilinear") tfo = TFO_BILINEAR; else /*if (filter == "none")*/ tfo = TFO_NONE; -#else - tfo = TFO_NONE; -#endif + MaterialManager::getSingleton().setDefaultTextureFiltering(tfo); MaterialManager::getSingleton().setDefaultAnisotropy( (filter == "anisotropic") ? Settings::Manager::getInt("anisotropy", "General") : 1 ); From 70398e2f9f2a9a0701c0c401e0d3c43f187f9267 Mon Sep 17 00:00:00 2001 From: sylar Date: Thu, 26 Feb 2015 18:30:14 +0400 Subject: [PATCH 506/740] change Jni name method --- components/files/androidpath.cpp | 2 +- components/files/androidpath.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/files/androidpath.cpp b/components/files/androidpath.cpp index 117626095..009bd98a2 100644 --- a/components/files/androidpath.cpp +++ b/components/files/androidpath.cpp @@ -27,7 +27,7 @@ char const * Buffer::getData() } -JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_getPathToJni(JNIEnv *env, jobject obj, jstring prompt) +JNIEXPORT void JNICALL Java_ui_activity_GameActivity_getPathToJni(JNIEnv *env, jobject obj, jstring prompt) { jboolean iscopy; Buffer::setData((env)->GetStringUTFChars(prompt, &iscopy)); diff --git a/components/files/androidpath.h b/components/files/androidpath.h index 3157c067f..a93a160e0 100644 --- a/components/files/androidpath.h +++ b/components/files/androidpath.h @@ -1,8 +1,8 @@ /* DO NOT EDIT THIS FILE - it is machine generated */ #include -#ifndef _Included_org_libsdl_app_SDLActivity_getPathToJni -#define _Included_org_libsdl_app_SDLActivity_getPathToJni +#ifndef _Included_ui_activity_GameActivity_getPathToJni +#define _Included_ui_activity_GameActivity_getPathToJni #ifdef __cplusplus extern "C" { #endif @@ -11,7 +11,7 @@ extern "C" { * Method: getPathToJni * Signature: (I)I */ -JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_getPathToJni(JNIEnv *env, jobject obj, jstring prompt); +JNIEXPORT void JNICALL Java_ui_activity_GameActivity_getPathToJni(JNIEnv *env, jobject obj, jstring prompt); #ifdef __cplusplus } From cda3782cf2d8185896c8139df015d1c76ddb0efb Mon Sep 17 00:00:00 2001 From: sylar Date: Thu, 26 Feb 2015 18:30:38 +0400 Subject: [PATCH 507/740] fix crash game on Android after start loading --- apps/openmw/mwworld/refdata.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index da7986ba0..e90b44f9c 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -33,11 +33,11 @@ namespace MWWorld MWScript::Locals mLocals; // if we find the overhead of heaving a locals // object in the refdata of refs without a script, // we can make this a pointer later. + bool mDeleted; // separate delete flag used for deletion by a content file bool mHasLocals; bool mEnabled; int mCount; // 0: deleted - bool mDeleted; // separate delete flag used for deletion by a content file ESM::Position mPosition; From cef725012c03f921b0dce68d15953cf4b050be15 Mon Sep 17 00:00:00 2001 From: sylar Date: Fri, 27 Feb 2015 08:56:20 +0400 Subject: [PATCH 508/740] fix transpose error fo gles2 --- files/materials/objects.shader | 17 ++++++++++++++--- files/materials/terrain.shader | 15 +++++++++++++-- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 2368d9961..ab693eb39 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -243,7 +243,9 @@ } #else - +#if NORMAL_MAP && SH_GLSLES + mat3 transpose( mat3 m); +#endif // ----------------------------------- FRAGMENT ------------------------------------------ #if UNDERWATER @@ -376,13 +378,13 @@ float3 binormal = cross(tangentPassthrough.xyz, normal.xyz); float3x3 tbn = float3x3(tangentPassthrough.xyz, binormal, normal.xyz); - #if SH_GLSL + #if SH_GLSL || SH_GLSLES tbn = transpose(tbn); #endif float4 normalTex = shSample(normalMap, UV.xy); - normal = normalize (shMatrixMult( transpose(tbn), normalTex.xyz * 2 - 1 )); + normal = normalize (shMatrixMult( transpose(tbn), normalTex.xyz * 2.0 - float (1.0,1.0,1.0) )); #endif #if ENV_MAP || SPECULAR || PARALLAX @@ -576,5 +578,14 @@ // prevent negative colour output (for example with negative lights) shOutputColour(0).xyz = max(shOutputColour(0).xyz, float3(0.0,0.0,0.0)); } +#if NORMAL_MAP && SH_GLSLES + mat3 transpose(mat3 m){ + return mat3( + m[0][0],m[1][0],m[2][0], + m[0][1],m[1][1],m[2][1], + m[0][2],m[1][2],m[2][2] + ); + } +#endif #endif diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index a4ca10fcc..9bb5d247d 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -221,6 +221,9 @@ #if UNDERWATER #include "underwater.h" #endif +#if NORMAL_MAP && SH_GLSLES + mat3 transpose(mat3 m); +#endif SH_BEGIN_PROGRAM @@ -319,7 +322,7 @@ shUniform(float4, cameraPos) @shAutoConstant(cameraPos, camera_position) // derive final matrix float3x3 tbn = float3x3(tangent, binormal, normal); - #if SH_GLSL + #if SH_GLSL || SH_GLSLES tbn = transpose(tbn); #endif #endif @@ -492,5 +495,13 @@ albedo = shLerp(albedo, diffuseTex, blendValues@shPropertyString(blendmap_compon shOutputColour(0).a = 1.0-previousAlpha; #endif } - +#if NORMAL_MAP && SH_GLSLES + mat3 transpose(mat3 m){ + return mat3( + m[0][0],m[1][0],m[2][0], + m[0][1],m[1][1],m[2][1], + m[0][2],m[1][2],m[2][2] + ); + } +#endif #endif From edd3f9f95c8256710f8063afcb10eb7f1f610043 Mon Sep 17 00:00:00 2001 From: sylar Date: Fri, 27 Feb 2015 08:58:00 +0400 Subject: [PATCH 509/740] small fix for float --- files/materials/objects.shader | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/materials/objects.shader b/files/materials/objects.shader index ab693eb39..828674cc7 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -384,7 +384,7 @@ float4 normalTex = shSample(normalMap, UV.xy); - normal = normalize (shMatrixMult( transpose(tbn), normalTex.xyz * 2.0 - float (1.0,1.0,1.0) )); + normal = normalize (shMatrixMult( transpose(tbn), normalTex.xyz * 2.0 - float3 (1.0,1.0,1.0) )); #endif #if ENV_MAP || SPECULAR || PARALLAX From 1e4a845b6f7bded5f8ff6ab7465f3cef0847df42 Mon Sep 17 00:00:00 2001 From: Digmaster Date: Sat, 20 Dec 2014 14:46:11 -0600 Subject: [PATCH 510/740] Minor code cleanup --- CMakeLists.txt | 3 ++ apps/openmw/mwbase/inputmanager.hpp | 6 +++- apps/openmw/mwinput/inputmanagerimp.cpp | 40 +++++++++++++++++++-- apps/openmw/mwinput/inputmanagerimp.hpp | 15 +++++--- apps/openmw/mwscript/interpretercontext.cpp | 12 +++++-- extern/oics/ICSInputControlSystem.cpp | 36 +------------------ extern/oics/ICSInputControlSystem.h | 3 +- files/CMakeLists.txt | 6 ---- 8 files changed, 68 insertions(+), 53 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5a923c631..d8872e162 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -379,6 +379,9 @@ configure_file(${OpenMW_SOURCE_DIR}/files/opencs.ini configure_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") + if (NOT WIN32 AND NOT APPLE) configure_file(${OpenMW_SOURCE_DIR}/files/openmw.desktop "${OpenMW_BINARY_DIR}/openmw.desktop") diff --git a/apps/openmw/mwbase/inputmanager.hpp b/apps/openmw/mwbase/inputmanager.hpp index 3ffa7148a..59b4e3b77 100644 --- a/apps/openmw/mwbase/inputmanager.hpp +++ b/apps/openmw/mwbase/inputmanager.hpp @@ -46,10 +46,14 @@ namespace MWBase ///Actions available for binding to controller buttons virtual std::vector getActionControllerSorting() = 0; virtual int getNumActions() = 0; - ///If keyboard is true, only pay attention to keyboard events. If false, only pay attention to cntroller events (excluding esc) + ///If keyboard is true, only pay attention to keyboard events. If false, only pay attention to controller events (excluding esc) virtual void enableDetectingBindingMode (int action, bool keyboard) = 0; virtual void resetToDefaultKeyBindings() = 0; virtual void resetToDefaultControllerBindings() = 0; + + /// Returns if the last used input device was a joystick or a keyboard + /// @return true if joystick, false otherwise + virtual bool joystickLastUsed() = 0; }; } diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 3d1239f54..180d371cf 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -124,6 +124,7 @@ namespace MWInput , mAttemptJump(false) , mControlsDisabled(false) , mJoystickLastUsed(false) + , mDetectingKeyboard(false) { Ogre::RenderWindow* window = ogre.getWindow (); @@ -135,8 +136,7 @@ namespace MWInput mInputManager->setControllerEventCallback(this); std::string file = userFileExists ? userFile : ""; - std::string controllerdb = Settings::Manager::getString("gamecontrollerdb file", "Input"); - mInputBinder = new ICS::InputControlSystem(file, true, this, NULL, controllerdb, A_Last); + mInputBinder = new ICS::InputControlSystem(file, true, this, NULL, A_Last); adjustMouseRegion (window->getWidth(), window->getHeight()); loadKeyDefaults(); @@ -154,6 +154,42 @@ namespace MWInput mControlSwitch["playermagic"] = true; mControlSwitch["playerviewswitch"] = true; mControlSwitch["vanitymode"] = true; + + /* Joystick Init */ + + //Load controller mappings +#if SDL_VERSION_ATLEAST(2,0,2) + Files::ConfigurationManager cfgMgr; + std::string db = cfgMgr.getLocalPath().string() + "/gamecontrollerdb.txt"; + if(boost::filesystem::exists(db)) + { + int res = SDL_GameControllerAddMappingsFromFile(db.c_str()); + if(res == -1) + { + //ICS_LOG(std::string("Error loading controller bindings: ")+SDL_GetError()); + } + else + { + //ICS_LOG(std::string("Loaded ")+boost::lexical_cast(res)+" Game controller bindings"); + } + } +#endif + + //Open all presently connected sticks + int numSticks = SDL_NumJoysticks(); + for(int i = 0; i < numSticks; i++) + { + if(SDL_IsGameController(i)) + { + SDL_ControllerDeviceEvent evt; + evt.which = i; + controllerAdded(evt); + } + else + { + //ICS_LOG(std::string("Unusable controller plugged in: ")+SDL_JoystickNameForIndex(i)); + } + } } void InputManager::clear() diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 61dbf18f8..df490ea00 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -4,6 +4,7 @@ #include "../mwgui/mode.hpp" #include +#include #include "../mwbase/inputmanager.hpp" #include @@ -41,6 +42,11 @@ namespace MyGUI class MouseButton; } +namespace Files +{ + struct ConfigurationManager; +} + #include #include @@ -85,8 +91,6 @@ namespace MWInput virtual std::string getActionDescription (int action); virtual std::string getActionKeyBindingName (int action); virtual std::string getActionControllerBindingName (int action); - virtual std::string sdlControllerAxisToString(int axis); - virtual std::string sdlControllerButtonToString(int button); virtual int getNumActions() { return A_Last; } virtual std::vector getActionKeySorting(); virtual std::vector getActionControllerSorting(); @@ -94,6 +98,8 @@ namespace MWInput virtual void resetToDefaultKeyBindings(); virtual void resetToDefaultControllerBindings(); + virtual bool joystickLastUsed() {return mJoystickLastUsed;} + public: virtual void keyPressed(const SDL_KeyboardEvent &arg ); virtual void keyReleased( const SDL_KeyboardEvent &arg ); @@ -181,6 +187,9 @@ namespace MWInput void adjustMouseRegion(int width, int height); MyGUI::MouseButton sdlButtonToMyGUI(Uint8 button); + virtual std::string sdlControllerAxisToString(int axis); + virtual std::string sdlControllerButtonToString(int button); + void resetIdleTime(); void updateIdleTime(float dt); @@ -201,8 +210,6 @@ namespace MWInput void quickLoad(); void quickSave(); - bool isAReverse(int action); - void quickKey (int index); void showQuickKeysMenu(); diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index b71e92555..f4e637a59 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -268,15 +268,21 @@ namespace MWScript std::string InterpreterContext::getActionBinding(const std::string& action) const { - std::vector actions = MWBase::Environment::get().getInputManager()->getActionKeySorting (); + MWBase::InputManager* input = MWBase::Environment::get().getInputManager(); + std::vector actions = input->getActionKeySorting (); for (std::vector::const_iterator it = actions.begin(); it != actions.end(); ++it) { - std::string desc = MWBase::Environment::get().getInputManager()->getActionDescription (*it); + std::string desc = input->getActionDescription (*it); if(desc == "") continue; if(desc == action) - return MWBase::Environment::get().getInputManager()->getActionKeyBindingName (*it); + { + if(input->joystickLastUsed()) + return input->getActionControllerBindingName(*it); + else + return input->getActionKeyBindingName (*it); + } } return "None"; diff --git a/extern/oics/ICSInputControlSystem.cpp b/extern/oics/ICSInputControlSystem.cpp index a8efd54bc..a38b46e98 100644 --- a/extern/oics/ICSInputControlSystem.cpp +++ b/extern/oics/ICSInputControlSystem.cpp @@ -30,7 +30,7 @@ namespace ICS { InputControlSystem::InputControlSystem(std::string file, bool active , DetectingBindingListener* detectingBindingListener - , InputControlSystemLog* log, std::string controllerdb, size_t channelCount) + , InputControlSystemLog* log, size_t channelCount) : mFileName(file) , mDetectingBindingListener(detectingBindingListener) , mDetectingBindingControl(NULL) @@ -273,40 +273,6 @@ namespace ICS } delete xmlDoc; - } - - /* Joystick Init */ - - //Load controller mappings -#if SDL_VERSION_ATLEAST(2,0,2) - if(!controllerdb.empty()) - { - int res = SDL_GameControllerAddMappingsFromFile(controllerdb.c_str()); - if(res == -1) - { - ICS_LOG(std::string("Error loading controller bindings: ")+SDL_GetError()); - } - else - { - ICS_LOG(std::string("Loaded ")+boost::lexical_cast(res)+" Game controller bindings"); - } - } -#endif - - //Open all presently connected sticks - int numSticks = SDL_NumJoysticks(); - for(int i = 0; i < numSticks; i++) - { - if(SDL_IsGameController(i)) - { - SDL_ControllerDeviceEvent evt; - evt.which = i; - controllerAdded(evt); - } - else - { - ICS_LOG(std::string("Unusable controller plugged in: ")+SDL_JoystickNameForIndex(i)); - } } ICS_LOG(" - InputControlSystem Created - "); diff --git a/extern/oics/ICSInputControlSystem.h b/extern/oics/ICSInputControlSystem.h index f58d242fc..0bdd67b34 100644 --- a/extern/oics/ICSInputControlSystem.h +++ b/extern/oics/ICSInputControlSystem.h @@ -74,8 +74,7 @@ namespace ICS InputControlSystem(std::string file = "", bool active = true , DetectingBindingListener* detectingBindingListener = NULL - , InputControlSystemLog* log = NULL, std::string controllerdb = "" - , size_t channelCount = 16); + , InputControlSystemLog* log = NULL, size_t channelCount = 16); ~InputControlSystem(); std::string getFileName(){ return mFileName; }; diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt index 4635cbfa4..9b2325744 100644 --- a/files/CMakeLists.txt +++ b/files/CMakeLists.txt @@ -49,12 +49,6 @@ set(MATERIAL_FILES mygui.shaderset ) -set(ETC_FILES - gamecontrollerdb.txt -) - copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/water "${OpenMW_BINARY_DIR}/resources/water/" "${WATER_FILES}") copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/materials "${OpenMW_BINARY_DIR}/resources/materials/" "${MATERIAL_FILES}") - -copy_all_files(${CMAKE_CURRENT_SOURCE_DIR} "${OpenMW_BINARY_DIR}/resources/" "${ETC_FILES}") From e3e6190b85c5ce274c7f2b2ca90d53ee56d8b50c Mon Sep 17 00:00:00 2001 From: Digmaster Date: Mon, 19 Jan 2015 15:36:15 -0600 Subject: [PATCH 511/740] Added multiple joystick support in ICS. Will fix other issues shortly --- apps/openmw/mwinput/inputmanagerimp.cpp | 53 ++-- apps/openmw/mwinput/inputmanagerimp.hpp | 16 +- extern/oics/ICSInputControlSystem.cpp | 90 +++---- extern/oics/ICSInputControlSystem.h | 44 ++-- .../oics/ICSInputControlSystem_joystick.cpp | 232 ++++++++++-------- extern/sdl4ogre/events.h | 10 +- extern/sdl4ogre/sdlinputwrapper.cpp | 8 +- 7 files changed, 245 insertions(+), 208 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 180d371cf..7b8580080 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -125,6 +125,7 @@ namespace MWInput , mControlsDisabled(false) , mJoystickLastUsed(false) , mDetectingKeyboard(false) + , mFakeDeviceID(1) { Ogre::RenderWindow* window = ogre.getWindow (); @@ -183,7 +184,7 @@ namespace MWInput { SDL_ControllerDeviceEvent evt; evt.which = i; - controllerAdded(evt); + controllerAdded(mFakeDeviceID, evt); } else { @@ -768,7 +769,7 @@ namespace MWInput } } - void InputManager::buttonPressed( const SDL_ControllerButtonEvent &arg ) + void InputManager::buttonPressed(int deviceID, const SDL_ControllerButtonEvent &arg ) { mJoystickLastUsed = true; bool guiMode = false; @@ -798,14 +799,14 @@ namespace MWInput setPlayerControlsEnabled(!guiFocus); if (!mControlsDisabled) - mInputBinder->buttonPressed(arg); + mInputBinder->buttonPressed(deviceID, arg); } - void InputManager::buttonReleased( const SDL_ControllerButtonEvent &arg ) + void InputManager::buttonReleased(int deviceID, const SDL_ControllerButtonEvent &arg ) { mJoystickLastUsed = true; if(mInputBinder->detectingBindingState()) - mInputBinder->buttonReleased(arg); + mInputBinder->buttonReleased(deviceID, arg); else if(arg.button == SDL_CONTROLLER_BUTTON_A || arg.button == SDL_CONTROLLER_BUTTON_B) { bool guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); @@ -814,26 +815,26 @@ namespace MWInput if(mInputBinder->detectingBindingState()) return; // don't allow same mouseup to bind as initiated bind setPlayerControlsEnabled(!guiMode); - mInputBinder->buttonReleased(arg); + mInputBinder->buttonReleased(deviceID, arg); } else - mInputBinder->buttonReleased(arg); + mInputBinder->buttonReleased(deviceID, arg); //to escape inital movie OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); } - void InputManager::axisMoved( const SDL_ControllerAxisEvent &arg ) + void InputManager::axisMoved(int deviceID, const SDL_ControllerAxisEvent &arg ) { mJoystickLastUsed = true; if (!mControlsDisabled) - mInputBinder->axisMoved(arg); + mInputBinder->axisMoved(deviceID, arg); } - void InputManager::controllerAdded(const SDL_ControllerDeviceEvent &arg) + void InputManager::controllerAdded(int deviceID, const SDL_ControllerDeviceEvent &arg) { - mInputBinder->controllerAdded(arg); + mInputBinder->controllerAdded(deviceID, arg); } void InputManager::controllerRemoved(const SDL_ControllerDeviceEvent &arg) { @@ -1221,20 +1222,20 @@ namespace MWInput control = mInputBinder->getChannel(i)->getAttachedControls ().front().control; } - if (!controlExists || force || ( mInputBinder->getJoystickAxisBinding (control, ICS::Control::INCREASE) == ICS::InputControlSystem::UNASSIGNED && mInputBinder->getJoystickButtonBinding (control, ICS::Control::INCREASE) == ICS_MAX_DEVICE_BUTTONS )) + if (!controlExists || force || ( mInputBinder->getJoystickAxisBinding (control, mFakeDeviceID, ICS::Control::INCREASE) == ICS::InputControlSystem::UNASSIGNED && mInputBinder->getJoystickButtonBinding (control, mFakeDeviceID, ICS::Control::INCREASE) == ICS_MAX_DEVICE_BUTTONS )) { clearAllControllerBindings(control); if (defaultButtonBindings.find(i) != defaultButtonBindings.end()) { control->setInitialValue(0.0f); - mInputBinder->addJoystickButtonBinding(control, defaultButtonBindings[i], ICS::Control::INCREASE); + mInputBinder->addJoystickButtonBinding(control, mFakeDeviceID, defaultButtonBindings[i], ICS::Control::INCREASE); } else if (defaultAxisBindings.find(i) != defaultAxisBindings.end()) { control->setValue(0.5f); control->setInitialValue(0.5f); - mInputBinder->addJoystickAxisBinding(control, defaultAxisBindings[i], ICS::Control::INCREASE); + mInputBinder->addJoystickAxisBinding(control, mFakeDeviceID, defaultAxisBindings[i], ICS::Control::INCREASE); } } } @@ -1307,10 +1308,10 @@ namespace MWInput ICS::Control* c = mInputBinder->getChannel (action)->getAttachedControls ().front().control; - if (mInputBinder->getJoystickAxisBinding (c, ICS::Control::INCREASE) != ICS::InputControlSystem::UNASSIGNED) - return sdlControllerAxisToString(mInputBinder->getJoystickAxisBinding (c, ICS::Control::INCREASE)); - else if (mInputBinder->getJoystickButtonBinding (c, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS ) - return sdlControllerButtonToString(mInputBinder->getJoystickButtonBinding (c, ICS::Control::INCREASE)); + if (mInputBinder->getJoystickAxisBinding (c, mFakeDeviceID, ICS::Control::INCREASE) != ICS::InputControlSystem::UNASSIGNED) + return sdlControllerAxisToString(mInputBinder->getJoystickAxisBinding (c, mFakeDeviceID, ICS::Control::INCREASE)); + else if (mInputBinder->getJoystickButtonBinding (c, mFakeDeviceID, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS ) + return sdlControllerButtonToString(mInputBinder->getJoystickButtonBinding (c, mFakeDeviceID, ICS::Control::INCREASE)); else return "#{sNone}"; } @@ -1489,7 +1490,7 @@ namespace MWInput MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); } - void InputManager::joystickAxisBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control + void InputManager::joystickAxisBindingDetected(ICS::InputControlSystem* ICS, int deviceID, ICS::Control* control , int axis, ICS::Control::ControlChangingDirection direction) { //only allow binding to the trigers @@ -1501,18 +1502,18 @@ namespace MWInput clearAllControllerBindings(control); control->setValue(0.5f); //axis bindings must start at 0.5 control->setInitialValue(0.5f); - ICS::DetectingBindingListener::joystickAxisBindingDetected (ICS, control, axis, direction); + ICS::DetectingBindingListener::joystickAxisBindingDetected (ICS, deviceID, control, axis, direction); MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); } - void InputManager::joystickButtonBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control + void InputManager::joystickButtonBindingDetected(ICS::InputControlSystem* ICS, int deviceID, ICS::Control* control , unsigned int button, ICS::Control::ControlChangingDirection direction) { if(mDetectingKeyboard) return; clearAllControllerBindings(control); control->setInitialValue(0.0f); - ICS::DetectingBindingListener::joystickButtonBindingDetected (ICS, control, button, direction); + ICS::DetectingBindingListener::joystickButtonBindingDetected (ICS, deviceID, control, button, direction); MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); } @@ -1528,10 +1529,10 @@ namespace MWInput void InputManager::clearAllControllerBindings (ICS::Control* control) { // right now we don't really need multiple bindings for the same action, so remove all others first - if (mInputBinder->getJoystickAxisBinding (control, ICS::Control::INCREASE) != SDL_SCANCODE_UNKNOWN) - mInputBinder->removeJoystickAxisBinding (mInputBinder->getJoystickAxisBinding (control, ICS::Control::INCREASE)); - if (mInputBinder->getJoystickButtonBinding (control, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS) - mInputBinder->removeJoystickButtonBinding (mInputBinder->getJoystickButtonBinding (control, ICS::Control::INCREASE)); + if (mInputBinder->getJoystickAxisBinding (control, mFakeDeviceID, ICS::Control::INCREASE) != SDL_SCANCODE_UNKNOWN) + mInputBinder->removeJoystickAxisBinding (mFakeDeviceID, mInputBinder->getJoystickAxisBinding (control, mFakeDeviceID, ICS::Control::INCREASE)); + if (mInputBinder->getJoystickButtonBinding (control, mFakeDeviceID, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS) + mInputBinder->removeJoystickButtonBinding (mFakeDeviceID, mInputBinder->getJoystickButtonBinding (control, mFakeDeviceID, ICS::Control::INCREASE)); } void InputManager::resetToDefaultKeyBindings() diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index df490ea00..e8ee955e2 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -109,11 +109,11 @@ namespace MWInput virtual void mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id ); virtual void mouseMoved( const SFO::MouseMotionEvent &arg ); - virtual void buttonPressed( const SDL_ControllerButtonEvent &arg); - virtual void buttonReleased( const SDL_ControllerButtonEvent &arg); - virtual void axisMoved( const SDL_ControllerAxisEvent &arg); - virtual void controllerAdded( const SDL_ControllerDeviceEvent &arg); - virtual void controllerRemoved( const SDL_ControllerDeviceEvent &arg); + virtual void buttonPressed(int deviceID, const SDL_ControllerButtonEvent &arg); + virtual void buttonReleased(int deviceID, const SDL_ControllerButtonEvent &arg); + virtual void axisMoved(int deviceID, const SDL_ControllerAxisEvent &arg); + virtual void controllerAdded(int deviceID, const SDL_ControllerDeviceEvent &arg); + virtual void controllerRemoved(const SDL_ControllerDeviceEvent &arg); virtual void windowVisibilityChange( bool visible ); virtual void windowFocusChange( bool have_focus ); @@ -131,10 +131,10 @@ namespace MWInput virtual void mouseButtonBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control , unsigned int button, ICS::Control::ControlChangingDirection direction); - virtual void joystickAxisBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control + virtual void joystickAxisBindingDetected(ICS::InputControlSystem* ICS, int deviceID, ICS::Control* control , int axis, ICS::Control::ControlChangingDirection direction); - virtual void joystickButtonBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control + virtual void joystickButtonBindingDetected(ICS::InputControlSystem* ICS, int deviceID, ICS::Control* control , unsigned int button, ICS::Control::ControlChangingDirection direction); void clearAllKeyBindings (ICS::Control* control); @@ -218,6 +218,8 @@ namespace MWInput void loadKeyDefaults(bool force = false); void loadControllerDefaults(bool force = false); + int mFakeDeviceID; //As we only support one controller at a time, use a fake deviceID so we don't lose bindings when switching controllers + private: enum Actions { diff --git a/extern/oics/ICSInputControlSystem.cpp b/extern/oics/ICSInputControlSystem.cpp index a38b46e98..95adb247e 100644 --- a/extern/oics/ICSInputControlSystem.cpp +++ b/extern/oics/ICSInputControlSystem.cpp @@ -536,65 +536,71 @@ namespace ICS } binder.SetAttribute( "direction", "DECREASE" ); control.InsertEndChild(binder); - } - if(getJoystickAxisBinding(*o, Control/*::ControlChangingDirection*/::INCREASE) - != /*NamedAxis::*/UNASSIGNED) - { - TiXmlElement binder( "JoystickAxisBinder" ); - - binder.SetAttribute( "axis", ToString( - getJoystickAxisBinding(*o, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); - - binder.SetAttribute( "direction", "INCREASE" ); + } + JoystickIDList::const_iterator it = mJoystickIDList.begin(); + while(it!=mJoystickIDList.end()) + { + int deviceID = *it; + if(getJoystickAxisBinding(*o, deviceID, Control/*::ControlChangingDirection*/::INCREASE) + != /*NamedAxis::*/UNASSIGNED) + { + TiXmlElement binder( "JoystickAxisBinder" ); + + binder.SetAttribute( "axis", ToString( + getJoystickAxisBinding(*o, deviceID, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); + + binder.SetAttribute( "direction", "INCREASE" ); - binder.SetAttribute( "deviceId", "1" ); //completely useless, but required for backwards compatability + binder.SetAttribute( "deviceId", deviceID ); //completely useless, but required for backwards compatability - control.InsertEndChild(binder); - } + control.InsertEndChild(binder); + } - if(getJoystickAxisBinding(*o, Control/*::ControlChangingDirection*/::DECREASE) - != /*NamedAxis::*/UNASSIGNED) - { - TiXmlElement binder( "JoystickAxisBinder" ); + if(getJoystickAxisBinding(*o, deviceID, Control/*::ControlChangingDirection*/::DECREASE) + != /*NamedAxis::*/UNASSIGNED) + { + TiXmlElement binder( "JoystickAxisBinder" ); - binder.SetAttribute( "axis", ToString( - getJoystickAxisBinding(*o, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); + binder.SetAttribute( "axis", ToString( + getJoystickAxisBinding(*o, deviceID, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); - binder.SetAttribute( "direction", "DECREASE" ); + binder.SetAttribute( "direction", "DECREASE" ); - binder.SetAttribute( "deviceId", "1" ); //completely useless, but required for backwards compatability + binder.SetAttribute( "deviceId", deviceID ); //completely useless, but required for backwards compatability - control.InsertEndChild(binder); - } + control.InsertEndChild(binder); + } - if(getJoystickButtonBinding(*o, Control/*::ControlChangingDirection*/::INCREASE) - != ICS_MAX_DEVICE_BUTTONS) - { - TiXmlElement binder( "JoystickButtonBinder" ); + if(getJoystickButtonBinding(*o, deviceID, Control/*::ControlChangingDirection*/::INCREASE) + != ICS_MAX_DEVICE_BUTTONS) + { + TiXmlElement binder( "JoystickButtonBinder" ); - binder.SetAttribute( "button", ToString( - getJoystickButtonBinding(*o, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); + binder.SetAttribute( "button", ToString( + getJoystickButtonBinding(*o, deviceID, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); - binder.SetAttribute( "direction", "INCREASE" ); + binder.SetAttribute( "direction", "INCREASE" ); - binder.SetAttribute( "deviceId", "1" ); //completely useless, but required for backwards compatability + binder.SetAttribute( "deviceId", deviceID ); //completely useless, but required for backwards compatability - control.InsertEndChild(binder); - } + control.InsertEndChild(binder); + } - if(getJoystickButtonBinding(*o, Control/*::ControlChangingDirection*/::DECREASE) - != ICS_MAX_DEVICE_BUTTONS) - { - TiXmlElement binder( "JoystickButtonBinder" ); + if(getJoystickButtonBinding(*o, deviceID, Control/*::ControlChangingDirection*/::DECREASE) + != ICS_MAX_DEVICE_BUTTONS) + { + TiXmlElement binder( "JoystickButtonBinder" ); - binder.SetAttribute( "button", ToString( - getJoystickButtonBinding(*o, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); + binder.SetAttribute( "button", ToString( + getJoystickButtonBinding(*o, deviceID, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); - binder.SetAttribute( "direction", "DECREASE" ); + binder.SetAttribute( "direction", "DECREASE" ); - binder.SetAttribute( "deviceId", "1" ); //completely useless, but required for backwards compatability + binder.SetAttribute( "deviceId", deviceID ); //completely useless, but required for backwards compatability - control.InsertEndChild(binder); + control.InsertEndChild(binder); + } + it++; } diff --git a/extern/oics/ICSInputControlSystem.h b/extern/oics/ICSInputControlSystem.h index 0bdd67b34..51b701b48 100644 --- a/extern/oics/ICSInputControlSystem.h +++ b/extern/oics/ICSInputControlSystem.h @@ -64,7 +64,8 @@ namespace ICS typedef NamedAxis MouseAxis; // MouseAxis is deprecated. It will be removed in future versions - typedef std::map JoystickIDList; + typedef std::map JoystickInstanceMap; + typedef std::list JoystickIDList; typedef struct { @@ -100,9 +101,10 @@ namespace ICS inline void activate(){ this->mActive = true; }; inline void deactivate(){ this->mActive = false; }; - void controllerAdded (const SDL_ControllerDeviceEvent &args); + void controllerAdded (int deviceID, const SDL_ControllerDeviceEvent &args); void controllerRemoved(const SDL_ControllerDeviceEvent &args); - JoystickIDList& getJoystickIdList(){ return mJoystickIDList; }; + JoystickIDList& getJoystickIdList(){ return mJoystickIDList; }; + JoystickInstanceMap& getJoystickInstanceMap(){ return mJoystickInstanceMap; }; // MouseListener void mouseMoved(const SFO::MouseMotionEvent &evt); @@ -114,28 +116,28 @@ namespace ICS void keyReleased(const SDL_KeyboardEvent &evt); // ControllerListener - void buttonPressed(const SDL_ControllerButtonEvent &evt); - void buttonReleased(const SDL_ControllerButtonEvent &evt); - void axisMoved(const SDL_ControllerAxisEvent &evt); + void buttonPressed(int deviceID, const SDL_ControllerButtonEvent &evt); + void buttonReleased(int deviceID, const SDL_ControllerButtonEvent &evt); + void axisMoved(int deviceID, const SDL_ControllerAxisEvent &evt); void addKeyBinding(Control* control, SDL_Scancode key, Control::ControlChangingDirection direction); bool isKeyBound(SDL_Scancode key) const; void addMouseAxisBinding(Control* control, NamedAxis axis, Control::ControlChangingDirection direction); void addMouseButtonBinding(Control* control, unsigned int button, Control::ControlChangingDirection direction); bool isMouseButtonBound(unsigned int button) const; - void addJoystickAxisBinding(Control* control, int axis, Control::ControlChangingDirection direction); - void addJoystickButtonBinding(Control* control, unsigned int button, Control::ControlChangingDirection direction); + void addJoystickAxisBinding(Control* control, int deviceID, int axis, Control::ControlChangingDirection direction); + void addJoystickButtonBinding(Control* control, int deviceID, unsigned int button, Control::ControlChangingDirection direction); void removeKeyBinding(SDL_Scancode key); void removeMouseAxisBinding(NamedAxis axis); void removeMouseButtonBinding(unsigned int button); - void removeJoystickAxisBinding(int axis); - void removeJoystickButtonBinding(unsigned int button); + void removeJoystickAxisBinding(int deviceID, int axis); + void removeJoystickButtonBinding(int deviceID, unsigned int button); SDL_Scancode getKeyBinding(Control* control, ICS::Control::ControlChangingDirection direction); NamedAxis getMouseAxisBinding(Control* control, ICS::Control::ControlChangingDirection direction); unsigned int getMouseButtonBinding(Control* control, ICS::Control::ControlChangingDirection direction); - int getJoystickAxisBinding(Control* control, ICS::Control::ControlChangingDirection direction); - unsigned int getJoystickButtonBinding(Control* control, ICS::Control::ControlChangingDirection direction); + int getJoystickAxisBinding(Control* control, int deviceID, ICS::Control::ControlChangingDirection direction); + unsigned int getJoystickButtonBinding(Control* control, int deviceID, ICS::Control::ControlChangingDirection direction); std::string scancodeToString(SDL_Scancode key); @@ -183,14 +185,15 @@ namespace ICS typedef std::map ControlsKeyBinderMapType; // typedef std::map ControlsAxisBinderMapType; // - typedef std::map ControlsButtonBinderMapType; // - typedef std::map ControlsPOVBinderMapType; // - typedef std::map ControlsSliderBinderMapType; // + typedef std::map ControlsButtonBinderMapType; // + + typedef std::map JoystickAxisBinderMapType; // > + typedef std::map JoystickButtonBinderMapType; // > ControlsAxisBinderMapType mControlsMouseAxisBinderMap; // ControlsButtonBinderMapType mControlsMouseButtonBinderMap; // - ControlsAxisBinderMapType mControlsJoystickAxisBinderMap; // - ControlsButtonBinderMapType mControlsJoystickButtonBinderMap; // + JoystickAxisBinderMapType mControlsJoystickAxisBinderMap; // + JoystickButtonBinderMapType mControlsJoystickButtonBinderMap; // std::vector mControls; std::vector mChannels; @@ -207,7 +210,8 @@ namespace ICS bool mXmouseAxisBinded; bool mYmouseAxisBinded; - JoystickIDList mJoystickIDList; + JoystickIDList mJoystickIDList; + JoystickInstanceMap mJoystickInstanceMap; int mMouseAxisBindingInitialValues[3]; @@ -229,10 +233,10 @@ namespace ICS virtual void mouseButtonBindingDetected(InputControlSystem* ICS, Control* control , unsigned int button, Control::ControlChangingDirection direction); - virtual void joystickAxisBindingDetected(InputControlSystem* ICS, Control* control + virtual void joystickAxisBindingDetected(InputControlSystem* ICS, int deviceID, Control* control , int axis, Control::ControlChangingDirection direction); - virtual void joystickButtonBindingDetected(InputControlSystem* ICS, Control* control + virtual void joystickButtonBindingDetected(InputControlSystem* ICS, int deviceID, Control* control , unsigned int button, Control::ControlChangingDirection direction); }; diff --git a/extern/oics/ICSInputControlSystem_joystick.cpp b/extern/oics/ICSInputControlSystem_joystick.cpp index d8dbfa112..ab219d074 100644 --- a/extern/oics/ICSInputControlSystem_joystick.cpp +++ b/extern/oics/ICSInputControlSystem_joystick.cpp @@ -48,7 +48,7 @@ namespace ICS dir = Control::DECREASE; } - addJoystickAxisBinding(mControls.back(), FromString(xmlJoystickBinder->Attribute("axis")), dir); + addJoystickAxisBinding(mControls.back(), FromString(xmlJoystickBinder->Attribute("deviceId")), FromString(xmlJoystickBinder->Attribute("axis")), dir); xmlJoystickBinder = xmlJoystickBinder->NextSiblingElement("JoystickAxisBinder"); } @@ -69,170 +69,193 @@ namespace ICS dir = Control::DECREASE; } - addJoystickButtonBinding(mControls.back(), FromString(xmlJoystickButtonBinder->Attribute("button")), dir); + addJoystickButtonBinding(mControls.back(), FromString(xmlJoystickButtonBinder->Attribute("deviceId")), FromString(xmlJoystickButtonBinder->Attribute("button")), dir); xmlJoystickButtonBinder = xmlJoystickButtonBinder->NextSiblingElement("JoystickButtonBinder"); } } // add bindings - void InputControlSystem::addJoystickAxisBinding(Control* control, int axis, Control::ControlChangingDirection direction) + void InputControlSystem::addJoystickAxisBinding(Control* control, int deviceID, int axis, Control::ControlChangingDirection direction) { ICS_LOG("\tAdding AxisBinder [axis=" - + ToString(axis) + ", direction=" - + ToString(direction) + "]"); + + ToString(axis) + ", deviceID=" + + ToString(deviceID) + ", direction=" + + ToString(direction) + "]"); control->setValue(0.5f); //all joystick axis start at .5, so do that ControlAxisBinderItem controlAxisBinderItem; controlAxisBinderItem.control = control; controlAxisBinderItem.direction = direction; - mControlsJoystickAxisBinderMap[ axis ] = controlAxisBinderItem; + mControlsJoystickAxisBinderMap[deviceID][axis] = controlAxisBinderItem; } - void InputControlSystem::addJoystickButtonBinding(Control* control, unsigned int button, Control::ControlChangingDirection direction) + void InputControlSystem::addJoystickButtonBinding(Control* control, int deviceID, unsigned int button, Control::ControlChangingDirection direction) { ICS_LOG("\tAdding JoystickButtonBinder [button=" - + ToString(button) + ", direction=" - + ToString(direction) + "]"); + + ToString(button) + ", deviceID=" + + ToString(deviceID) + ", direction=" + + ToString(direction) + "]"); ControlButtonBinderItem controlJoystickButtonBinderItem; controlJoystickButtonBinderItem.direction = direction; controlJoystickButtonBinderItem.control = control; - mControlsJoystickButtonBinderMap[ button ] = controlJoystickButtonBinderItem; + mControlsJoystickButtonBinderMap[deviceID][button] = controlJoystickButtonBinderItem; } // get bindings - int InputControlSystem::getJoystickAxisBinding(Control* control, ICS::Control::ControlChangingDirection direction) - { - ControlsAxisBinderMapType::iterator it = mControlsJoystickAxisBinderMap.begin(); - while(it != mControlsJoystickAxisBinderMap.end()) - { - if(it->first >= 0 && it->second.control == control && it->second.direction == direction) + int InputControlSystem::getJoystickAxisBinding(Control* control, int deviceID, ICS::Control::ControlChangingDirection direction) + { + if(mControlsJoystickAxisBinderMap.find(deviceID) != mControlsJoystickAxisBinderMap.end()) + { + ControlsAxisBinderMapType::iterator it = mControlsJoystickAxisBinderMap[deviceID].begin(); + while(it != mControlsJoystickAxisBinderMap[deviceID].end()) { - return it->first; - } - ++it; + if(it->first >= 0 && it->second.control == control && it->second.direction == direction) + { + return it->first; + } + ++it; + } } return /*NamedAxis::*/UNASSIGNED; } - unsigned int InputControlSystem::getJoystickButtonBinding(Control* control, ICS::Control::ControlChangingDirection direction) - { - ControlsButtonBinderMapType::iterator it = mControlsJoystickButtonBinderMap.begin(); - while(it != mControlsJoystickButtonBinderMap.end()) - { - if(it->second.control == control && it->second.direction == direction) + unsigned int InputControlSystem::getJoystickButtonBinding(Control* control, int deviceID, ICS::Control::ControlChangingDirection direction) + { + if(mControlsJoystickButtonBinderMap.find(deviceID) != mControlsJoystickButtonBinderMap.end()) + { + ControlsButtonBinderMapType::iterator it = mControlsJoystickButtonBinderMap[deviceID].begin(); + while(it != mControlsJoystickButtonBinderMap[deviceID].end()) { - return it->first; - } - ++it; + if(it->second.control == control && it->second.direction == direction) + { + return it->first; + } + ++it; + } } return ICS_MAX_DEVICE_BUTTONS; } // remove bindings - void InputControlSystem::removeJoystickAxisBinding(int axis) - { - ControlsButtonBinderMapType::iterator it = mControlsJoystickAxisBinderMap.find(axis); - if(it != mControlsJoystickAxisBinderMap.end()) - { - mControlsJoystickAxisBinderMap.erase(it); + void InputControlSystem::removeJoystickAxisBinding(int deviceID, int axis) + { + if(mControlsJoystickAxisBinderMap.find(deviceID) != mControlsJoystickAxisBinderMap.end()) + { + ControlsAxisBinderMapType::iterator it = mControlsJoystickAxisBinderMap[deviceID].find(axis); + if(it != mControlsJoystickAxisBinderMap[deviceID].end()) + { + mControlsJoystickAxisBinderMap[deviceID].erase(it); + } } } - void InputControlSystem::removeJoystickButtonBinding(unsigned int button) - { - ControlsButtonBinderMapType::iterator it = mControlsJoystickButtonBinderMap.find(button); - if(it != mControlsJoystickButtonBinderMap.end()) - { - mControlsJoystickButtonBinderMap.erase(it); + void InputControlSystem::removeJoystickButtonBinding(int deviceID, unsigned int button) + { + if(mControlsJoystickButtonBinderMap.find(deviceID) != mControlsJoystickButtonBinderMap.end()) + { + ControlsButtonBinderMapType::iterator it = mControlsJoystickButtonBinderMap[deviceID].find(button); + if(it != mControlsJoystickButtonBinderMap[deviceID].end()) + { + mControlsJoystickButtonBinderMap[deviceID].erase(it); + } } } // joyStick listeners - void InputControlSystem::buttonPressed(const SDL_ControllerButtonEvent &evt) + void InputControlSystem::buttonPressed(int deviceID, const SDL_ControllerButtonEvent &evt) { if(mActive) { if(!mDetectingBindingControl) - { - ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap.find(evt.button); - if(it != mControlsJoystickButtonBinderMap.end()) + { + if(mControlsJoystickButtonBinderMap.find(deviceID) != mControlsJoystickButtonBinderMap.end()) { - it->second.control->setIgnoreAutoReverse(false); - if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop()) + ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap[deviceID].find(evt.button); + if(it != mControlsJoystickButtonBinderMap[deviceID].end()) { - it->second.control->setChangingDirection(it->second.direction); - } - else - { - if(it->second.control->getValue() == 1) + it->second.control->setIgnoreAutoReverse(false); + if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop()) { - it->second.control->setChangingDirection(Control::DECREASE); + it->second.control->setChangingDirection(it->second.direction); } - else if(it->second.control->getValue() == 0) + else { - it->second.control->setChangingDirection(Control::INCREASE); + if(it->second.control->getValue() == 1) + { + it->second.control->setChangingDirection(Control::DECREASE); + } + else if(it->second.control->getValue() == 0) + { + it->second.control->setChangingDirection(Control::INCREASE); + } } - } + } } } } } - void InputControlSystem::buttonReleased(const SDL_ControllerButtonEvent &evt) + void InputControlSystem::buttonReleased(int deviceID, const SDL_ControllerButtonEvent &evt) { if(mActive) { if(!mDetectingBindingControl) - { - ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap.find(evt.button); - if(it != mControlsJoystickButtonBinderMap.end()) + { + if(mControlsJoystickButtonBinderMap.find(deviceID) != mControlsJoystickButtonBinderMap.end()) { - it->second.control->setChangingDirection(Control::STOP); + ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap[deviceID].find(evt.button); + if(it != mControlsJoystickButtonBinderMap[deviceID].end()) + { + it->second.control->setChangingDirection(Control::STOP); + } } } else if(mDetectingBindingListener) { - mDetectingBindingListener->joystickButtonBindingDetected(this, + mDetectingBindingListener->joystickButtonBindingDetected(this, deviceID, mDetectingBindingControl, evt.button, mDetectingBindingDirection); } } } - void InputControlSystem::axisMoved(const SDL_ControllerAxisEvent &evt) + void InputControlSystem::axisMoved(int deviceID, const SDL_ControllerAxisEvent &evt) { if(mActive) { if(!mDetectingBindingControl) - { - ControlAxisBinderItem joystickBinderItem = mControlsJoystickAxisBinderMap[evt.axis]; // joystic axis start at 0 index - Control* ctrl = joystickBinderItem.control; - if(ctrl) + { + if(mControlsJoystickAxisBinderMap.find(deviceID) != mControlsJoystickAxisBinderMap.end()) { - ctrl->setIgnoreAutoReverse(true); - - float axisRange = SDL_JOY_AXIS_MAX - SDL_JOY_AXIS_MIN; - float valDisplaced = (float)(evt.value - SDL_JOY_AXIS_MIN); - float percent = valDisplaced / axisRange * (1+DEADZONE*2) - DEADZONE; //Assures all values, 0 through 1, are seen - if(percent > .5-DEADZONE && percent < .5+DEADZONE) //close enough to center - percent = .5; - else if(percent > .5) - percent -= DEADZONE; - else - percent += DEADZONE; - - if(joystickBinderItem.direction == Control::INCREASE) - { - ctrl->setValue( percent ); - } - else if(joystickBinderItem.direction == Control::DECREASE) + ControlAxisBinderItem joystickBinderItem = mControlsJoystickAxisBinderMap[deviceID][evt.axis]; // joystic axis start at 0 index + Control* ctrl = joystickBinderItem.control; + if(ctrl) { - ctrl->setValue( 1 - ( percent ) ); - } + ctrl->setIgnoreAutoReverse(true); + + float axisRange = SDL_JOY_AXIS_MAX - SDL_JOY_AXIS_MIN; + float valDisplaced = (float)(evt.value - SDL_JOY_AXIS_MIN); + float percent = valDisplaced / axisRange * (1+DEADZONE*2) - DEADZONE; //Assures all values, 0 through 1, are seen + if(percent > .5-DEADZONE && percent < .5+DEADZONE) //close enough to center + percent = .5; + else if(percent > .5) + percent -= DEADZONE; + else + percent += DEADZONE; + + if(joystickBinderItem.direction == Control::INCREASE) + { + ctrl->setValue( percent ); + } + else if(joystickBinderItem.direction == Control::DECREASE) + { + ctrl->setValue( 1 - ( percent ) ); + } + } } } else if(mDetectingBindingListener) @@ -244,7 +267,7 @@ namespace ICS { if( abs( evt.value ) > ICS_JOYSTICK_AXIS_BINDING_MARGIN) { - mDetectingBindingListener->joystickAxisBindingDetected(this, + mDetectingBindingListener->joystickAxisBindingDetected(this, deviceID, mDetectingBindingControl, evt.axis, mDetectingBindingDirection); } } @@ -252,67 +275,68 @@ namespace ICS } } - void InputControlSystem::controllerAdded(const SDL_ControllerDeviceEvent &args) + void InputControlSystem::controllerAdded(int deviceID, const SDL_ControllerDeviceEvent &args) { ICS_LOG("Adding joystick (index: " + ToString(args.which) + ")"); SDL_GameController* cntrl = SDL_GameControllerOpen(args.which); int instanceID = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(cntrl)); - if(mJoystickIDList.empty()) // + if(std::find(mJoystickIDList.begin(), mJoystickIDList.end(), deviceID)==mJoystickIDList.end()) { for(int j = 0 ; j < ICS_MAX_JOYSTICK_AXIS ; j++) { - if(mControlsJoystickAxisBinderMap.find(j) == mControlsJoystickAxisBinderMap.end()) + if(mControlsJoystickAxisBinderMap[deviceID].find(j) == mControlsJoystickAxisBinderMap[deviceID].end()) { ControlAxisBinderItem controlJoystickBinderItem; controlJoystickBinderItem.direction = Control::STOP; controlJoystickBinderItem.control = NULL; - mControlsJoystickAxisBinderMap[j] = controlJoystickBinderItem; + mControlsJoystickAxisBinderMap[deviceID][j] = controlJoystickBinderItem; } } + mJoystickIDList.push_front(deviceID); } - mJoystickIDList[instanceID] = cntrl; + mJoystickInstanceMap[instanceID] = cntrl; } void InputControlSystem::controllerRemoved(const SDL_ControllerDeviceEvent &args) { ICS_LOG("Removing joystick (instance id: " + ToString(args.which) + ")"); - if(mJoystickIDList.count(args.which)!=0) + if(mJoystickInstanceMap.count(args.which)!=0) { - SDL_GameControllerClose(mJoystickIDList.at(args.which)); - mJoystickIDList.erase(args.which); + SDL_GameControllerClose(mJoystickInstanceMap.at(args.which)); + mJoystickInstanceMap.erase(args.which); } } // joystick auto bindings - void DetectingBindingListener::joystickAxisBindingDetected(InputControlSystem* ICS, Control* control, int axis, Control::ControlChangingDirection direction) + void DetectingBindingListener::joystickAxisBindingDetected(InputControlSystem* ICS, int deviceID, Control* control, int axis, Control::ControlChangingDirection direction) { // if the joystick axis is used by another control, remove it - ICS->removeJoystickAxisBinding(axis); + ICS->removeJoystickAxisBinding(deviceID, axis); // if the control has an axis assigned, remove it - int oldAxis = ICS->getJoystickAxisBinding(control, direction); + int oldAxis = ICS->getJoystickAxisBinding(control, deviceID, direction); if(oldAxis != InputControlSystem::UNASSIGNED) { - ICS->removeJoystickAxisBinding(oldAxis); + ICS->removeJoystickAxisBinding(deviceID, oldAxis); } - ICS->addJoystickAxisBinding(control, axis, direction); + ICS->addJoystickAxisBinding(control, deviceID, axis, direction); ICS->cancelDetectingBindingState(); } - void DetectingBindingListener::joystickButtonBindingDetected(InputControlSystem* ICS, Control* control + void DetectingBindingListener::joystickButtonBindingDetected(InputControlSystem* ICS, int deviceID, Control* control , unsigned int button, Control::ControlChangingDirection direction) { // if the joystick button is used by another control, remove it - ICS->removeJoystickButtonBinding(button); + ICS->removeJoystickButtonBinding(deviceID, button); // if the control has a joystick button assigned, remove it - unsigned int oldButton = ICS->getJoystickButtonBinding(control, direction); + unsigned int oldButton = ICS->getJoystickButtonBinding(control, deviceID, direction); if(oldButton != ICS_MAX_DEVICE_BUTTONS) { - ICS->removeJoystickButtonBinding(oldButton); + ICS->removeJoystickButtonBinding(deviceID, oldButton); } - ICS->addJoystickButtonBinding(control, button, direction); + ICS->addJoystickButtonBinding(control, deviceID, button, direction); ICS->cancelDetectingBindingState(); } } diff --git a/extern/sdl4ogre/events.h b/extern/sdl4ogre/events.h index ebabb4cbb..a12283def 100644 --- a/extern/sdl4ogre/events.h +++ b/extern/sdl4ogre/events.h @@ -45,19 +45,19 @@ class ControllerListener public: virtual ~ControllerListener() {} /** @remarks Joystick button down event */ - virtual void buttonPressed( const SDL_ControllerButtonEvent &evt) = 0; + virtual void buttonPressed(int deviceID, const SDL_ControllerButtonEvent &evt) = 0; /** @remarks Joystick button up event */ - virtual void buttonReleased( const SDL_ControllerButtonEvent &evt) = 0; + virtual void buttonReleased(int deviceID, const SDL_ControllerButtonEvent &evt) = 0; /** @remarks Joystick axis moved event */ - virtual void axisMoved( const SDL_ControllerAxisEvent &arg) = 0; + virtual void axisMoved(int deviceID, const SDL_ControllerAxisEvent &arg) = 0; /** @remarks Joystick Added **/ - virtual void controllerAdded( const SDL_ControllerDeviceEvent &arg) = 0; + virtual void controllerAdded(int deviceID, const SDL_ControllerDeviceEvent &arg) = 0; /** @remarks Joystick Removed **/ - virtual void controllerRemoved( const SDL_ControllerDeviceEvent &arg) = 0; + virtual void controllerRemoved(const SDL_ControllerDeviceEvent &arg) = 0; }; diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index f211811cc..d2938eb14 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -97,7 +97,7 @@ namespace SFO break; case SDL_CONTROLLERDEVICEADDED: if(mConListener) - mConListener->controllerAdded(evt.cdevice); + mConListener->controllerAdded(1, evt.cdevice); //We only support one joystick, so give everything a generic deviceID break; case SDL_CONTROLLERDEVICEREMOVED: if(mConListener) @@ -105,15 +105,15 @@ namespace SFO break; case SDL_CONTROLLERBUTTONDOWN: if(mConListener) - mConListener->buttonPressed(evt.cbutton); + mConListener->buttonPressed(1, evt.cbutton); break; case SDL_CONTROLLERBUTTONUP: if(mConListener) - mConListener->buttonReleased(evt.cbutton); + mConListener->buttonReleased(1, evt.cbutton); break; case SDL_CONTROLLERAXISMOTION: if(mConListener) - mConListener->axisMoved(evt.caxis); + mConListener->axisMoved(1, evt.caxis); break; case SDL_WINDOWEVENT: handleWindowEvent(evt); From 796b4b01b0dcecb7b7bc860c0ecca7e5ffac8a1e Mon Sep 17 00:00:00 2001 From: Digmaster Date: Mon, 19 Jan 2015 18:20:49 -0600 Subject: [PATCH 512/740] Fix activating every frame when action is bound to a trigger --- apps/openmw/mwinput/inputmanagerimp.cpp | 29 +++++++++++++++++-------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 7b8580080..76d0b877a 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -233,14 +233,26 @@ namespace MWInput int action = channel->getNumber(); - if(currentValue > .8) currentValue = 1.0; - else if(currentValue < .6) currentValue = 0.0; - else return; - - if(previousValue > .8) previousValue = 1.0; - else if(previousValue < .6) previousValue = 0.0; - - if(currentValue == previousValue) return; + if((previousValue == 1 || previousValue == 0) && (currentValue==1 || currentValue==0)) + { + //Is a normal button press, so don't change it at all + } + //Otherwise only trigger button presses as they go through specific points + else if(previousValue >= .8 && currentValue < .8) + { + currentValue = 0.0; + previousValue = 1.0; + } + else if(previousValue <= .6 && currentValue > .6) + { + currentValue = 1.0; + previousValue = 0.0; + } + else + { + //If it's not switching between those values, ignore the channel change. + return; + } if (mControlSwitch["playercontrols"]) { @@ -271,7 +283,6 @@ namespace MWInput break; case A_Activate: resetIdleTime(); - if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) activate(); break; From a192836582cbfeab7eff133dea989b13641c67ed Mon Sep 17 00:00:00 2001 From: Digmaster Date: Mon, 19 Jan 2015 18:55:17 -0600 Subject: [PATCH 513/740] (hopefully) correct gamecontrollerdb.txt behavior --- CMakeLists.txt | 3 +++ apps/openmw/engine.cpp | 14 +++++++++++++- apps/openmw/mwinput/inputmanagerimp.cpp | 17 ++++------------- apps/openmw/mwinput/inputmanagerimp.hpp | 3 ++- 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d8872e162..8efb90436 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -460,6 +460,7 @@ IF(NOT WIN32 AND NOT APPLE) INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${SYSCONFDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") INSTALL(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${SYSCONFDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "${SYSCONFDIR}" RENAME "openmw.cfg" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${SYSCONFDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") IF(BUILD_OPENCS) INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${SYSCONFDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs") ENDIF(BUILD_OPENCS) @@ -479,6 +480,7 @@ if(WIN32) "${OpenMW_SOURCE_DIR}/Docs/license/DejaVu Font License.txt" "${OpenMW_BINARY_DIR}/settings-default.cfg" "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" + "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" "${OpenMW_BINARY_DIR}/Release/openmw.exe" DESTINATION ".") @@ -750,6 +752,7 @@ if (APPLE) install(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" RENAME "openmw.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) + install(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 0e636e054..9c485c2af 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -368,7 +368,19 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) std::string keybinderUser = (mCfgMgr.getUserConfigPath() / "input_v2.xml").string(); bool keybinderUserExists = boost::filesystem::exists(keybinderUser); - MWInput::InputManager* input = new MWInput::InputManager (*mOgre, *this, keybinderUser, keybinderUserExists, mGrab); + + // find correct path to the game controller bindings + const std::string localdefault = mCfgMgr.getLocalPath().string() + "/gamecontrollerdb.cfg"; + const std::string globaldefault = mCfgMgr.getGlobalPath().string() + "/gamecontrollerdb.cfg"; + std::string gameControllerdb; + if (boost::filesystem::exists(localdefault)) + gameControllerdb = localdefault; + else if (boost::filesystem::exists(globaldefault)) + gameControllerdb = globaldefault; + else + gameControllerdb = ""; //if it doesn't exist, pass in an empty string + + MWInput::InputManager* input = new MWInput::InputManager (*mOgre, *this, keybinderUser, keybinderUserExists, gameControllerdb, mGrab); mEnvironment.setInputManager (input); MWGui::WindowManager* window = new MWGui::WindowManager( diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 76d0b877a..05ce62374 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -100,7 +100,8 @@ namespace MWInput { InputManager::InputManager(OEngine::Render::OgreRenderer &ogre, OMW::Engine& engine, - const std::string& userFile, bool userFileExists, bool grab) + const std::string& userFile, bool userFileExists, + const std::string& controllerBindingsFile, bool grab) : mOgre(ogre) , mPlayer(NULL) , mEngine(engine) @@ -160,19 +161,9 @@ namespace MWInput //Load controller mappings #if SDL_VERSION_ATLEAST(2,0,2) - Files::ConfigurationManager cfgMgr; - std::string db = cfgMgr.getLocalPath().string() + "/gamecontrollerdb.txt"; - if(boost::filesystem::exists(db)) + if(controllerBindingsFile!="") { - int res = SDL_GameControllerAddMappingsFromFile(db.c_str()); - if(res == -1) - { - //ICS_LOG(std::string("Error loading controller bindings: ")+SDL_GetError()); - } - else - { - //ICS_LOG(std::string("Loaded ")+boost::lexical_cast(res)+" Game controller bindings"); - } + SDL_GameControllerAddMappingsFromFile(controllerBindingsFile.c_str()); } #endif diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index e8ee955e2..a72275a9c 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -68,7 +68,8 @@ namespace MWInput public: InputManager(OEngine::Render::OgreRenderer &_ogre, OMW::Engine& engine, - const std::string& userFile, bool userFileExists, bool grab); + const std::string& userFile, bool userFileExists, + const std::string& controllerBindingsFile, bool grab); virtual ~InputManager(); From df5513da7c6bb66529eaa2637444635bc5c02f36 Mon Sep 17 00:00:00 2001 From: Digmaster Date: Sat, 24 Jan 2015 16:03:55 -0600 Subject: [PATCH 514/740] uses v3 input bindings, not v2 --- apps/openmw/engine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 9c485c2af..41179f6e5 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -366,7 +366,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) // Create input and UI first to set up a bootstrapping environment for // showing a loading screen and keeping the window responsive while doing so - std::string keybinderUser = (mCfgMgr.getUserConfigPath() / "input_v2.xml").string(); + std::string keybinderUser = (mCfgMgr.getUserConfigPath() / "input_v3.xml").string(); bool keybinderUserExists = boost::filesystem::exists(keybinderUser); // find correct path to the game controller bindings From 5d77ebdc60f7a93f0442862d599f809f99cd53e9 Mon Sep 17 00:00:00 2001 From: Digmaster Date: Sat, 24 Jan 2015 16:44:17 -0600 Subject: [PATCH 515/740] If v3 doesn't exist, copy from v2 --- apps/openmw/engine.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 5a50d6d27..7764b8775 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -373,6 +373,11 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) std::string keybinderUser = (mCfgMgr.getUserConfigPath() / "input_v3.xml").string(); bool keybinderUserExists = boost::filesystem::exists(keybinderUser); + if(!keybinderUserExists) + { + boost::filesystem::copy_file(mCfgMgr.getUserConfigPath() / "input_v2.xml", mCfgMgr.getUserConfigPath() / "input_v3.xml"); + keybinderUserExists=true; + } // find correct path to the game controller bindings const std::string localdefault = mCfgMgr.getLocalPath().string() + "/gamecontrollerdb.cfg"; From 464bbe4d6f0e0ec212cd5a37ee442fed58e24763 Mon Sep 17 00:00:00 2001 From: Digmaster Date: Sun, 25 Jan 2015 01:11:21 -0600 Subject: [PATCH 516/740] if v2 doesn't exist, don't erroneously set keyboardUserExists to true. --- apps/openmw/engine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 7764b8775..282182493 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -376,7 +376,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) if(!keybinderUserExists) { boost::filesystem::copy_file(mCfgMgr.getUserConfigPath() / "input_v2.xml", mCfgMgr.getUserConfigPath() / "input_v3.xml"); - keybinderUserExists=true; + keybinderUserExists = boost::filesystem::exists(keybinderUser); } // find correct path to the game controller bindings From 84ff11d0ab13e08cd03aaf9fd8405ff8026f5fc6 Mon Sep 17 00:00:00 2001 From: Digmaster Date: Mon, 26 Jan 2015 12:50:44 -0600 Subject: [PATCH 517/740] check if v2 exists before attemping to copy it --- apps/openmw/engine.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 282182493..d7230a394 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -375,8 +375,11 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) bool keybinderUserExists = boost::filesystem::exists(keybinderUser); if(!keybinderUserExists) { - boost::filesystem::copy_file(mCfgMgr.getUserConfigPath() / "input_v2.xml", mCfgMgr.getUserConfigPath() / "input_v3.xml"); - keybinderUserExists = boost::filesystem::exists(keybinderUser); + std::string input2 = (mCfgMgr.getUserConfigPath() / "input_v2.xml").string(); + if(boost::filesystem::exists(input2)) { + boost::filesystem::copy_file(input2, keybinderUser); + keybinderUserExists = boost::filesystem::exists(keybinderUser); + } } // find correct path to the game controller bindings From 0cd5437595e4a791cd18ff7288169d8f153c8a4b Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 27 Feb 2015 22:37:29 +0100 Subject: [PATCH 518/740] gamecontrollerdb.txt updated from upstream, added link and license --- files/gamecontrollerdb.txt | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/files/gamecontrollerdb.txt b/files/gamecontrollerdb.txt index 9ad8778a0..bd8d9c5fc 100644 --- a/files/gamecontrollerdb.txt +++ b/files/gamecontrollerdb.txt @@ -1,3 +1,24 @@ +# from https://github.com/gabomdq/SDL_GameControllerDB +# License: +# Simple DirectMedia Layer +# Copyright (C) 1997-2013 Sam Lantinga +# +# This software is provided 'as-is', without any express or implied +# warranty. In no event will the authors be held liable for any damages +# arising from the use of this software. +# +# Permission is granted to anyone to use this software for any purpose, +# including commercial applications, and to alter it and redistribute it +# freely, subject to the following restrictions: +# +# 1. The origin of this software must not be misrepresented; you must not +# claim that you wrote the original software. If you use this software +# in a product, an acknowledgment in the product documentation would be +# appreciated but is not required. +# 2. Altered source versions must be plainly marked as such, and must not be +# misrepresented as being the original software. +# 3. This notice may not be removed or altered from any source distribution. + # Windows - DINPUT 8f0e1200000000000000504944564944,Acme,platform:Windows,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, 341a3608000000000000504944564944,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, @@ -8,7 +29,6 @@ ffff0000000000000000504944564944,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4, 4c056802000000000000504944564944,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows, 25090500000000000000504944564944,PS3 DualShock,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows, 4c05c405000000000000504944564944,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, -xinput,X360 Controller,a:b10,b:b11,back:b5,dpdown:b1,dpleft:b2,dpright:b3,dpup:b0,guide:b14,leftshoulder:b8,leftstick:b6,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b7,righttrigger:a5,rightx:a2,righty:a3,start:b4,x:b12,y:b13,platform:Windows, 6d0418c2000000000000504944564944,Logitech RumblePad 2 USB,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, 36280100000000000000504944564944,OUYA Controller,platform:Windows,a:b0,b:b3,y:b2,x:b1,start:b14,guide:b15,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b8,dpleft:b10,dpdown:b9,dpright:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b12,righttrigger:b13, 4f0400b3000000000000504944564944,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Windows, @@ -16,6 +36,9 @@ xinput,X360 Controller,a:b10,b:b11,back:b5,dpdown:b1,dpleft:b2,dpright:b3,dpup:b 00f0f100000000000000504944564944,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows, 28040140000000000000504944564944,GamePad Pro USB,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7, ff113133000000000000504944564944,SVEN X-PAD,platform:Windows,a:b2,b:b3,y:b1,x:b0,start:b5,back:b4,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b8,righttrigger:b9, +8f0e0300000000000000504944564944,Piranha xtreme,platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +8f0e0d31000000000000504944564944,Multilaser JS071 USB,platform:Windows,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, +10080300000000000000504944564944,PS2 USB,platform:Windows,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a4,righty:a2,lefttrigger:b4,righttrigger:b5, # OS X 0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, @@ -28,6 +51,8 @@ ff113133000000000000504944564944,SVEN X-PAD,platform:Windows,a:b2,b:b3,y:b1,x:b0 5e040000000000008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, 891600000000000000fd000000000000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b8,guide:b10,back:b9,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b11,dpleft:b13,dpdown:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Mac OS X, 4f0400000000000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Mac OS X, +8f0e0000000000000300000000000000,Piranha xtreme,platform:Mac OS X,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +0d0f0000000000004d00000000000000,HORI Gem Pad 3,platform:Mac OS X,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, # Linux 0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, @@ -73,3 +98,4 @@ ff113133000000000000504944564944,SVEN X-PAD,platform:Windows,a:b2,b:b3,y:b1,x:b0 03000000666600000488000000010000,Super Joy Box 5 Pro,platform:Linux,a:b2,b:b1,x:b3,y:b0,back:b9,start:b8,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,dpup:b12,dpleft:b15,dpdown:b14,dpright:b13, 05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2, 05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2, +030000008916000001fd000024010000,Razer Onza Classic Edition,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8tart:b7,dpleft:b11,dpdown:b14,dpright:b12,dpup:b13,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4, From 54e3ebde63e22f1920c5a70acf7fc18299ffb229 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 28 Feb 2015 17:13:21 +1300 Subject: [PATCH 519/740] addon list in launcher shows addon files with no dependencies (Fixes #2348) Also, game files must end with ".esm" or ".omwgame". --- components/contentselector/model/contentmodel.cpp | 3 ++- components/contentselector/model/esmfile.cpp | 6 ++++++ components/contentselector/model/esmfile.hpp | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index cd0c67ee7..7850b2cd6 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -115,9 +115,10 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index return Qt::NoItemFlags; Qt::ItemFlags returnFlags; - bool gamefileChecked = false; // addon can be checked if its gamefile is + // ... special case, addon with no dependency can be used with any gamefile. + bool gamefileChecked = (file->gameFiles().count() == 0); foreach (const QString &fileName, file->gameFiles()) { bool depFound = false; diff --git a/components/contentselector/model/esmfile.cpp b/components/contentselector/model/esmfile.cpp index a0a09105a..9f85e5f43 100644 --- a/components/contentselector/model/esmfile.cpp +++ b/components/contentselector/model/esmfile.cpp @@ -62,6 +62,12 @@ QByteArray ContentSelectorModel::EsmFile::encodedData() const return encodedData; } +bool ContentSelectorModel::EsmFile::isGameFile() const +{ + return (mGameFiles.size() == 0) && + (mFileName.endsWith(QLatin1String(".esm")) || mFileName.endsWith(QLatin1String(".omwgame"))); +} + QVariant ContentSelectorModel::EsmFile::fileProperty(const FileProperty prop) const { switch (prop) diff --git a/components/contentselector/model/esmfile.hpp b/components/contentselector/model/esmfile.hpp index 7e1edcaba..d0cebab3c 100644 --- a/components/contentselector/model/esmfile.hpp +++ b/components/contentselector/model/esmfile.hpp @@ -64,7 +64,7 @@ namespace ContentSelectorModel .arg(mGameFiles.join(", ")); } - inline bool isGameFile() const { return (mGameFiles.size() == 0); } + bool isGameFile() const; QByteArray encodedData() const; public: From 5e2839977bd7c40dee207122524af4107d4efb18 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 28 Feb 2015 20:25:03 +1300 Subject: [PATCH 520/740] file extension comparison needs to be case insensitive. --- components/contentselector/model/esmfile.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/contentselector/model/esmfile.cpp b/components/contentselector/model/esmfile.cpp index 9f85e5f43..1ac1c7500 100644 --- a/components/contentselector/model/esmfile.cpp +++ b/components/contentselector/model/esmfile.cpp @@ -65,7 +65,8 @@ QByteArray ContentSelectorModel::EsmFile::encodedData() const bool ContentSelectorModel::EsmFile::isGameFile() const { return (mGameFiles.size() == 0) && - (mFileName.endsWith(QLatin1String(".esm")) || mFileName.endsWith(QLatin1String(".omwgame"))); + (mFileName.endsWith(QLatin1String(".esm"), Qt::CaseInsensitive) || + mFileName.endsWith(QLatin1String(".omwgame"), Qt::CaseInsensitive)); } QVariant ContentSelectorModel::EsmFile::fileProperty(const FileProperty prop) const From f82751422d87e9e2f99392d9fdece404e0168f6d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Feb 2015 16:31:22 +0100 Subject: [PATCH 521/740] Fix constant effect restore enchantments being applied incorrectly (Fixes #2408) --- apps/openmw/mwmechanics/spellcasting.cpp | 80 +++++++++++++----------- apps/openmw/mwmechanics/spellcasting.hpp | 2 - 2 files changed, 45 insertions(+), 37 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 105fa5866..e702401a6 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -56,6 +56,42 @@ namespace } } + void applyDynamicStatsEffect(int attribute, const MWWorld::Ptr& target, float magnitude) + { + MWMechanics::DynamicStat value = target.getClass().getCreatureStats(target).getDynamic(attribute); + value.setCurrent(value.getCurrent()+magnitude, attribute == 2); + target.getClass().getCreatureStats(target).setDynamic(attribute, value); + } + + // TODO: refactor the effect tick functions in Actors so they can be reused here + void applyInstantEffectTick(int effectId, const MWWorld::Ptr& target, float magnitude) + { + if (effectId == ESM::MagicEffect::DamageHealth) + { + applyDynamicStatsEffect(0, target, magnitude * -1); + } + else if (effectId == ESM::MagicEffect::RestoreHealth) + { + applyDynamicStatsEffect(0, target, magnitude); + } + else if (effectId == ESM::MagicEffect::DamageFatigue) + { + applyDynamicStatsEffect(2, target, magnitude * -1); + } + else if (effectId == ESM::MagicEffect::RestoreFatigue) + { + applyDynamicStatsEffect(2, target, magnitude); + } + else if (effectId == ESM::MagicEffect::DamageMagicka) + { + applyDynamicStatsEffect(1, target, magnitude * -1); + } + else if (effectId == ESM::MagicEffect::RestoreMagicka) + { + applyDynamicStatsEffect(1, target, magnitude); + } + } + } namespace MWMechanics @@ -438,8 +474,8 @@ namespace MWMechanics float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random; magnitude *= magnitudeMult; - bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration) && effectIt->mDuration > 0; - if (target.getClass().isActor() && hasDuration) + bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration); + if (target.getClass().isActor() && hasDuration && effectIt->mDuration > 0) { ActiveSpells::ActiveEffect effect; effect.mEffectId = effectIt->mEffectID; @@ -471,7 +507,12 @@ namespace MWMechanics } } else - applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude); + { + if (hasDuration && target.getClass().isActor()) + applyInstantEffectTick(effectIt->mEffectID, target, magnitude); + else + applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude); + } // Re-casting a summon effect will remove the creature from previous castings of that effect. if (isSummoningEffect(effectIt->mEffectID) && !target.isEmpty() && target.getClass().isActor()) @@ -594,31 +635,6 @@ namespace MWMechanics value.restore(magnitude); target.getClass().getCreatureStats(target).setAttribute(attribute, value); } - // TODO: refactor the effect tick functions in Actors so they can be reused here - else if (effectId == ESM::MagicEffect::DamageHealth) - { - applyDynamicStatsEffect(0, target, magnitude * -1); - } - else if (effectId == ESM::MagicEffect::RestoreHealth) - { - applyDynamicStatsEffect(0, target, magnitude); - } - else if (effectId == ESM::MagicEffect::DamageFatigue) - { - applyDynamicStatsEffect(2, target, magnitude * -1); - } - else if (effectId == ESM::MagicEffect::RestoreFatigue) - { - applyDynamicStatsEffect(2, target, magnitude); - } - else if (effectId == ESM::MagicEffect::DamageMagicka) - { - applyDynamicStatsEffect(1, target, magnitude * -1); - } - else if (effectId == ESM::MagicEffect::RestoreMagicka) - { - applyDynamicStatsEffect(1, target, magnitude); - } else if (effectId == ESM::MagicEffect::DamageSkill || effectId == ESM::MagicEffect::RestoreSkill) { if (target.getTypeName() != typeid(ESM::NPC).name()) @@ -680,13 +696,7 @@ namespace MWMechanics } } } - - void CastSpell::applyDynamicStatsEffect(int attribute, const MWWorld::Ptr& target, float magnitude) - { - DynamicStat value = target.getClass().getCreatureStats(target).getDynamic(attribute); - value.setCurrent(value.getCurrent()+magnitude, attribute == 2); - target.getClass().getCreatureStats(target).setDynamic(attribute, value); - } + bool CastSpell::cast(const std::string &id) { diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 2d550e085..dca4f0192 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -97,8 +97,6 @@ namespace MWMechanics /// @note \a caster can be any type of object, or even an empty object. void applyInstantEffect (const MWWorld::Ptr& target, const MWWorld::Ptr& caster, const MWMechanics::EffectKey& effect, float magnitude); - - void applyDynamicStatsEffect (int attribute, const MWWorld::Ptr& target, float magnitude); }; } From 76732b475a01a4fbfd7837a7cb034be4096bc6c2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Feb 2015 16:37:06 +0100 Subject: [PATCH 522/740] Remove leftover --- files/settings-default.cfg | 2 -- 1 file changed, 2 deletions(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 422561a02..19b570e2a 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -194,8 +194,6 @@ always run = false allow third person zoom = false -gamecontrollerdb file = resources/gamecontrollerdb.txt - [Game] # Always use the most powerful attack when striking with a weapon (chop, slash or thrust) best attack = false From 960e99c4f375de2e13d8a8d14b9049d3513b25fb Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Feb 2015 17:43:15 +0100 Subject: [PATCH 523/740] Loading screen align fix --- files/mygui/openmw_loading_screen.layout | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/mygui/openmw_loading_screen.layout b/files/mygui/openmw_loading_screen.layout index 8a1514f84..92bc5aa4c 100644 --- a/files/mygui/openmw_loading_screen.layout +++ b/files/mygui/openmw_loading_screen.layout @@ -10,7 +10,7 @@
- + From 2f2a95f735d0006d581ef12f0c5e16d0c4c170d7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Feb 2015 19:33:49 +0100 Subject: [PATCH 524/740] Fix crash for terrain without data, part 2 --- apps/openmw/mwworld/scene.cpp | 2 +- libs/openengine/bullet/physic.cpp | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index f03f65b36..08767df80 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -199,7 +199,7 @@ namespace MWWorld (*iter)->getCell()->getGridX(), (*iter)->getCell()->getGridY() ); - if (land) + if (land && land->mDataTypes&ESM::Land::DATA_VHGT) mPhysics->removeHeightField ((*iter)->getCell()->getGridX(), (*iter)->getCell()->getGridY()); } diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 1ef00a0e1..b3e9f1395 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -414,13 +414,17 @@ namespace Physic + boost::lexical_cast(x) + "_" + boost::lexical_cast(y); - HeightField hf = mHeightFieldMap [name]; + HeightFieldContainer::iterator it = mHeightFieldMap.find(name); + if (it == mHeightFieldMap.end()) + return; + + const HeightField& hf = it->second; mDynamicsWorld->removeRigidBody(hf.mBody); delete hf.mShape; delete hf.mBody; - mHeightFieldMap.erase(name); + mHeightFieldMap.erase(it); } void PhysicEngine::adjustRigidBody(RigidBody* body, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, From 41e15e0c2d2ac255f14e55acc38a981bd3fc74a5 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 1 Mar 2015 10:27:51 +1300 Subject: [PATCH 525/740] Limit maximum attribute damage (Fixes #2367) Maximum damage that an attribute can have = base + fortify. --- apps/openmw/mwmechanics/actors.cpp | 8 ++++---- apps/openmw/mwmechanics/stat.cpp | 5 +++++ apps/openmw/mwmechanics/stat.hpp | 21 +++++++++++++-------- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index f8068e800..aa2cc8615 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -515,8 +515,8 @@ namespace MWMechanics for(int i = 0;i < ESM::Attribute::Length;++i) { AttributeValue stat = creatureStats.getAttribute(i); - stat.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifyAttribute, i)).getMagnitude() - - effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).getMagnitude() - + stat.setModifiers(effects.get(EffectKey(ESM::MagicEffect::FortifyAttribute, i)).getMagnitude(), + effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).getMagnitude(), effects.get(EffectKey(ESM::MagicEffect::AbsorbAttribute, i)).getMagnitude()); stat.damage(effects.get(EffectKey(ESM::MagicEffect::DamageAttribute, i)).getMagnitude() * duration * 1.5); @@ -782,8 +782,8 @@ namespace MWMechanics for(int i = 0;i < ESM::Skill::Length;++i) { SkillValue& skill = npcStats.getSkill(i); - skill.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifySkill, i)).getMagnitude() - - effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).getMagnitude() - + skill.setModifiers(effects.get(EffectKey(ESM::MagicEffect::FortifySkill, i)).getMagnitude(), + effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).getMagnitude(), effects.get(EffectKey(ESM::MagicEffect::AbsorbSkill, i)).getMagnitude()); skill.damage(effects.get(EffectKey(ESM::MagicEffect::DamageSkill, i)).getMagnitude() * duration * 1.5); diff --git a/apps/openmw/mwmechanics/stat.cpp b/apps/openmw/mwmechanics/stat.cpp index 61b6d60ad..554f619a5 100644 --- a/apps/openmw/mwmechanics/stat.cpp +++ b/apps/openmw/mwmechanics/stat.cpp @@ -15,6 +15,11 @@ void MWMechanics::AttributeValue::readState (const ESM::StatState& state) mDamage = state.mDamage; } +void MWMechanics::AttributeValue::setModifiers(int fortify, int drain, int absorb) +{ + mFortified = fortify; + mModifier = (fortify - drain) - absorb; +} void MWMechanics::SkillValue::writeState (ESM::StatState& state) const { diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index 1c33db0fd..294dbcb6c 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -235,26 +235,29 @@ namespace MWMechanics class AttributeValue { int mBase; - int mModifier; + int mFortified; + int mModifier; // net effect of Fortified, Drain & Absorb float mDamage; // needs to be float to allow continuous damage public: - AttributeValue() : mBase(0), mModifier(0), mDamage(0) {} + AttributeValue() : mBase(0), mFortified(0), mModifier(0), mDamage(0) {} int getModified() const { return std::max(0, mBase - (int) mDamage + mModifier); } int getBase() const { return mBase; } int getModifier() const { return mModifier; } void setBase(int base) { mBase = std::max(0, base); } - void setModifier(int mod) { mModifier = mod; } + void setModifiers(int fortify, int drain, int absorb); - void damage(float damage) { mDamage += damage; } + void damage(float damage) { mDamage = std::min(mDamage + damage, (float)(mBase + mFortified)); } void restore(float amount) { mDamage -= std::min(mDamage, amount); } int getDamage() const { return mDamage; } void writeState (ESM::StatState& state) const; void readState (const ESM::StatState& state); + + friend bool operator== (const AttributeValue& left, const AttributeValue& right); }; class SkillValue : public AttributeValue @@ -268,13 +271,16 @@ namespace MWMechanics void writeState (ESM::StatState& state) const; void readState (const ESM::StatState& state); + + friend bool operator== (const SkillValue& left, const SkillValue& right); }; inline bool operator== (const AttributeValue& left, const AttributeValue& right) { return left.getBase() == right.getBase() + && left.mFortified == right.mFortified && left.getModifier() == right.getModifier() - && left.getDamage() == right.getDamage(); + && left.mDamage == right.mDamage; } inline bool operator!= (const AttributeValue& left, const AttributeValue& right) { @@ -283,9 +289,8 @@ namespace MWMechanics inline bool operator== (const SkillValue& left, const SkillValue& right) { - return left.getBase() == right.getBase() - && left.getModifier() == right.getModifier() - && left.getDamage() == right.getDamage() + // delegate to base class for most of the work + return (static_cast(left) == right) && left.getProgress() == right.getProgress(); } inline bool operator!= (const SkillValue& left, const SkillValue& right) From c4625b94e5979ed42d29c48019830ec631f56778 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 1 Mar 2015 12:52:43 +1100 Subject: [PATCH 526/740] Fix OpenCS crashing since commit 9d6145 by showing gamefiles if the content selector was created from OpenCS. --- apps/opencs/view/doc/filedialog.cpp | 4 ++-- .../contentselector/model/contentmodel.cpp | 16 +++++++++++----- .../contentselector/model/contentmodel.hpp | 3 ++- .../contentselector/view/contentselector.cpp | 8 ++++---- .../contentselector/view/contentselector.hpp | 4 ++-- 5 files changed, 21 insertions(+), 14 deletions(-) diff --git a/apps/opencs/view/doc/filedialog.cpp b/apps/opencs/view/doc/filedialog.cpp index 6a72f13ed..c895a3399 100644 --- a/apps/opencs/view/doc/filedialog.cpp +++ b/apps/opencs/view/doc/filedialog.cpp @@ -24,7 +24,7 @@ CSVDoc::FileDialog::FileDialog(QWidget *parent) : resize(400, 400); setObjectName ("FileDialog"); - mSelector = new ContentSelectorView::ContentSelector (ui.contentSelectorWidget); + mSelector = new ContentSelectorView::ContentSelector (ui.contentSelectorWidget, true); mAdjusterWidget = new AdjusterWidget (this); } @@ -147,7 +147,7 @@ void CSVDoc::FileDialog::slotUpdateAcceptButton(int) void CSVDoc::FileDialog::slotUpdateAcceptButton(const QString &name, bool) { - bool success = (mSelector->selectedFiles().size() > 0); + bool success = !mSelector->selectedFiles().empty(); bool isNew = (mAction == ContentAction_New); diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 7850b2cd6..3e3536413 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -9,13 +9,14 @@ #include "components/esm/esmreader.hpp" -ContentSelectorModel::ContentModel::ContentModel(QObject *parent, QIcon warningIcon) : +ContentSelectorModel::ContentModel::ContentModel(QObject *parent, QIcon warningIcon, bool showGameFiles) : QAbstractTableModel(parent), mWarningIcon(warningIcon), mMimeType ("application/omwcontent"), mMimeTypes (QStringList() << mMimeType), mColumnCount (1), - mDropActions (Qt::MoveAction) + mDropActions (Qt::MoveAction), + mShowGameFiles(showGameFiles) { setEncoding ("win1252"); uncheckAll(); @@ -110,9 +111,14 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index if (!file) return Qt::NoItemFlags; - //game files are not shown + //game files are not shown (unless OpenCS) if (file->isGameFile()) - return Qt::NoItemFlags; + { + if(mShowGameFiles) + return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable; + else + return Qt::NoItemFlags; + } Qt::ItemFlags returnFlags; @@ -463,7 +469,7 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path) file->setDescription(QString::fromUtf8(fileReader.getDesc().c_str())); // HACK - // Load order constraint of Bloodmoon.esm needing Tribunal.esm is missing + // Load order constraint of Bloodmoon.esm needing Tribunal.esm is missing // from the file supplied by Bethesda, so we have to add it ourselves if (file->fileName().compare("Bloodmoon.esm", Qt::CaseInsensitive) == 0) { diff --git a/components/contentselector/model/contentmodel.hpp b/components/contentselector/model/contentmodel.hpp index 658555852..887ad51b3 100644 --- a/components/contentselector/model/contentmodel.hpp +++ b/components/contentselector/model/contentmodel.hpp @@ -23,7 +23,7 @@ namespace ContentSelectorModel { Q_OBJECT public: - explicit ContentModel(QObject *parent, QIcon warningIcon); + explicit ContentModel(QObject *parent, QIcon warningIcon, bool showGameFiles = false); ~ContentModel(); void setEncoding(const QString &encoding); @@ -66,6 +66,7 @@ namespace ContentSelectorModel void addFile(EsmFile *file); const EsmFile *item(int row) const; EsmFile *item(int row); + bool mShowGameFiles; void sortFiles(); diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index 2363ae477..9d35de8f6 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -13,21 +13,21 @@ #include #include -ContentSelectorView::ContentSelector::ContentSelector(QWidget *parent) : +ContentSelectorView::ContentSelector::ContentSelector(QWidget *parent, bool showGameFiles) : QObject(parent) { ui.setupUi(parent); ui.addonView->setDragDropMode(QAbstractItemView::InternalMove); - buildContentModel(); + buildContentModel(showGameFiles); buildGameFileView(); buildAddonView(); } -void ContentSelectorView::ContentSelector::buildContentModel() +void ContentSelectorView::ContentSelector::buildContentModel(bool showGameFiles) { QIcon warningIcon(ui.addonView->style()->standardIcon(QStyle::SP_MessageBoxWarning).pixmap(QSize(16, 15))); - mContentModel = new ContentSelectorModel::ContentModel(this, warningIcon); + mContentModel = new ContentSelectorModel::ContentModel(this, warningIcon, showGameFiles); } void ContentSelectorView::ContentSelector::buildGameFileView() diff --git a/components/contentselector/view/contentselector.hpp b/components/contentselector/view/contentselector.hpp index 2507cf6ad..eb060f7a9 100644 --- a/components/contentselector/view/contentselector.hpp +++ b/components/contentselector/view/contentselector.hpp @@ -23,7 +23,7 @@ namespace ContentSelectorView public: - explicit ContentSelector(QWidget *parent = 0); + explicit ContentSelector(QWidget *parent = 0, bool showGameFiles = false); QString currentFile() const; @@ -48,7 +48,7 @@ namespace ContentSelectorView Ui::ContentSelector ui; - void buildContentModel(); + void buildContentModel(bool showGameFiles); void buildGameFileView(); void buildAddonView(); void setGameFileSelected(int index, bool selected); From 5ff66ad40b5f439e9fb676c1b5ab90a473753d59 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 1 Mar 2015 13:09:23 +1100 Subject: [PATCH 527/740] Fix Bug #2402. SKIL records should not have NAME subrecord. --- apps/opencs/model/doc/savingstages.hpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.hpp b/apps/opencs/model/doc/savingstages.hpp index 87c9ba7eb..6607e9968 100644 --- a/apps/opencs/model/doc/savingstages.hpp +++ b/apps/opencs/model/doc/savingstages.hpp @@ -103,8 +103,20 @@ namespace CSMDoc if (state==CSMWorld::RecordBase::State_Modified || state==CSMWorld::RecordBase::State_ModifiedOnly) { - mState.getWriter().startRecord (mCollection.getRecord (stage).mModified.sRecordId); - mState.getWriter().writeHNCString ("NAME", mCollection.getId (stage)); + // FIXME: A quick Workaround to support SKIL records which should not write NAME. + // If there are more idcollection records that don't use NAME then a more + // generic solution may be required. The conversion code was simply + // copied from esmwriter. There's room for improving speed a little bit + // here if it turns out to be an issue. + uint32_t name = mCollection.getRecord (stage).mModified.sRecordId; + mState.getWriter().startRecord (name); + std::string type; + for (int i=0; i<4; ++i) + /// \todo make endianess agnostic + type += reinterpret_cast (&name)[i]; + + if(type != "SKIL") + mState.getWriter().writeHNCString ("NAME", mCollection.getId (stage)); mCollection.getRecord (stage).mModified.save (mState.getWriter()); mState.getWriter().endRecord (mCollection.getRecord (stage).mModified.sRecordId); } From cdee6f41fc651dc68d256e29e5a6e3c560d5b9d5 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 1 Mar 2015 15:34:18 +1300 Subject: [PATCH 528/740] fix: multi effect spell with different ranges (Fixes #2285) Applies all effects for a spell with multiple effects, where not all effects have the same range. --- apps/openmw/mwmechanics/activespells.cpp | 43 +++++++++++++++++++----- apps/openmw/mwmechanics/activespells.hpp | 3 ++ 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index 6e15449e1..eec4f2bd3 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -152,12 +152,7 @@ namespace MWMechanics void ActiveSpells::addSpell(const std::string &id, bool stack, std::vector effects, const std::string &displayName, int casterActorId) { - bool exists = false; - for (TContainer::const_iterator it = begin(); it != end(); ++it) - { - if (id == it->first) - exists = true; - } + TContainer::iterator it(mSpells.find(id)); ActiveSpellParams params; params.mTimeStamp = MWBase::Environment::get().getWorld()->getTimeStamp(); @@ -165,14 +160,44 @@ namespace MWMechanics params.mDisplayName = displayName; params.mCasterActorId = casterActorId; - if (!exists || stack) - mSpells.insert (std::make_pair(id, params)); + if (it == end() || stack) + { + mSpells.insert(std::make_pair(id, params)); + } else - mSpells.find(id)->second = params; + { + // addSpell() is called with effects for a range. + // but a spell may have effects with different ranges (e.g. Touch & Target) + // so, if we see new effects for same spell assume additional + // spell effects and add to existing effects of spell + mergeEffects(params.mEffects, it->second.mEffects); + it->second = params; + } mSpellsChanged = true; } + void ActiveSpells::mergeEffects(std::vector& addTo, const std::vector& from) + { + for (std::vector::const_iterator effect(from.begin()); effect != from.end(); ++effect) + { + // if effect is not in addTo, add it + bool missing = true; + for (std::vector::const_iterator iter(addTo.begin()); iter != addTo.end(); ++iter) + { + if (effect->mEffectId == iter->mEffectId) + { + missing = false; + break; + } + } + if (missing) + { + addTo.push_back(*effect); + } + } + } + void ActiveSpells::removeEffects(const std::string &id) { mSpells.erase(Misc::StringUtils::lowerCase(id)); diff --git a/apps/openmw/mwmechanics/activespells.hpp b/apps/openmw/mwmechanics/activespells.hpp index 4f9d15d8c..2a4d75d40 100644 --- a/apps/openmw/mwmechanics/activespells.hpp +++ b/apps/openmw/mwmechanics/activespells.hpp @@ -55,6 +55,9 @@ namespace MWMechanics void rebuildEffects() const; + /// Add any effects that are in "from" and not in "addTo" to "addTo" + void mergeEffects(std::vector& addTo, const std::vector& from); + double timeToExpire (const TIterator& iterator) const; ///< Returns time (in in-game hours) until the spell pointed to by \a iterator /// expires. From 4c57cfc2d32c35a8acc156f4ccc8fff893a6528e Mon Sep 17 00:00:00 2001 From: sylar Date: Sun, 1 Mar 2015 09:49:33 +0400 Subject: [PATCH 529/740] fixes for glsles2 --- files/materials/atmosphere.shader | 2 +- files/materials/clouds.shader | 2 +- files/materials/moon.shader | 2 +- files/materials/objects.shader | 4 ++-- files/materials/stars.shader | 2 +- files/materials/sun.shader | 2 +- files/materials/terrain.shader | 2 +- files/materials/underwater.h | 4 ++-- files/materials/water.shader | 2 +- 9 files changed, 11 insertions(+), 11 deletions(-) diff --git a/files/materials/atmosphere.shader b/files/materials/atmosphere.shader index 5040052fc..3eaa73b1c 100644 --- a/files/materials/atmosphere.shader +++ b/files/materials/atmosphere.shader @@ -11,7 +11,7 @@ SH_START_PROGRAM { float4x4 viewFixed = view; -#if !SH_GLSL +#if !SH_GLSL && !SH_GLSLES viewFixed[0][3] = 0.0; viewFixed[1][3] = 0.0; viewFixed[2][3] = 0.0; diff --git a/files/materials/clouds.shader b/files/materials/clouds.shader index 93d0780e0..5902d2fdc 100644 --- a/files/materials/clouds.shader +++ b/files/materials/clouds.shader @@ -13,7 +13,7 @@ { float4x4 worldviewFixed = worldview; -#if !SH_GLSL +#if !SH_GLSL && !SH_GLSLES worldviewFixed[0][3] = 0.0; worldviewFixed[1][3] = 0.0; worldviewFixed[2][3] = 0.0; diff --git a/files/materials/moon.shader b/files/materials/moon.shader index 0e1a4ffc8..151b94180 100644 --- a/files/materials/moon.shader +++ b/files/materials/moon.shader @@ -12,7 +12,7 @@ shUniform(float4x4, projection) @shAutoConstant(projection, projection_matrix) SH_START_PROGRAM { float4x4 viewFixed = view; -#if !SH_GLSL +#if !SH_GLSL && !SH_GLSLES viewFixed[0][3] = 0.0; viewFixed[1][3] = 0.0; viewFixed[2][3] = 0.0; diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 828674cc7..5c74b1139 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -166,7 +166,7 @@ #if VIEWPROJ_FIX float4x4 vpFixed = vpMatrix; -#if !SH_GLSL +#if !SH_GLSL && !SH_GLSLES vpFixed[2] = vpRow2Fix; #else vpFixed[0][2] = vpRow2Fix.x; @@ -384,7 +384,7 @@ float4 normalTex = shSample(normalMap, UV.xy); - normal = normalize (shMatrixMult( transpose(tbn), normalTex.xyz * 2.0 - float3 (1.0,1.0,1.0) )); + normal = normalize (shMatrixMult( transpose(tbn), normalTex.xyz * 2.0 - 1.0 )); #endif #if ENV_MAP || SPECULAR || PARALLAX diff --git a/files/materials/stars.shader b/files/materials/stars.shader index f2eb616a2..830be862a 100644 --- a/files/materials/stars.shader +++ b/files/materials/stars.shader @@ -13,7 +13,7 @@ SH_START_PROGRAM { float4x4 worldviewFixed = worldview; -#if !SH_GLSL +#if !SH_GLSL && !SH_GLSLES worldviewFixed[0][3] = 0.0; worldviewFixed[1][3] = 0.0; worldviewFixed[2][3] = 0.0; diff --git a/files/materials/sun.shader b/files/materials/sun.shader index fc747b522..72e49d1a7 100644 --- a/files/materials/sun.shader +++ b/files/materials/sun.shader @@ -12,7 +12,7 @@ shUniform(float4x4, projection) @shAutoConstant(projection, projection_matrix) SH_START_PROGRAM { float4x4 viewFixed = view; -#if !SH_GLSL +#if !SH_GLSL && !SH_GLSLES viewFixed[0][3] = 0.0; viewFixed[1][3] = 0.0; viewFixed[2][3] = 0.0; diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index 9bb5d247d..f20fce506 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -136,7 +136,7 @@ #if NEED_DEPTH #if VIEWPROJ_FIX float4x4 vpFixed = viewProjMatrix; -#if !SH_GLSL +#if !SH_GLSL && !SH_GLSLES vpFixed[2] = vpRow2Fix; #else vpFixed[0][2] = vpRow2Fix.x; diff --git a/files/materials/underwater.h b/files/materials/underwater.h index 332a0fd7d..2f38f6546 100644 --- a/files/materials/underwater.h +++ b/files/materials/underwater.h @@ -93,7 +93,7 @@ float3 getCaustics (shTexture2D causticMap, float3 worldPos, float3 waterEyePos, // NOTE: the original shader calculated a tangent space basis here, // but using only the world normal is cheaper and i couldn't see a visual difference // also, if this effect gets moved to screen-space some day, it's unlikely to have tangent information - float3 causticNorm = worldNormal.xyz * perturb(causticMap, causticPos.xy, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).xyz * 2 - 1; + float3 causticNorm = worldNormal.xyz * perturb(causticMap, causticPos.xy, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).xyz * 2.0 - 1.0; causticNorm = float3(causticNorm.x, causticNorm.y, -causticNorm.z); //float fresnel = pow(clamp(dot(LV,causticnorm),0.0,1.0),2.0); @@ -111,7 +111,7 @@ float3 getCaustics (shTexture2D causticMap, float3 worldPos, float3 waterEyePos, //caustics = shSaturate(pow(float3(causticR,causticG,causticB)*5.5,float3(5.5*causticdepth)))*NdotL*sunFade*causticdepth; caustics = shSaturate(pow(float3(causticR,causticG,causticB)*5.5,float3(5.5*causticdepth,5.5*causticdepth,5.5*causticdepth)))*NdotL*causticdepth; - caustics *= 3; + caustics *= 3.0; // shore transition caustics = shLerp (float3(1,1,1), caustics, waterDepth); diff --git a/files/materials/water.shader b/files/materials/water.shader index 10d63cdf4..eff245b5e 100644 --- a/files/materials/water.shader +++ b/files/materials/water.shader @@ -97,7 +97,7 @@ shOutputPosition = shMatrixMult(wvp, shInputPosition); - #if !SH_GLSL + #if !SH_GLSL && !SH_GLSLES float4x4 scalemat = float4x4( 0.5, 0.0, 0.0, 0.5, 0.0, -0.5, 0.0, 0.5, 0.0, 0.0, 0.5, 0.5, From 239c0071f5233e436232f37a7fb8f42aa1f23973 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 1 Mar 2015 19:28:20 +0100 Subject: [PATCH 530/740] Armor tooltip should show the effective armor rating --- apps/openmw/mwclass/armor.cpp | 19 ++++++++++++++++++- apps/openmw/mwclass/armor.hpp | 3 +++ apps/openmw/mwclass/npc.cpp | 11 +---------- apps/openmw/mwworld/class.cpp | 5 +++++ apps/openmw/mwworld/class.hpp | 3 +++ 5 files changed, 30 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 64043157d..0f99d91da 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -245,7 +245,8 @@ namespace MWClass else typeText = "#{sHeavy}"; - text += "\n#{sArmorRating}: " + MWGui::ToolTips::toString(ref->mBase->mData.mArmor); + text += "\n#{sArmorRating}: " + MWGui::ToolTips::toString(getEffectiveArmorRating(ptr, + MWBase::Environment::get().getWorld()->getPlayerPtr())); int remainingHealth = getItemHealth(ptr); text += "\n#{sCondition}: " + MWGui::ToolTips::toString(remainingHealth) + "/" @@ -290,6 +291,22 @@ namespace MWClass return record->mId; } + int Armor::getEffectiveArmorRating(const MWWorld::Ptr &ptr, const MWWorld::Ptr &actor) const + { + MWWorld::LiveCellRef *ref = ptr.get(); + + int armorSkillType = getEquipmentSkill(ptr); + int armorSkill = actor.getClass().getSkill(actor, armorSkillType); + + const MWBase::World *world = MWBase::Environment::get().getWorld(); + int iBaseArmorSkill = world->getStore().get().find("iBaseArmorSkill")->getInt(); + + if(ref->mBase->mData.mWeight == 0) + return ref->mBase->mData.mArmor; + else + return ref->mBase->mData.mArmor * armorSkill / iBaseArmorSkill; + } + std::pair Armor::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const { MWWorld::InventoryStore& invStore = npc.getClass().getInventoryStore(npc); diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 8c8e74cf4..21d711a0d 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -86,6 +86,9 @@ namespace MWClass virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + + /// Get the effective armor rating, factoring in the actor's skills, for the given armor. + virtual int getEffectiveArmorRating(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; }; } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index cedff1291..52e5a0a95 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1086,7 +1086,6 @@ namespace MWClass MWMechanics::NpcStats &stats = getNpcStats(ptr); MWWorld::InventoryStore &invStore = getInventoryStore(ptr); - int iBaseArmorSkill = store.find("iBaseArmorSkill")->getInt(); float fUnarmoredBase1 = store.find("fUnarmoredBase1")->getFloat(); float fUnarmoredBase2 = store.find("fUnarmoredBase2")->getFloat(); int unarmoredSkill = stats.getSkill(ESM::Skill::Unarmored).getModified(); @@ -1102,15 +1101,7 @@ namespace MWClass } else { - MWWorld::LiveCellRef *ref = it->get(); - - int armorSkillType = it->getClass().getEquipmentSkill(*it); - int armorSkill = stats.getSkill(armorSkillType).getModified(); - - if(ref->mBase->mData.mWeight == 0) - ratings[i] = ref->mBase->mData.mArmor; - else - ratings[i] = ref->mBase->mData.mArmor * armorSkill / iBaseArmorSkill; + ratings[i] = it->getClass().getEffectiveArmorRating(*it, ptr); } } diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index afc5ed635..6fa9ba9b6 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -454,4 +454,9 @@ namespace MWWorld { return -1; } + + int Class::getEffectiveArmorRating(const Ptr &ptr, const Ptr &actor) const + { + throw std::runtime_error("class does not support armor ratings"); + } } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 380d2a34b..782aa7815 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -347,6 +347,9 @@ namespace MWWorld virtual std::string getPrimaryFaction (const MWWorld::Ptr& ptr) const; virtual int getPrimaryFactionRank (const MWWorld::Ptr& ptr) const; + + /// Get the effective armor rating, factoring in the actor's skills, for the given armor. + virtual int getEffectiveArmorRating(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; }; } From 1ee615394095a3367cc0d4544aab6b0de55877d9 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 2 Mar 2015 06:51:31 +1100 Subject: [PATCH 531/740] Remove unnecessary boolean passing between objects. --- apps/opencs/view/doc/filedialog.cpp | 2 +- components/contentselector/model/contentmodel.cpp | 14 ++++---------- components/contentselector/model/contentmodel.hpp | 3 +-- .../contentselector/view/contentselector.cpp | 8 ++++---- .../contentselector/view/contentselector.hpp | 4 ++-- 5 files changed, 12 insertions(+), 19 deletions(-) diff --git a/apps/opencs/view/doc/filedialog.cpp b/apps/opencs/view/doc/filedialog.cpp index c895a3399..8dd83f24a 100644 --- a/apps/opencs/view/doc/filedialog.cpp +++ b/apps/opencs/view/doc/filedialog.cpp @@ -24,7 +24,7 @@ CSVDoc::FileDialog::FileDialog(QWidget *parent) : resize(400, 400); setObjectName ("FileDialog"); - mSelector = new ContentSelectorView::ContentSelector (ui.contentSelectorWidget, true); + mSelector = new ContentSelectorView::ContentSelector (ui.contentSelectorWidget); mAdjusterWidget = new AdjusterWidget (this); } diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 3e3536413..3dc02af21 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -9,14 +9,13 @@ #include "components/esm/esmreader.hpp" -ContentSelectorModel::ContentModel::ContentModel(QObject *parent, QIcon warningIcon, bool showGameFiles) : +ContentSelectorModel::ContentModel::ContentModel(QObject *parent, QIcon warningIcon) : QAbstractTableModel(parent), mWarningIcon(warningIcon), mMimeType ("application/omwcontent"), mMimeTypes (QStringList() << mMimeType), mColumnCount (1), - mDropActions (Qt::MoveAction), - mShowGameFiles(showGameFiles) + mDropActions (Qt::MoveAction) { setEncoding ("win1252"); uncheckAll(); @@ -111,14 +110,9 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index if (!file) return Qt::NoItemFlags; - //game files are not shown (unless OpenCS) + //game files can always be checked if (file->isGameFile()) - { - if(mShowGameFiles) - return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable; - else - return Qt::NoItemFlags; - } + return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable; Qt::ItemFlags returnFlags; diff --git a/components/contentselector/model/contentmodel.hpp b/components/contentselector/model/contentmodel.hpp index 887ad51b3..658555852 100644 --- a/components/contentselector/model/contentmodel.hpp +++ b/components/contentselector/model/contentmodel.hpp @@ -23,7 +23,7 @@ namespace ContentSelectorModel { Q_OBJECT public: - explicit ContentModel(QObject *parent, QIcon warningIcon, bool showGameFiles = false); + explicit ContentModel(QObject *parent, QIcon warningIcon); ~ContentModel(); void setEncoding(const QString &encoding); @@ -66,7 +66,6 @@ namespace ContentSelectorModel void addFile(EsmFile *file); const EsmFile *item(int row) const; EsmFile *item(int row); - bool mShowGameFiles; void sortFiles(); diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index 9d35de8f6..2363ae477 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -13,21 +13,21 @@ #include #include -ContentSelectorView::ContentSelector::ContentSelector(QWidget *parent, bool showGameFiles) : +ContentSelectorView::ContentSelector::ContentSelector(QWidget *parent) : QObject(parent) { ui.setupUi(parent); ui.addonView->setDragDropMode(QAbstractItemView::InternalMove); - buildContentModel(showGameFiles); + buildContentModel(); buildGameFileView(); buildAddonView(); } -void ContentSelectorView::ContentSelector::buildContentModel(bool showGameFiles) +void ContentSelectorView::ContentSelector::buildContentModel() { QIcon warningIcon(ui.addonView->style()->standardIcon(QStyle::SP_MessageBoxWarning).pixmap(QSize(16, 15))); - mContentModel = new ContentSelectorModel::ContentModel(this, warningIcon, showGameFiles); + mContentModel = new ContentSelectorModel::ContentModel(this, warningIcon); } void ContentSelectorView::ContentSelector::buildGameFileView() diff --git a/components/contentselector/view/contentselector.hpp b/components/contentselector/view/contentselector.hpp index eb060f7a9..2507cf6ad 100644 --- a/components/contentselector/view/contentselector.hpp +++ b/components/contentselector/view/contentselector.hpp @@ -23,7 +23,7 @@ namespace ContentSelectorView public: - explicit ContentSelector(QWidget *parent = 0, bool showGameFiles = false); + explicit ContentSelector(QWidget *parent = 0); QString currentFile() const; @@ -48,7 +48,7 @@ namespace ContentSelectorView Ui::ContentSelector ui; - void buildContentModel(bool showGameFiles); + void buildContentModel(); void buildGameFileView(); void buildAddonView(); void setGameFileSelected(int index, bool selected); From a653716e2c08df5581771452ac6d4e067fd66be3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 1 Mar 2015 22:22:20 +0100 Subject: [PATCH 532/740] Fix for damage/restore effects using the instant apply path when they have a duration --- apps/openmw/mwmechanics/spellcasting.cpp | 58 ++++++++++-------------- 1 file changed, 24 insertions(+), 34 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index e702401a6..b91ea9984 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -64,8 +64,9 @@ namespace } // TODO: refactor the effect tick functions in Actors so they can be reused here - void applyInstantEffectTick(int effectId, const MWWorld::Ptr& target, float magnitude) + void applyInstantEffectTick(MWMechanics::EffectKey effect, const MWWorld::Ptr& target, float magnitude) { + int effectId = effect.mId; if (effectId == ESM::MagicEffect::DamageHealth) { applyDynamicStatsEffect(0, target, magnitude * -1); @@ -90,6 +91,27 @@ namespace { applyDynamicStatsEffect(1, target, magnitude); } + else if (effectId == ESM::MagicEffect::DamageAttribute || effectId == ESM::MagicEffect::RestoreAttribute) + { + int attribute = effect.mArg; + MWMechanics::AttributeValue value = target.getClass().getCreatureStats(target).getAttribute(attribute); + if (effectId == ESM::MagicEffect::DamageAttribute) + value.damage(magnitude); + else + value.restore(magnitude); + target.getClass().getCreatureStats(target).setAttribute(attribute, value); + } + else if (effectId == ESM::MagicEffect::DamageSkill || effectId == ESM::MagicEffect::RestoreSkill) + { + if (target.getTypeName() != typeid(ESM::NPC).name()) + return; + int skill = effect.mArg; + MWMechanics::SkillValue& value = target.getClass().getNpcStats(target).getSkill(skill); + if (effectId == ESM::MagicEffect::DamageSkill) + value.damage(magnitude); + else + value.restore(magnitude); + } } } @@ -509,7 +531,7 @@ namespace MWMechanics else { if (hasDuration && target.getClass().isActor()) - applyInstantEffectTick(effectIt->mEffectID, target, magnitude); + applyInstantEffectTick(EffectKey(*effectIt), target, magnitude); else applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude); } @@ -526,16 +548,6 @@ namespace MWMechanics } } - // HACK: Damage attribute/skill actually has a duration, even though the actual effect is instant and permanent. - // This was probably just done to have the effect visible in the magic menu for a while - // to notify the player they've been damaged? - if (effectIt->mEffectID == ESM::MagicEffect::DamageAttribute - || effectIt->mEffectID == ESM::MagicEffect::DamageSkill - || effectIt->mEffectID == ESM::MagicEffect::RestoreAttribute - || effectIt->mEffectID == ESM::MagicEffect::RestoreSkill - ) - applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude); - if (target.getClass().isActor() || magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration) { // Play sound, only for the first effect @@ -625,28 +637,6 @@ namespace MWMechanics } else { - if (effectId == ESM::MagicEffect::DamageAttribute || effectId == ESM::MagicEffect::RestoreAttribute) - { - int attribute = effect.mArg; - AttributeValue value = target.getClass().getCreatureStats(target).getAttribute(attribute); - if (effectId == ESM::MagicEffect::DamageAttribute) - value.damage(magnitude); - else - value.restore(magnitude); - target.getClass().getCreatureStats(target).setAttribute(attribute, value); - } - else if (effectId == ESM::MagicEffect::DamageSkill || effectId == ESM::MagicEffect::RestoreSkill) - { - if (target.getTypeName() != typeid(ESM::NPC).name()) - return; - int skill = effect.mArg; - SkillValue& value = target.getClass().getNpcStats(target).getSkill(skill); - if (effectId == ESM::MagicEffect::DamageSkill) - value.damage(magnitude); - else - value.restore(magnitude); - } - if (effectId == ESM::MagicEffect::CurePoison) target.getClass().getCreatureStats(target).getActiveSpells().purgeEffect(ESM::MagicEffect::Poison); else if (effectId == ESM::MagicEffect::CureParalyzation) From fb0fdf0312d872bad23e8db1fcde0426351e997b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 1 Mar 2015 23:58:16 +0100 Subject: [PATCH 533/740] New look for fps counter --- files/mygui/openmw_hud.layout | 18 +++++++++--------- files/mygui/openmw_text.skin.xml | 4 +++- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/files/mygui/openmw_hud.layout b/files/mygui/openmw_hud.layout index 8334e34b9..0cbe0dd97 100644 --- a/files/mygui/openmw_hud.layout +++ b/files/mygui/openmw_hud.layout @@ -127,35 +127,35 @@
- + - + - + - + - - + + - - + + - + diff --git a/files/mygui/openmw_text.skin.xml b/files/mygui/openmw_text.skin.xml index fe01d3417..e459f22fa 100644 --- a/files/mygui/openmw_text.skin.xml +++ b/files/mygui/openmw_text.skin.xml @@ -19,9 +19,11 @@ color_misc=0,205,205 # ???? - + + + From 0ad514b29be91a0bac47bc46f6cc6ebfc831413e Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Mar 2015 01:03:03 +0100 Subject: [PATCH 534/740] Fix collision for nodes with MRK extra data (Fixes #2415) --- components/nifbullet/bulletnifloader.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 35d552726..cdc06f985 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -274,10 +274,12 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, // No collision. Use an internal flag setting to mark this. flags |= 0x800; } - else if (sd->string == "MRK" && !mShowMarkers) - // Marker objects. These are only visible in the - // editor. + else if (sd->string == "MRK" && !mShowMarkers && raycasting) + { + // Marker objects should be invisible, but still have collision. + // Except in the editor, the marker objects are visible. return; + } } } From 191c0104f600abfa1edd27590790302bec17f36a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Mar 2015 15:19:57 +0100 Subject: [PATCH 535/740] Crash fix for creatures with no skeleton base (Fixes #2419) --- apps/openmw/mwrender/animation.cpp | 4 ++ apps/openmw/mwrender/creatureanimation.cpp | 7 +++- apps/openmw/mwrender/npcanimation.cpp | 46 +++++++++++++--------- 3 files changed, 37 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 50afc5afd..01a88faf2 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1271,7 +1271,11 @@ void Animation::addEffect(const std::string &model, int effectId, bool loop, con if (bonename.empty()) params.mObjects = NifOgre::Loader::createObjects(mInsert, model); else + { + if (!mSkelBase) + return; params.mObjects = NifOgre::Loader::createObjects(mSkelBase, bonename, "", mInsert, model); + } setRenderProperties(params.mObjects, RV_Effects, RQG_Main, RQG_Alpha, 0.f, false, NULL); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 2bdf8a499..7260fc6d1 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -88,6 +88,9 @@ void CreatureWeaponAnimation::updateParts() void CreatureWeaponAnimation::updatePart(NifOgre::ObjectScenePtr& scene, int slot) { + if (!mSkelBase) + return; + MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr); MWWorld::ContainerStoreIterator it = inv.getSlot(slot); @@ -181,7 +184,9 @@ void CreatureWeaponAnimation::releaseArrow() Ogre::Vector3 CreatureWeaponAnimation::runAnimation(float duration) { Ogre::Vector3 ret = Animation::runAnimation(duration); - pitchSkeleton(mPtr.getRefData().getPosition().rot[0], mSkelBase->getSkeleton()); + + if (mSkelBase) + pitchSkeleton(mPtr.getRefData().getPosition().rot[0], mSkelBase->getSkeleton()); if (!mWeapon.isNull()) { diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 0926498c0..66ba25859 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -335,7 +335,10 @@ void NpcAnimation::updateNpcBase() } void NpcAnimation::updateParts() -{ +{ + if (!mSkelBase) + return; + mAlpha = 1.f; const MWWorld::Class &cls = mPtr.getClass(); @@ -621,30 +624,33 @@ NifOgre::ObjectScenePtr NpcAnimation::insertBoundedPart(const std::string &model } Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) -{ +{ Ogre::Vector3 ret = Animation::runAnimation(timepassed); mHeadAnimationTime->update(timepassed); - Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); - if(mViewMode == VM_FirstPerson) + if (mSkelBase) { - float pitch = mPtr.getRefData().getPosition().rot[0]; - Ogre::Node *node = baseinst->getBone("Bip01 Neck"); - node->pitch(Ogre::Radian(-pitch), Ogre::Node::TS_WORLD); + Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); + if(mViewMode == VM_FirstPerson) + { + float pitch = mPtr.getRefData().getPosition().rot[0]; + Ogre::Node *node = baseinst->getBone("Bip01 Neck"); + node->pitch(Ogre::Radian(-pitch), Ogre::Node::TS_WORLD); - // This has to be done before this function ends; - // updateSkeletonInstance, below, touches the hands. - node->translate(mFirstPersonOffset, Ogre::Node::TS_WORLD); - } - else - { - // In third person mode we may still need pitch for ranged weapon targeting - pitchSkeleton(mPtr.getRefData().getPosition().rot[0], baseinst); + // This has to be done before this function ends; + // updateSkeletonInstance, below, touches the hands. + node->translate(mFirstPersonOffset, Ogre::Node::TS_WORLD); + } + else + { + // In third person mode we may still need pitch for ranged weapon targeting + pitchSkeleton(mPtr.getRefData().getPosition().rot[0], baseinst); - Ogre::Node* node = baseinst->getBone("Bip01 Head"); - if (node) - node->rotate(Ogre::Quaternion(mHeadYaw, Ogre::Vector3::UNIT_Z) * Ogre::Quaternion(mHeadPitch, Ogre::Vector3::UNIT_X), Ogre::Node::TS_WORLD); + Ogre::Node* node = baseinst->getBone("Bip01 Head"); + if (node) + node->rotate(Ogre::Quaternion(mHeadYaw, Ogre::Vector3::UNIT_Z) * Ogre::Quaternion(mHeadPitch, Ogre::Vector3::UNIT_X), Ogre::Node::TS_WORLD); + } } mFirstPersonOffset = 0.f; // reset the X, Y, Z offset for the next frame. @@ -659,7 +665,9 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) if (!isSkinned(mObjectParts[i])) continue; - updateSkeletonInstance(baseinst, mObjectParts[i]->mSkelBase->getSkeleton()); + if (mSkelBase) + updateSkeletonInstance(mSkelBase->getSkeleton(), mObjectParts[i]->mSkelBase->getSkeleton()); + mObjectParts[i]->mSkelBase->getAllAnimationStates()->_notifyDirty(); } From c57f9ad5dc0e9c4cb5cac02eb9dca2ce5c172a81 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Mar 2015 15:44:27 +0100 Subject: [PATCH 536/740] CMake: don't use CMAKE_CXX_FLAGS for gcc warning levels, it only works for CMAKE_BUILD_TYPE=None --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ed6d6e17..20b38ce95 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -387,12 +387,12 @@ endif() # Compiler settings if (CMAKE_COMPILER_IS_GNUCC) - SET(CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++98 -pedantic -Wno-long-long ${CMAKE_CXX_FLAGS}") + set_property(GLOBAL APPEND_STRING PROPERTY COMPILE_FLAGS "-Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++98 -pedantic -Wno-long-long") execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) if ("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6) - SET(CMAKE_CXX_FLAGS "-Wno-unused-but-set-parameter ${CMAKE_CXX_FLAGS}") + set_property(GLOBAL APPEND_STRING PROPERTY COMPILE_FLAGS "-Wno-unused-but-set-parameter") endif("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6) elseif (MSVC) # Enable link-time code generation globally for all linking From c6aa374934f7ffbcb5bff6ba221cbc61cc1587e7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Mar 2015 15:45:29 +0100 Subject: [PATCH 537/740] CMake: set windows warning levels globally instead of per target --- CMakeLists.txt | 30 ++++-------------------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 20b38ce95..7b668cde1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -705,43 +705,21 @@ if (WIN32) set(WARNINGS "${WARNINGS} /wd${d}") endforeach(d) + set_property(GLOBAL APPEND_STRING PROPERTY COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + # boost::wave has a few issues with signed / unsigned conversions, so we suppress those here set(SHINY_WARNINGS "${WARNINGS} /wd4245") set_target_properties(shiny PROPERTIES COMPILE_FLAGS "${SHINY_WARNINGS} ${MT_BUILD}") - set_target_properties(shiny.OgrePlatform PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") - set_target_properties(sdl4ogre PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + # oics uses tinyxml, which has an initialized but unused variable set(OICS_WARNINGS "${WARNINGS} /wd4189") set_target_properties(oics PROPERTIES COMPILE_FLAGS "${OICS_WARNINGS} ${MT_BUILD}") - set_target_properties(components PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") - set_target_properties(ogre-ffmpeg-videoplayer PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") - if (BUILD_MYGUI_PLUGIN) - set_target_properties(Plugin_MyGUI_OpenMW_Resources PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") - endif (BUILD_MYGUI_PLUGIN) - if (BUILD_LAUNCHER) - set_target_properties(openmw-launcher PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") - endif (BUILD_LAUNCHER) - set_target_properties(openmw PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") - if (BUILD_BSATOOL) - set_target_properties(bsatool PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") - endif (BUILD_BSATOOL) - if (BUILD_ESMTOOL) - set_target_properties(esmtool PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") - endif (BUILD_ESMTOOL) - if (BUILD_WIZARD) - set_target_properties(openmw-wizard PROPERTIES COMPILE_FLAGS ${WARNINGS}) - endif (BUILD_WIZARD) + if (BUILD_OPENCS) # QT triggers an informational warning that the object layout may differ when compiled with /vd2 set(OPENCS_WARNINGS "${WARNINGS} ${MT_BUILD} /wd4435") set_target_properties(openmw-cs PROPERTIES COMPILE_FLAGS ${OPENCS_WARNINGS}) endif (BUILD_OPENCS) - if (BUILD_ESSIMPORTER) - set_target_properties(openmw-essimporter PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") - endif (BUILD_ESSIMPORTER) - if (BUILD_MWINIIMPORTER) - set_target_properties(openmw-iniimporter PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") - endif (BUILD_MWINIIMPORTER) endif(MSVC) # Same for MinGW From 1eaa64c49caeb753facf36c5173d5236c1f969e0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Mar 2015 15:45:44 +0100 Subject: [PATCH 538/740] CMake: remove lines for MinGW, no one is maintaining those --- CMakeLists.txt | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b668cde1..b01525692 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -722,22 +722,6 @@ if (WIN32) endif (BUILD_OPENCS) endif(MSVC) - # Same for MinGW - if (MINGW) - if (USE_DEBUG_CONSOLE) - set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "-Wl,-subsystem,console") - set_target_properties(openmw PROPERTIES LINK_FLAGS_RELWITHDEBINFO "-Wl,-subsystem,console") - set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS_DEBUG "_CONSOLE") - else(USE_DEBUG_CONSOLE) - set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "-Wl,-subsystem,windows") - set_target_properties(openmw PROPERTIES LINK_FLAGS_RELWITHDEBINFO "-Wl,-subsystem,windows") - endif(USE_DEBUG_CONSOLE) - - set_target_properties(openmw PROPERTIES LINK_FLAGS_RELEASE "-Wl,-subsystem,console") - set_target_properties(openmw PROPERTIES LINK_FLAGS_MINSIZEREL "-Wl,-subsystem,console") - set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS_RELEASE "_CONSOLE") - endif(MINGW) - # TODO: At some point release builds should not use the console but rather write to a log file #set_target_properties(openmw PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS") #set_target_properties(openmw PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:WINDOWS") From 730138035d1e532a928baa29e418241a4d562ef6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Mar 2015 17:25:26 +0100 Subject: [PATCH 539/740] Cycle infinite loop fix (Fixes #2421) --- apps/openmw/mwgui/inventorywindow.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 4270c4be1..e8e88ef65 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -653,16 +653,13 @@ namespace MWGui if (selected != -1) lastId = model.getItem(selected).mBase.getCellRef().getRefId(); ItemModel::ModelIndex cycled = selected; - while (!found) + for (int i=0; i Date: Mon, 2 Mar 2015 11:53:59 -0500 Subject: [PATCH 540/740] if cell doesn't exist, PositionCell and PlaceItemCell warn std::err but still execute, bug #2407 --- .../mwscript/transformationextensions.cpp | 28 ++++++++----------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 7af35a9ff..9166bf909 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -310,12 +310,13 @@ namespace MWScript } catch(std::exception&) { - const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getExterior(cellID); - if(cell) + const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getExterior(cellID); + int cx,cy; + MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy); + store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); + if(!cell) { - int cx,cy; - MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy); - store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); + std::cerr << "unknown cell (" << cellID << ")\n"; } } if(store) @@ -335,10 +336,6 @@ namespace MWScript ptr.getClass().adjustPosition(ptr, false); } - else - { - throw std::runtime_error (std::string("unknown cell (") + cellID + ")"); - } } }; @@ -426,11 +423,12 @@ namespace MWScript catch(std::exception&) { const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getExterior(cellID); - if(cell) + int cx,cy; + MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy); + store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); + if(!cell) { - int cx,cy; - MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy); - store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); + std::cerr << "unknown cell (" << cellID << ")\n"; } } if(store) @@ -446,10 +444,6 @@ namespace MWScript MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,pos); placed.getClass().adjustPosition(placed, true); } - else - { - throw std::runtime_error ( std::string("unknown cell (") + cellID + ")"); - } } }; From 653ddd3f2520cefa189901f195aca181bd9a0a53 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Mar 2015 20:16:11 +0100 Subject: [PATCH 541/740] Warning 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 e8e88ef65..b0adddffa 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -653,7 +653,7 @@ namespace MWGui if (selected != -1) lastId = model.getItem(selected).mBase.getCellRef().getRefId(); ItemModel::ModelIndex cycled = selected; - for (int i=0; i Date: Mon, 2 Mar 2015 21:12:21 +0100 Subject: [PATCH 542/740] Remove "loading cell" message This spams the log too much, in particular when loading a savegame. --- apps/openmw/mwworld/cellstore.cpp | 2 -- apps/openmw/mwworld/scene.cpp | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 545bbd4b3..7da7c187d 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -407,8 +407,6 @@ namespace MWWorld if (mState==State_Preloaded) mIds.clear(); - std::cout << "loading cell " << mCell->getDescription() << std::endl; - loadRefs (store, esm); mState = State_Loaded; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 08767df80..96e5ef224 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -219,6 +219,8 @@ namespace MWWorld if(result.second) { + std::cout << "loading cell " << cell->getCell()->getDescription() << std::endl; + float verts = ESM::Land::LAND_SIZE; float worldsize = ESM::Land::REAL_SIZE; From a8427c2efb6427c5751cda271e8db2408aa0e2b9 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 3 Mar 2015 07:36:11 +1100 Subject: [PATCH 543/740] Do not add NAME subrecords while saving magic effects or scripts. --- apps/opencs/model/doc/savingstages.hpp | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.hpp b/apps/opencs/model/doc/savingstages.hpp index 6607e9968..8b79f2ddb 100644 --- a/apps/opencs/model/doc/savingstages.hpp +++ b/apps/opencs/model/doc/savingstages.hpp @@ -103,19 +103,14 @@ namespace CSMDoc if (state==CSMWorld::RecordBase::State_Modified || state==CSMWorld::RecordBase::State_ModifiedOnly) { - // FIXME: A quick Workaround to support SKIL records which should not write NAME. - // If there are more idcollection records that don't use NAME then a more - // generic solution may be required. The conversion code was simply - // copied from esmwriter. There's room for improving speed a little bit - // here if it turns out to be an issue. + // FIXME: A quick Workaround to support records which should not write + // NAME, including SKIL, MGEF and SCPT. If there are many more + // idcollection records that doesn't use NAME then a more generic + // solution may be required. uint32_t name = mCollection.getRecord (stage).mModified.sRecordId; mState.getWriter().startRecord (name); - std::string type; - for (int i=0; i<4; ++i) - /// \todo make endianess agnostic - type += reinterpret_cast (&name)[i]; - if(type != "SKIL") + if(name != ESM::REC_SKIL && name != ESM::REC_MGEF && name != ESM::REC_SCPT) mState.getWriter().writeHNCString ("NAME", mCollection.getId (stage)); mCollection.getRecord (stage).mModified.save (mState.getWriter()); mState.getWriter().endRecord (mCollection.getRecord (stage).mModified.sRecordId); From 8eb1f4e70e5e7a431c807d2412ca32bfafa20cb8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Mar 2015 22:13:50 +0100 Subject: [PATCH 544/740] Remove more log spam --- apps/openmw/mwworld/scene.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 96e5ef224..8d689240b 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -492,8 +492,6 @@ namespace MWWorld loadingListener->setProgressRange(refsToLoad); // Load cell. - std::cout << "cellName: " << cell->getCell()->mName << std::endl; - loadCell (cell, loadingListener); changePlayerCell(cell, position, true); From f6509fe53eeffd1fc3834616b68989b09300087c Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Mar 2015 22:23:00 +0100 Subject: [PATCH 545/740] Another crash fix for land record without data --- apps/opencs/view/render/cell.cpp | 2 +- components/esmterrain/storage.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index a0d0f6e71..ae2fad95a 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -78,7 +78,7 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, if (landIndex != -1) { const ESM::Land* esmLand = land.getRecord(mId).get().mLand.get(); - if(esmLand) + if(esmLand && esmLand->mDataTypes&ESM::Land::DATA_VHGT) { mTerrain.reset(new Terrain::TerrainGrid(sceneManager, new TerrainStorage(mData), Element_Terrain, true, Terrain::Align_XY)); diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index d4a0a0df2..e925a1e17 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -383,7 +383,7 @@ namespace ESMTerrain int cellY = std::floor(worldPos.y / 8192.f); ESM::Land* land = getLand(cellX, cellY); - if (!land) + if (!land || !(land->mDataTypes&ESM::Land::DATA_VHGT)) return -2048; // Mostly lifted from Ogre::Terrain::getHeightAtTerrainPosition From 7c0f5b72c5941ccca810fff45fe6286fc6be68bf Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 3 Mar 2015 08:31:06 +1100 Subject: [PATCH 546/740] Add enum namespace to workaround travis. --- apps/opencs/model/doc/savingstages.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/doc/savingstages.hpp b/apps/opencs/model/doc/savingstages.hpp index 8b79f2ddb..edf8c2640 100644 --- a/apps/opencs/model/doc/savingstages.hpp +++ b/apps/opencs/model/doc/savingstages.hpp @@ -110,7 +110,8 @@ namespace CSMDoc uint32_t name = mCollection.getRecord (stage).mModified.sRecordId; mState.getWriter().startRecord (name); - if(name != ESM::REC_SKIL && name != ESM::REC_MGEF && name != ESM::REC_SCPT) + if(name != ESM::RecNameInts::REC_SKIL && + name != ESM::RecNameInts::REC_MGEF && name != ESM::RecNameInts::REC_SCPT) mState.getWriter().writeHNCString ("NAME", mCollection.getId (stage)); mCollection.getRecord (stage).mModified.save (mState.getWriter()); mState.getWriter().endRecord (mCollection.getRecord (stage).mModified.sRecordId); From 17e3069896f9d5453281650b4f6bb6ed81c7fc9d Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Mar 2015 22:33:37 +0100 Subject: [PATCH 547/740] Minor efficiency fix --- components/esmterrain/storage.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index e925a1e17..9c7beebce 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -465,8 +465,9 @@ namespace ESMTerrain Terrain::LayerInfo Storage::getLayerInfo(const std::string& texture) { // Already have this cached? - if (mLayerInfoMap.find(texture) != mLayerInfoMap.end()) - return mLayerInfoMap[texture]; + std::map::iterator found = mLayerInfoMap.find(texture); + if (found != mLayerInfoMap.end()) + return found->second; Terrain::LayerInfo info; info.mParallax = false; From 666248618eb2e4ca2003f51a5dbc1891baa98998 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Mar 2015 23:20:59 +0100 Subject: [PATCH 548/740] Fix reference cell movement leaving behind deleted Ptrs for script access --- apps/openmw/mwworld/worldimp.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 8a2b67bfc..3ef4f8e81 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1206,6 +1206,10 @@ namespace MWWorld } } ptr.getRefData().setCount(0); + // Deleted references can still be accessed by scripts, + // so we need this extra step to remove access to the old reference completely. + // This will no longer be necessary once we have a proper cell movement tracker. + ptr.getCellRef().unsetRefNum(); } } if (haveToMove && ptr.getRefData().getBaseNode()) From f09cbfb1678f7df933d858889dfa0da0b884afc1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Mar 2015 23:29:33 +0100 Subject: [PATCH 549/740] Add a comment --- apps/openmw/mwworld/store.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index a155a3760..50dd37ac0 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -555,6 +555,9 @@ namespace MWWorld if (left.first == right.first) return left.second > right.second; + // Exterior cells are listed in descending, row-major order, + // this is a workaround for an ambiguous chargen_plank reference in the vanilla game. + // there is one at -22,16 and one at -2,-9, the latter should be used. return left.first > right.first; } }; From 66ef9d237ce5612fa9940f716909667016f9f9d9 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 3 Mar 2015 10:12:40 +1100 Subject: [PATCH 550/740] Another try to make it work with gcc/travis. --- apps/opencs/model/doc/savingstages.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.hpp b/apps/opencs/model/doc/savingstages.hpp index edf8c2640..907041114 100644 --- a/apps/opencs/model/doc/savingstages.hpp +++ b/apps/opencs/model/doc/savingstages.hpp @@ -7,6 +7,8 @@ #include "../world/idcollection.hpp" #include "../world/scope.hpp" +#include + #include "savingstate.hpp" namespace ESM @@ -110,8 +112,7 @@ namespace CSMDoc uint32_t name = mCollection.getRecord (stage).mModified.sRecordId; mState.getWriter().startRecord (name); - if(name != ESM::RecNameInts::REC_SKIL && - name != ESM::RecNameInts::REC_MGEF && name != ESM::RecNameInts::REC_SCPT) + if(name != ESM::REC_SKIL && name != ESM::REC_MGEF && name != ESM::REC_SCPT) mState.getWriter().writeHNCString ("NAME", mCollection.getId (stage)); mCollection.getRecord (stage).mModified.save (mState.getWriter()); mState.getWriter().endRecord (mCollection.getRecord (stage).mModified.sRecordId); From a8cb4e807b63657bcb6c5d8c2937dee664cb5aba Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Mar 2015 11:23:50 +0100 Subject: [PATCH 551/740] Warning fix --- apps/openmw/mwinput/inputmanagerimp.cpp | 12 ++++++------ components/config/launchersettings.hpp | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 4212c562b..284919f64 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -816,7 +816,7 @@ namespace MWInput setPlayerControlsEnabled(!guiMode); - //esc, to leave inital movie screen + //esc, to leave initial movie screen OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); bool guiFocus = MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); setPlayerControlsEnabled(!guiFocus); @@ -843,7 +843,7 @@ namespace MWInput else mInputBinder->buttonReleased(deviceID, arg); - //to escape inital movie + //to escape initial movie OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); } @@ -1236,11 +1236,11 @@ namespace MWInput bool controlExists = mInputBinder->getChannel(i)->getControlsCount () != 0; if (!controlExists) { - int inital; + float initial; if (defaultButtonBindings.find(i) != defaultButtonBindings.end()) - inital = 0.0f; - else inital = 0.5f; - control = new ICS::Control(boost::lexical_cast(i), false, true, inital, ICS::ICS_MAX, ICS::ICS_MAX); + initial = 0.0f; + else initial = 0.5f; + control = new ICS::Control(boost::lexical_cast(i), false, true, initial, ICS::ICS_MAX, ICS::ICS_MAX); mInputBinder->addControl(control); control->attachChannel(mInputBinder->getChannel(i), ICS::Channel::DIRECT); } diff --git a/components/config/launchersettings.hpp b/components/config/launchersettings.hpp index cbe21c54a..c5eefb22a 100644 --- a/components/config/launchersettings.hpp +++ b/components/config/launchersettings.hpp @@ -17,7 +17,7 @@ namespace Config /// \return names of all Content Lists in the launcher's .cfg file. QStringList getContentLists(); - /// Set initally selected content list to match values from openmw.cfg, creating if necessary + /// Set initially selected content list to match values from openmw.cfg, creating if necessary void setContentList(const GameSettings& gameSettings); /// Create a Content List (or replace if it already exists) From cdf53c17e7e250717b26a2349d64744d13603d1d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 3 Mar 2015 11:54:35 +0100 Subject: [PATCH 552/740] updated version number --- CMakeLists.txt | 2 +- README.md | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b01525692..6b6944d5c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ message(STATUS "Configuring OpenMW...") set(OPENMW_VERSION_MAJOR 0) set(OPENMW_VERSION_MINOR 35) -set(OPENMW_VERSION_RELEASE 0) +set(OPENMW_VERSION_RELEASE 1) set(OPENMW_VERSION_COMMITHASH "") set(OPENMW_VERSION_TAGHASH "") diff --git a/README.md b/README.md index 63a313896..ce37de8c5 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ OpenMW OpenMW is an attempt at recreating the engine for the popular role-playing game Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work. -* Version: 0.35.0 +* Version: 0.35.1 * License: GPL (see docs/license/GPL3.txt for more information) * Website: http://www.openmw.org * IRC: #openmw on irc.freenode.net @@ -68,9 +68,9 @@ Command line options of the blacklist is enabled) --script-blacklist-use [=arg(=1)] (=1) enable script blacklisting - --load-savegame arg load a save game file on game startup - (specify an absolute filename or a - filename relative to the current + --load-savegame arg load a save game file on game startup + (specify an absolute filename or a + filename relative to the current working directory) --skip-menu [=arg(=1)] (=0) skip main menu on game startup --new-game [=arg(=1)] (=0) run new game sequence (ignored if From bf92d5cde9e501e2bfcc081707968938a79076a0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 3 Mar 2015 13:04:57 +0100 Subject: [PATCH 553/740] removed redundant mScript field in ESM::StartScript --- apps/esmtool/record.cpp | 2 +- apps/openmw/mwscript/globalscripts.cpp | 2 +- apps/openmw/mwworld/store.hpp | 13 ------------- components/esm/loadsscr.cpp | 4 ++-- components/esm/loadsscr.hpp | 2 +- 5 files changed, 5 insertions(+), 18 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 97b0635fe..6fd4b80fb 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -1253,7 +1253,7 @@ void Record::print() template<> void Record::print() { - std::cout << "Start Script: " << mData.mScript << std::endl; + std::cout << "Start Script: " << mData.mId << std::endl; std::cout << "Start Data: " << mData.mData << std::endl; } diff --git a/apps/openmw/mwscript/globalscripts.cpp b/apps/openmw/mwscript/globalscripts.cpp index 92fd51d87..a6ad2cc11 100644 --- a/apps/openmw/mwscript/globalscripts.cpp +++ b/apps/openmw/mwscript/globalscripts.cpp @@ -100,7 +100,7 @@ namespace MWScript mStore.get().begin(); iter != mStore.get().end(); ++iter) { - scripts.push_back (iter->mScript); + scripts.push_back (iter->mId); } // add scripts diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 50dd37ac0..a887272c5 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -364,19 +364,6 @@ namespace MWWorld inserted.first->second = scpt; } - template <> - inline void Store::load(ESM::ESMReader &esm, const std::string &id) { - ESM::StartScript s; - s.load(esm); - s.mId = Misc::StringUtils::toLower(s.mScript); - - std::pair inserted = mStatic.insert(std::make_pair(s.mId, s)); - if (inserted.second) - mShared.push_back(&inserted.first->second); - else - inserted.first->second = s; - } - template <> class Store : public StoreBase { diff --git a/components/esm/loadsscr.cpp b/components/esm/loadsscr.cpp index 816075b7e..9b02b51c9 100644 --- a/components/esm/loadsscr.cpp +++ b/components/esm/loadsscr.cpp @@ -23,7 +23,7 @@ namespace ESM hasData = true; break; case ESM::FourCC<'N','A','M','E'>::value: - mScript = esm.getHString(); + mId = esm.getHString(); hasName = true; break; default: @@ -38,7 +38,7 @@ namespace ESM void StartScript::save(ESMWriter &esm) const { esm.writeHNString("DATA", mData); - esm.writeHNString("NAME", mScript); + esm.writeHNString("NAME", mId); } } diff --git a/components/esm/loadsscr.hpp b/components/esm/loadsscr.hpp index d09ad883e..954a4a2b6 100644 --- a/components/esm/loadsscr.hpp +++ b/components/esm/loadsscr.hpp @@ -22,7 +22,7 @@ struct StartScript static unsigned int sRecordId; std::string mData; - std::string mId, mScript; + std::string mId; // Load a record and add it to the list void load(ESMReader &esm); From 4e1c086d6acfd9a9e2de7a8aa030b1a12f4fcaac Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 3 Mar 2015 13:52:36 +0100 Subject: [PATCH 554/740] load start up script records --- apps/opencs/model/world/data.cpp | 16 ++++++++++++++++ apps/opencs/model/world/data.hpp | 6 ++++++ apps/opencs/model/world/universalid.cpp | 2 ++ apps/opencs/model/world/universalid.hpp | 2 ++ components/esm/loadsscr.cpp | 4 ++++ components/esm/loadsscr.hpp | 2 ++ 6 files changed, 32 insertions(+) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 67f6822c7..313518091 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -254,6 +254,10 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mPathgrids.addColumn (new RecordStateColumn); mPathgrids.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Pathgrid)); + mStartScripts.addColumn (new StringIdColumn); + mStartScripts.addColumn (new RecordStateColumn); + mStartScripts.addColumn (new FixedRecordTypeColumn (UniversalId::Type_StartScript)); + mRefs.addColumn (new StringIdColumn (true)); mRefs.addColumn (new RecordStateColumn); mRefs.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Reference)); @@ -327,6 +331,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc addModel (new IdTable (&mSoundGens), UniversalId::Type_SoundGen); addModel (new IdTable (&mMagicEffects), UniversalId::Type_MagicEffect); addModel (new IdTable (&mPathgrids), UniversalId::Type_Pathgrid); + addModel (new IdTable (&mStartScripts), UniversalId::Type_StartScript); addModel (new IdTable (&mReferenceables, IdTable::Feature_Preview), UniversalId::Type_Referenceable); addModel (new IdTable (&mRefs, IdTable::Feature_ViewCell | IdTable::Feature_Preview), UniversalId::Type_Reference); @@ -615,6 +620,16 @@ CSMWorld::SubCellCollection& CSMWorld::Data::getPathgrids() return mPathgrids; } +const CSMWorld::IdCollection& CSMWorld::Data::getStartScripts() const +{ + return mStartScripts; +} + +CSMWorld::IdCollection& CSMWorld::Data::getStartScripts() +{ + return mStartScripts; +} + const CSMWorld::Resources& CSMWorld::Data::getResources (const UniversalId& id) const { return mResourcesManager.get (id.getType()); @@ -719,6 +734,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) case ESM::REC_SNDG: mSoundGens.load (*mReader, mBase); break; case ESM::REC_MGEF: mMagicEffects.load (*mReader, mBase); break; case ESM::REC_PGRD: mPathgrids.load (*mReader, mBase); break; + case ESM::REC_SSCR: mStartScripts.load (*mReader, mBase); break; case ESM::REC_LTEX: mLandTextures.load (*mReader, mBase); break; diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 02f7bc452..298a9be1f 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -80,6 +81,7 @@ namespace CSMWorld SubCellCollection mPathgrids; IdCollection mDebugProfiles; IdCollection mSoundGens; + IdCollection mStartScripts; InfoCollection mTopicInfos; InfoCollection mJournalInfos; IdCollection mCells; @@ -225,6 +227,10 @@ namespace CSMWorld SubCellCollection& getPathgrids(); + const IdCollection& getStartScripts() const; + + IdCollection& getStartScripts(); + /// Throws an exception, if \a id does not match a resources list. const Resources& getResources (const UniversalId& id) const; diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index d19959d44..50ac846db 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -55,6 +55,7 @@ namespace { 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_Pathgrids, "Pathgrids", 0 }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_StartScripts, "Start Scripts", 0 }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker }; @@ -118,6 +119,7 @@ namespace { 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_Pathgrid, "Pathgrid", 0 }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_StartScript, "Start Script", 0 }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index ce2d021d0..a716aec03 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -128,6 +128,8 @@ namespace CSMWorld Type_MagicEffect, Type_Pathgrids, Type_Pathgrid, + Type_StartScripts, + Type_StartScript, Type_RunLog }; diff --git a/components/esm/loadsscr.cpp b/components/esm/loadsscr.cpp index 9b02b51c9..7380dd0a7 100644 --- a/components/esm/loadsscr.cpp +++ b/components/esm/loadsscr.cpp @@ -41,4 +41,8 @@ namespace ESM esm.writeHNString("NAME", mId); } + void StartScript::blank() + { + mData.clear(); + } } diff --git a/components/esm/loadsscr.hpp b/components/esm/loadsscr.hpp index 954a4a2b6..1420d16c4 100644 --- a/components/esm/loadsscr.hpp +++ b/components/esm/loadsscr.hpp @@ -27,6 +27,8 @@ struct StartScript // Load a record and add it to the list void load(ESMReader &esm); void save(ESMWriter &esm) const; + + void blank(); }; } From a148b851c0294f7222a75d3217311fe0d6c57c63 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 3 Mar 2015 14:32:12 +0100 Subject: [PATCH 555/740] added start script table --- apps/opencs/view/doc/view.cpp | 9 +++++++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/world/subviews.cpp | 2 ++ 3 files changed, 13 insertions(+) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 9117a6d03..211f74187 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -173,6 +173,10 @@ void CSVDoc::View::setupMechanicsMenu() QAction *effects = new QAction (tr ("Magic Effects"), this); connect (effects, SIGNAL (triggered()), this, SLOT (addMagicEffectsSubView())); mechanics->addAction (effects); + + QAction *startScripts = new QAction (tr ("Start Scripts"), this); + connect (startScripts, SIGNAL (triggered()), this, SLOT (addStartScriptsSubView())); + mechanics->addAction (startScripts); } void CSVDoc::View::setupCharacterMenu() @@ -716,6 +720,11 @@ void CSVDoc::View::addPathgridSubView() addSubView (CSMWorld::UniversalId::Type_Pathgrids); } +void CSVDoc::View::addStartScriptsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_StartScripts); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 55ea5ee51..baadca85c 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -215,6 +215,8 @@ namespace CSVDoc void addPathgridSubView(); + void addStartScriptsSubView(); + void toggleShowStatusBar (bool show); void loadErrorLog(); diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index c5d969d0d..5e01ef283 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -43,6 +43,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_BodyParts, CSMWorld::UniversalId::Type_SoundGens, CSMWorld::UniversalId::Type_Pathgrids, + CSMWorld::UniversalId::Type_StartScripts, CSMWorld::UniversalId::Type_None // end marker }; @@ -123,6 +124,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_BodyPart, CSMWorld::UniversalId::Type_SoundGen, CSMWorld::UniversalId::Type_Pathgrid, + CSMWorld::UniversalId::Type_StartScript, CSMWorld::UniversalId::Type_None // end marker }; From 1ed606065c13677d87be2bc97b1a76697c3c53de Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 3 Mar 2015 16:11:00 +0100 Subject: [PATCH 556/740] save start script records --- apps/opencs/model/doc/saving.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/opencs/model/doc/saving.cpp b/apps/opencs/model/doc/saving.cpp index 70e9e1d87..b52186a47 100644 --- a/apps/opencs/model/doc/saving.cpp +++ b/apps/opencs/model/doc/saving.cpp @@ -78,6 +78,9 @@ CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& proje appendStage (new WriteCollectionStage > (mDocument.getData().getMagicEffects(), mState)); + appendStage (new WriteCollectionStage > + (mDocument.getData().getStartScripts(), mState)); + appendStage (new WriteDialogueCollectionStage (mDocument, mState, false)); appendStage (new WriteDialogueCollectionStage (mDocument, mState, true)); From d01e8cc97d290fc59486a1a3a0e086fce57776aa Mon Sep 17 00:00:00 2001 From: Scott Howard Date: Tue, 3 Mar 2015 17:36:22 -0500 Subject: [PATCH 557/740] PositionCell/PlaceItemCell: add console message if cell doesn't exist --- apps/openmw/mwscript/transformationextensions.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 9166bf909..734df7d74 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -316,6 +316,7 @@ namespace MWScript store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); if(!cell) { + runtime.getContext().report ("unknown cell (" + cellID + ")"); std::cerr << "unknown cell (" << cellID << ")\n"; } } @@ -428,6 +429,7 @@ namespace MWScript store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); if(!cell) { + runtime.getContext().report ("unknown cell (" + cellID + ")"); std::cerr << "unknown cell (" << cellID << ")\n"; } } From 8931ddf42804ccb4139a367e8389657a65c02447 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Mar 2015 23:46:53 +0100 Subject: [PATCH 558/740] Remove unneeded casts --- apps/openmw/mwscript/aiextensions.cpp | 5 +-- apps/openmw/mwscript/controlextensions.cpp | 5 +-- apps/openmw/mwscript/miscextensions.cpp | 48 ++++++---------------- apps/openmw/mwscript/skyextensions.cpp | 5 +-- 4 files changed, 16 insertions(+), 47 deletions(-) diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index a3f935487..163aedf76 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -466,12 +466,9 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context - = static_cast (runtime.getContext()); - bool enabled = MWBase::Environment::get().getMechanicsManager()->toggleAI(); - context.report (enabled ? "AI -> On" : "AI -> Off"); + runtime.getContext().report (enabled ? "AI -> On" : "AI -> Off"); } }; diff --git a/apps/openmw/mwscript/controlextensions.cpp b/apps/openmw/mwscript/controlextensions.cpp index fd7fe4737..904e0ee85 100644 --- a/apps/openmw/mwscript/controlextensions.cpp +++ b/apps/openmw/mwscript/controlextensions.cpp @@ -65,12 +65,9 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context - = static_cast (runtime.getContext()); - bool enabled = MWBase::Environment::get().getWorld()->toggleCollisionMode(); - context.report (enabled ? "Collision -> On" : "Collision -> Off"); + runtime.getContext().report (enabled ? "Collision -> On" : "Collision -> Off"); } }; diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 52094947c..507b27807 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -212,13 +212,10 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context = - static_cast (runtime.getContext()); - bool enabled = MWBase::Environment::get().getWorld()->toggleRenderMode (MWBase::World::Render_CollisionDebug); - context.report (enabled ? + runtime.getContext().report (enabled ? "Collision Mesh Rendering -> On" : "Collision Mesh Rendering -> Off"); } }; @@ -230,13 +227,10 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context = - static_cast (runtime.getContext()); - bool enabled = MWBase::Environment::get().getWorld()->toggleRenderMode (MWBase::World::Render_BoundingBoxes); - context.report (enabled ? + runtime.getContext().report (enabled ? "Bounding Box Rendering -> On" : "Bounding Box Rendering -> Off"); } }; @@ -247,13 +241,10 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context = - static_cast (runtime.getContext()); - bool enabled = MWBase::Environment::get().getWorld()->toggleRenderMode (MWBase::World::Render_Wireframe); - context.report (enabled ? + runtime.getContext().report (enabled ? "Wireframe Rendering -> On" : "Wireframe Rendering -> Off"); } }; @@ -263,13 +254,10 @@ namespace MWScript public: virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context = - static_cast (runtime.getContext()); - bool enabled = MWBase::Environment::get().getWorld()->toggleRenderMode (MWBase::World::Render_Pathgrid); - context.report (enabled ? + runtime.getContext().report (enabled ? "Path Grid rendering -> On" : "Path Grid Rendering -> Off"); } }; @@ -386,17 +374,14 @@ namespace MWScript virtual void execute(Interpreter::Runtime &runtime) { - InterpreterContext& context = - static_cast (runtime.getContext()); - MWBase::World *world = MWBase::Environment::get().getWorld(); if (world->toggleVanityMode(sActivate)) { - context.report(sActivate ? "Vanity Mode -> On" : "Vanity Mode -> Off"); + runtime.getContext().report(sActivate ? "Vanity Mode -> On" : "Vanity Mode -> Off"); sActivate = !sActivate; } else { - context.report("Vanity Mode -> No"); + runtime.getContext().report("Vanity Mode -> No"); } } }; @@ -862,14 +847,11 @@ namespace MWScript void printGlobalVars(Interpreter::Runtime &runtime) { - InterpreterContext& context = - static_cast (runtime.getContext()); - std::stringstream str; str<< "Global variables:"; MWBase::World *world = MWBase::Environment::get().getWorld(); - std::vector names = context.getGlobals(); + std::vector names = runtime.getContext().getGlobals(); for(size_t i = 0;i < names.size();++i) { char type = world->getGlobalVariableType (names[i]); @@ -879,17 +861,17 @@ namespace MWScript { case 's': - str << context.getGlobalShort (names[i]) << " (short)"; + str << runtime.getContext().getGlobalShort (names[i]) << " (short)"; break; case 'l': - str << context.getGlobalLong (names[i]) << " (long)"; + str << runtime.getContext().getGlobalLong (names[i]) << " (long)"; break; case 'f': - str << context.getGlobalFloat (names[i]) << " (float)"; + str << runtime.getContext().getGlobalFloat (names[i]) << " (float)"; break; default: @@ -898,7 +880,7 @@ namespace MWScript } } - context.report (str.str()); + runtime.getContext().report (str.str()); } public: @@ -920,11 +902,9 @@ namespace MWScript public: virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context = static_cast (runtime.getContext()); - bool enabled = MWBase::Environment::get().getWorld()->toggleScripts(); - context.report(enabled ? "Scripts -> On" : "Scripts -> Off"); + runtime.getContext().report(enabled ? "Scripts -> On" : "Scripts -> Off"); } }; @@ -933,11 +913,9 @@ namespace MWScript public: virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context = static_cast (runtime.getContext()); - bool enabled = MWBase::Environment::get().getWorld()->toggleGodMode(); - context.report (enabled ? "God Mode -> On" : "God Mode -> Off"); + runtime.getContext().report (enabled ? "God Mode -> On" : "God Mode -> Off"); } }; diff --git a/apps/openmw/mwscript/skyextensions.cpp b/apps/openmw/mwscript/skyextensions.cpp index 0ccd0ce31..d28d01b63 100644 --- a/apps/openmw/mwscript/skyextensions.cpp +++ b/apps/openmw/mwscript/skyextensions.cpp @@ -25,10 +25,7 @@ namespace MWScript { bool enabled = MWBase::Environment::get().getWorld()->toggleSky(); - InterpreterContext& context = - static_cast (runtime.getContext()); - - context.report (enabled ? "Sky -> On" : "Sky -> Off"); + runtime.getContext().report (enabled ? "Sky -> On" : "Sky -> Off"); } }; From cced508916b2dd9201ca468d2629862fd42b9daf Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Mar 2015 01:49:00 +0100 Subject: [PATCH 559/740] Remove unintended 1.5 factor for damage/restore magic effects --- apps/openmw/mwmechanics/actors.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index aa2cc8615..d91d54f6f 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -519,8 +519,8 @@ namespace MWMechanics effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).getMagnitude(), effects.get(EffectKey(ESM::MagicEffect::AbsorbAttribute, i)).getMagnitude()); - stat.damage(effects.get(EffectKey(ESM::MagicEffect::DamageAttribute, i)).getMagnitude() * duration * 1.5); - stat.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreAttribute, i)).getMagnitude() * duration * 1.5); + stat.damage(effects.get(EffectKey(ESM::MagicEffect::DamageAttribute, i)).getMagnitude() * duration); + stat.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreAttribute, i)).getMagnitude() * duration); creatureStats.setAttribute(i, stat); } @@ -786,8 +786,8 @@ namespace MWMechanics effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).getMagnitude(), effects.get(EffectKey(ESM::MagicEffect::AbsorbSkill, i)).getMagnitude()); - skill.damage(effects.get(EffectKey(ESM::MagicEffect::DamageSkill, i)).getMagnitude() * duration * 1.5); - skill.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreSkill, i)).getMagnitude() * duration * 1.5); + skill.damage(effects.get(EffectKey(ESM::MagicEffect::DamageSkill, i)).getMagnitude() * duration); + skill.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreSkill, i)).getMagnitude() * duration); } } From 80fe24207c17c5294627ba745ef9c6c5c9ca3447 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 5 Mar 2015 20:21:22 +1300 Subject: [PATCH 560/740] correction from Scrawl. Now correctly handles skills/attributes. Also, document what ContentSelectorView::ContentSelector::slotAddonTableItemActivated() is doing. --- apps/openmw/mwmechanics/activespells.cpp | 2 +- components/contentselector/view/contentselector.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index eec4f2bd3..b4701126b 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -185,7 +185,7 @@ namespace MWMechanics bool missing = true; for (std::vector::const_iterator iter(addTo.begin()); iter != addTo.end(); ++iter) { - if (effect->mEffectId == iter->mEffectId) + if ((effect->mEffectId == iter->mEffectId) && (effect->mArg == iter->mArg)) { missing = false; break; diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index 2363ae477..e3093d568 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -183,6 +183,7 @@ void ContentSelectorView::ContentSelector::setGameFileSelected(int index, bool s void ContentSelectorView::ContentSelector::slotAddonTableItemActivated(const QModelIndex &index) { + // toggles check state when an AddOn file is double clicked or activated by keyboard QModelIndex sourceIndex = mAddonProxyModel->mapToSource (index); if (!mContentModel->isEnabled (sourceIndex)) From 0b70fdac578329481507696a98070927b9f4cb73 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 5 Mar 2015 11:24:01 +0100 Subject: [PATCH 561/740] added start script verifier --- apps/opencs/CMakeLists.txt | 1 + apps/opencs/model/tools/startscriptcheck.cpp | 31 ++++++++++++++++++++ apps/opencs/model/tools/startscriptcheck.hpp | 28 ++++++++++++++++++ apps/opencs/model/tools/tools.cpp | 3 ++ 4 files changed, 63 insertions(+) create mode 100644 apps/opencs/model/tools/startscriptcheck.cpp create mode 100644 apps/opencs/model/tools/startscriptcheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 1d6b40d5f..d2d745cc2 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -40,6 +40,7 @@ opencs_units (model/tools opencs_units_noqt (model/tools mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck + startscriptcheck ) diff --git a/apps/opencs/model/tools/startscriptcheck.cpp b/apps/opencs/model/tools/startscriptcheck.cpp new file mode 100644 index 000000000..e3c01368b --- /dev/null +++ b/apps/opencs/model/tools/startscriptcheck.cpp @@ -0,0 +1,31 @@ + +#include "startscriptcheck.hpp" + +#include + +CSMTools::StartScriptCheckStage::StartScriptCheckStage ( + const CSMWorld::IdCollection& startScripts, + const CSMWorld::IdCollection& scripts) +: mStartScripts (startScripts), mScripts (scripts) +{} + +void CSMTools::StartScriptCheckStage::perform(int stage, CSMDoc::Messages& messages) +{ + const CSMWorld::Record& record = mStartScripts.getRecord (stage); + + if (record.isDeleted()) + return; + + std::string scriptId = record.get().mId; + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_StartScript, scriptId); + + if (mScripts.searchId (Misc::StringUtils::lowerCase (scriptId))==-1) + messages.push_back ( + std::make_pair (id, "Start script " + scriptId + " does not exist")); +} + +int CSMTools::StartScriptCheckStage::setup() +{ + return mStartScripts.getSize(); +} diff --git a/apps/opencs/model/tools/startscriptcheck.hpp b/apps/opencs/model/tools/startscriptcheck.hpp new file mode 100644 index 000000000..cb82cbae7 --- /dev/null +++ b/apps/opencs/model/tools/startscriptcheck.hpp @@ -0,0 +1,28 @@ +#ifndef CSM_TOOLS_STARTSCRIPTCHECK_H +#define CSM_TOOLS_STARTSCRIPTCHECK_H + +#include +#include + +#include "../doc/stage.hpp" + +#include "../world/idcollection.hpp" + +namespace CSMTools +{ + class StartScriptCheckStage : public CSMDoc::Stage + { + const CSMWorld::IdCollection& mStartScripts; + const CSMWorld::IdCollection& mScripts; + + public: + + StartScriptCheckStage (const CSMWorld::IdCollection& startScripts, + const CSMWorld::IdCollection& scripts); + + virtual void perform(int stage, CSMDoc::Messages& messages); + virtual int setup(); + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index e78758bb6..2139f890f 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -24,6 +24,7 @@ #include "scriptcheck.hpp" #include "bodypartcheck.hpp" #include "referencecheck.hpp" +#include "startscriptcheck.hpp" CSMDoc::Operation *CSMTools::Tools::get (int type) { @@ -84,6 +85,8 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier() mVerifier->appendStage (new ScriptCheckStage (mDocument)); + mVerifier->appendStage (new StartScriptCheckStage (mData.getStartScripts(), mData.getScripts())); + mVerifier->appendStage( new BodyPartCheckStage( mData.getBodyParts(), From c7cd576002512e41a8675145549418d8c265943d Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Mar 2015 23:12:47 +0100 Subject: [PATCH 562/740] Remove leftover of old tests --- libs/openengine/testall.sh | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100755 libs/openengine/testall.sh diff --git a/libs/openengine/testall.sh b/libs/openengine/testall.sh deleted file mode 100755 index 097fdabd5..000000000 --- a/libs/openengine/testall.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -function run() -{ - echo "TESTING $1" - cd "$1/tests/" - ./test.sh - cd ../../ -} - -run input From d28f257adac9b7fa52c165f66f5f60837d39df64 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 6 Mar 2015 11:53:46 +1100 Subject: [PATCH 563/740] Fix for bug #2428. Set default flag value (mandatory) for containers. --- components/esm/loadcont.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/loadcont.cpp b/components/esm/loadcont.cpp index 999c3f92a..3481189c3 100644 --- a/components/esm/loadcont.cpp +++ b/components/esm/loadcont.cpp @@ -87,7 +87,7 @@ namespace ESM mModel.clear(); mScript.clear(); mWeight = 0; - mFlags = 0; + mFlags = 0x8; // set default flag value mInventory.mList.clear(); } } From 0fda1cdd53b44c7d909b4e594fab409718d61896 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Mar 2015 00:56:37 +0100 Subject: [PATCH 564/740] Move oengine to a static library, fixes duplicate compilation of oengine/bullet files by openmw and opencs --- CMakeLists.txt | 42 +++---------------- apps/opencs/CMakeLists.txt | 5 ++- apps/openmw/CMakeLists.txt | 5 +-- extern/sdl4ogre/CMakeLists.txt | 1 + .../ogre => extern/sdl4ogre}/imagerotate.cpp | 6 ++- .../ogre => extern/sdl4ogre}/imagerotate.hpp | 6 +-- extern/sdl4ogre/sdlcursormanager.cpp | 4 +- libs/openengine/CMakeLists.txt | 33 +++++++++++++++ 8 files changed, 53 insertions(+), 49 deletions(-) rename {libs/openengine/ogre => extern/sdl4ogre}/imagerotate.cpp (99%) rename {libs/openengine/ogre => extern/sdl4ogre}/imagerotate.hpp (94%) create mode 100644 libs/openengine/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ed6d6e17..27ea78331 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,43 +97,6 @@ endif() # We probably support older versions than this. cmake_minimum_required(VERSION 2.6) -# source directory: libs - -set(LIBS_DIR ${CMAKE_SOURCE_DIR}/libs) - -set(OENGINE_OGRE - ${LIBS_DIR}/openengine/ogre/renderer.cpp - ${LIBS_DIR}/openengine/ogre/lights.cpp - ${LIBS_DIR}/openengine/ogre/selectionbuffer.cpp - ${LIBS_DIR}/openengine/ogre/imagerotate.cpp -) - -set(OENGINE_GUI - ${LIBS_DIR}/openengine/gui/loglistener.cpp - ${LIBS_DIR}/openengine/gui/manager.cpp - ${LIBS_DIR}/openengine/gui/layout.cpp -) - -set(OENGINE_BULLET - ${LIBS_DIR}/openengine/bullet/BtOgre.cpp - ${LIBS_DIR}/openengine/bullet/BtOgreExtras.h - ${LIBS_DIR}/openengine/bullet/BtOgreGP.h - ${LIBS_DIR}/openengine/bullet/BtOgrePG.h - ${LIBS_DIR}/openengine/bullet/physic.cpp - ${LIBS_DIR}/openengine/bullet/physic.hpp - ${LIBS_DIR}/openengine/bullet/BulletShapeLoader.cpp - ${LIBS_DIR}/openengine/bullet/BulletShapeLoader.h - ${LIBS_DIR}/openengine/bullet/trace.cpp - ${LIBS_DIR}/openengine/bullet/trace.h - -) - -set(OENGINE_ALL ${OENGINE_OGRE} ${OENGINE_GUI} ${OENGINE_BULLET}) -source_group(libs\\openengine FILES ${OENGINE_ALL}) - -set(OPENMW_LIBS ${OENGINE_ALL}) -set(OPENMW_LIBS_HEADER) - # Sound setup set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE SWRESAMPLE AVRESAMPLE) unset(FFMPEG_LIBRARIES CACHE) @@ -275,6 +238,7 @@ include_directories("." ${MYGUI_INCLUDE_DIRS} ${MYGUI_PLATFORM_INCLUDE_DIRS} ${OPENAL_INCLUDE_DIR} + ${BULLET_INCLUDE_DIRS} ${LIBS_DIR} ) @@ -572,6 +536,10 @@ if(WIN32) include(CPack) endif(WIN32) +# Libs +include_directories(libs) +add_subdirectory(libs/openengine) + # Extern add_subdirectory (extern/shiny) add_subdirectory (extern/ogre-ffmpeg-videoplayer) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 1d6b40d5f..3ea611694 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -164,7 +164,8 @@ qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI}) qt4_wrap_cpp(OPENCS_MOC_SRC ${OPENCS_HDR_QT}) qt4_add_resources(OPENCS_RES_SRC ${OPENCS_RES}) -include_directories(${CMAKE_CURRENT_BINARY_DIR} ${BULLET_INCLUDE_DIRS}) +# for compiled .ui files +include_directories(${CMAKE_CURRENT_BINARY_DIR}) if(APPLE) set (OPENCS_MAC_ICON ${CMAKE_SOURCE_DIR}/files/mac/openmw-cs.icns) @@ -174,7 +175,6 @@ endif(APPLE) add_executable(openmw-cs MACOSX_BUNDLE - ${OENGINE_BULLET} ${OPENCS_SRC} ${OPENCS_UI_HDR} ${OPENCS_MOC_SRC} @@ -198,6 +198,7 @@ if(APPLE) endif(APPLE) target_link_libraries(openmw-cs + ${OENGINE_LIBRARY} ${OGRE_LIBRARIES} ${OGRE_Overlay_LIBRARIES} ${OGRE_STATIC_PLUGINS} diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index eabbb7577..860cc2fcb 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -104,7 +104,6 @@ find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) if (NOT ANDROID) add_executable(openmw - ${OPENMW_LIBS} ${OPENMW_LIBS_HEADER} ${OPENMW_FILES} ${GAME} ${GAME_HEADER} ${APPLE_BUNDLE_RESOURCES} @@ -112,7 +111,6 @@ if (NOT ANDROID) else () add_library(openmw SHARED - ${OPENMW_LIBS} ${OPENMW_LIBS_HEADER} ${OPENMW_FILES} ${GAME} ${GAME_HEADER} ) @@ -120,9 +118,10 @@ endif () # Sound stuff - here so CMake doesn't stupidly recompile EVERYTHING # when we change the backend. -include_directories(${SOUND_INPUT_INCLUDES} ${BULLET_INCLUDE_DIRS}) +include_directories(${SOUND_INPUT_INCLUDES}) target_link_libraries(openmw + ${OENGINE_LIBRARY} ${OGRE_LIBRARIES} ${OGRE_STATIC_PLUGINS} ${SHINY_LIBRARIES} diff --git a/extern/sdl4ogre/CMakeLists.txt b/extern/sdl4ogre/CMakeLists.txt index 86ce7b70e..b8c56bd00 100644 --- a/extern/sdl4ogre/CMakeLists.txt +++ b/extern/sdl4ogre/CMakeLists.txt @@ -6,6 +6,7 @@ set(SDL4OGRE_SOURCE_FILES sdlinputwrapper.cpp sdlcursormanager.cpp sdlwindowhelper.cpp + imagerotate.cpp ) if (APPLE) diff --git a/libs/openengine/ogre/imagerotate.cpp b/extern/sdl4ogre/imagerotate.cpp similarity index 99% rename from libs/openengine/ogre/imagerotate.cpp rename to extern/sdl4ogre/imagerotate.cpp index cc5f572cf..b825943fc 100644 --- a/libs/openengine/ogre/imagerotate.cpp +++ b/extern/sdl4ogre/imagerotate.cpp @@ -17,7 +17,9 @@ #include using namespace Ogre; -using namespace OEngine::Render; + +namespace SFO +{ void ImageRotate::rotate(const std::string& sourceImage, const std::string& destImage, const float angle) { @@ -93,3 +95,5 @@ void ImageRotate::rotate(const std::string& sourceImage, const std::string& dest root->destroySceneManager(sceneMgr); delete rect; } + +} diff --git a/libs/openengine/ogre/imagerotate.hpp b/extern/sdl4ogre/imagerotate.hpp similarity index 94% rename from libs/openengine/ogre/imagerotate.hpp rename to extern/sdl4ogre/imagerotate.hpp index a3f6d662f..7135a571a 100644 --- a/libs/openengine/ogre/imagerotate.hpp +++ b/extern/sdl4ogre/imagerotate.hpp @@ -3,9 +3,8 @@ #include -namespace OEngine -{ -namespace Render + +namespace SFO { /// Rotate an image by certain degrees and save as file, uses the GPU @@ -22,6 +21,5 @@ namespace Render }; } -} #endif diff --git a/extern/sdl4ogre/sdlcursormanager.cpp b/extern/sdl4ogre/sdlcursormanager.cpp index 7623d57db..61508a64e 100644 --- a/extern/sdl4ogre/sdlcursormanager.cpp +++ b/extern/sdl4ogre/sdlcursormanager.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include "imagerotate.hpp" namespace SFO { @@ -91,7 +91,7 @@ namespace SFO // we use a render target to uncompress the DDS texture // just blitting doesn't seem to work on D3D9 - OEngine::Render::ImageRotate::rotate(tex->getName(), tempName, -rotDegrees); + ImageRotate::rotate(tex->getName(), tempName, -rotDegrees); Ogre::TexturePtr resultTexture = Ogre::TextureManager::getSingleton().getByName(tempName); diff --git a/libs/openengine/CMakeLists.txt b/libs/openengine/CMakeLists.txt new file mode 100644 index 000000000..7a0a791d1 --- /dev/null +++ b/libs/openengine/CMakeLists.txt @@ -0,0 +1,33 @@ +set(OENGINE_OGRE + ogre/renderer.cpp + ogre/lights.cpp + ogre/selectionbuffer.cpp +) + +set(OENGINE_GUI + gui/loglistener.cpp + gui/manager.cpp + gui/layout.cpp +) + +set(OENGINE_BULLET + bullet/BtOgre.cpp + bullet/BtOgreExtras.h + bullet/BtOgreGP.h + bullet/BtOgrePG.h + bullet/physic.cpp + bullet/physic.hpp + bullet/BulletShapeLoader.cpp + bullet/BulletShapeLoader.h + bullet/trace.cpp + bullet/trace.h +) + +set(OENGINE_ALL ${OENGINE_OGRE} ${OENGINE_GUI} ${OENGINE_BULLET}) + +set(OENGINE_LIBRARY "oengine") +set(OENGINE_LIBRARY ${OENGINE_LIBRARY} PARENT_SCOPE) + +source_group(oengine FILES ${OENGINE_ALL}) + +add_library(${OENGINE_LIBRARY} STATIC ${OENGINE_ALL}) From 5a47b7ae6e50e581b5f55eac9b9d2cf9cefda363 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Mar 2015 00:57:26 +0100 Subject: [PATCH 565/740] Warning fix --- extern/ogre-ffmpeg-videoplayer/audiodecoder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/ogre-ffmpeg-videoplayer/audiodecoder.cpp b/extern/ogre-ffmpeg-videoplayer/audiodecoder.cpp index cfc6c17b9..1a56802da 100644 --- a/extern/ogre-ffmpeg-videoplayer/audiodecoder.cpp +++ b/extern/ogre-ffmpeg-videoplayer/audiodecoder.cpp @@ -222,7 +222,7 @@ int MovieAudioDecoder::audio_decode_frame(AVFrame *frame, int &sample_skip) } /* if update, update the audio clock w/pts */ - if((uint64_t)pkt->pts != AV_NOPTS_VALUE) + if(pkt->pts != AV_NOPTS_VALUE) mAudioClock = av_q2d(mAVStream->time_base)*pkt->pts; } } From 6d6ff8c6a47e102679b40c388b7dbf099c07cbba Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 6 Mar 2015 14:36:13 +1100 Subject: [PATCH 566/740] Resolved compile issues, but not fully working. --- apps/opencs/model/world/idtable.cpp | 26 ++++++------ apps/opencs/view/world/dialoguesubview.cpp | 46 +++++++++++----------- apps/opencs/view/world/dialoguesubview.hpp | 8 ++-- apps/opencs/view/world/nestedtable.cpp | 8 ++-- apps/opencs/view/world/nestedtable.hpp | 14 +++---- 5 files changed, 51 insertions(+), 51 deletions(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 2852cb581..fc8ac66b7 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -31,7 +31,7 @@ int CSMWorld::IdTable::columnCount (const QModelIndex & parent) const { return dynamic_cast(mIdCollection)->getNestedColumnsCount(parent.row(), parent.column()); } - + return mIdCollection->getColumns(); } @@ -72,7 +72,7 @@ QVariant CSMWorld::IdTable::headerData (int section, { return mIdCollection->getColumn (section).mDisplayType; } - + return QVariant(); } @@ -104,7 +104,7 @@ bool CSMWorld::IdTable::setData (const QModelIndex &index, const QVariant &value const std::pair& parentAdress(unfoldIndexAdress(index.internalId())); dynamic_cast(mIdCollection)->setNestedData(parentAdress.first, parentAdress.second, value, index.row(), index.column()); - + emit dataChanged (CSMWorld::IdTable::index (parentAdress.first, 0), CSMWorld::IdTable::index (parentAdress.second, mIdCollection->getColumns()-1)); @@ -114,17 +114,17 @@ bool CSMWorld::IdTable::setData (const QModelIndex &index, const QVariant &value return false; } } - + if (mIdCollection->getColumn (index.column()).isEditable() && role==Qt::EditRole) { mIdCollection->setData (index.row(), index.column(), value); - + emit dataChanged (CSMWorld::IdTable::index (index.row(), 0), CSMWorld::IdTable::index (index.row(), mIdCollection->getColumns()-1)); - + return true; - } - + } + return false; } @@ -177,7 +177,7 @@ void CSMWorld::IdTable::addNestedRow(const QModelIndex& parent, int position) dynamic_cast(mIdCollection)->addNestedRow(row, parent.column(), position); endInsertRows(); - + emit dataChanged (CSMWorld::IdTable::index (row, 0), CSMWorld::IdTable::index (row, mIdCollection->getColumns()-1)); } @@ -353,7 +353,7 @@ std::pair< int, int > CSMWorld::IdTable::unfoldIndexAdress (unsigned int id) con --id; int row = id / this->columnCount(); int column = id - row * this->columnCount(); - return std::make_pair(row, column); + return std::make_pair (row, column); } bool CSMWorld::IdTable::hasChildren(const QModelIndex& index) const @@ -370,14 +370,14 @@ void CSMWorld::IdTable::setNestedTable(const QModelIndex& index, const CSMWorld: { throw std::logic_error("Tried to set nested table, but index has no children"); } - + bool removeRowsMode = false; if (nestedTable.size() != this->nestedTable(index)->size()) { emit resetStart(this->index(index.row(), 0).data().toString()); removeRowsMode = true; } - + dynamic_cast(mIdCollection)->setNestedTable(index.row(), index.column(), nestedTable); emit dataChanged (CSMWorld::IdTable::index (index.row(), 0), @@ -395,6 +395,6 @@ CSMWorld::NestedTableWrapperBase* CSMWorld::IdTable::nestedTable(const QModelInd { throw std::logic_error("Tried to retrive nested table, but index has no children"); } - + return dynamic_cast(mIdCollection)->nestedTable(index.row(), index.column()); } diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index f6ad79a6a..a2b6f45f1 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -281,7 +281,7 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: connect(proxy, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), this, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); - skip = true; + //skip = true; } else if (qobject_cast(editor)) { @@ -298,7 +298,7 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: else if (qobject_cast(editor)) { connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited())); - } //lisp cond pairs would be nice in the C++ + } connect(proxy, SIGNAL(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display)), this, SLOT(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display))); @@ -328,8 +328,8 @@ CSVWorld::EditWidget::~EditWidget() } } -CSVWorld::EditWidget::EditWidget(QWidget *parent, int row, CSMWorld::IdTable* table, QUndoStack& undoStack, bool createAndDelete) : -mDispatcher(this, table, undoStack), +CSVWorld::EditWidget::EditWidget(QWidget *parent, int row, CSMWorld::IdTable* table, CSMDoc::Document& document, bool createAndDelete) : +mDispatcher(this, table, document), QScrollArea(parent), mWidgetMapper(NULL), mMainWidget(NULL), @@ -338,7 +338,7 @@ mTable(table) { remake (row); - connect(&mDispatcher, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), + connect(&mDispatcher, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), this, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); } @@ -349,7 +349,7 @@ void CSVWorld::EditWidget::remake(int row) delete mNestedModels[i]; } mNestedModels.clear(); - + if (mMainWidget) { delete mMainWidget; @@ -401,8 +401,8 @@ void CSVWorld::EditWidget::remake(int row) if (mTable->hasChildren(mTable->index(row, i))) { mNestedModels.push_back(new CSMWorld::NestedTableModel (mTable->index(row, i), display, mTable)); - - NestedTable* table = new NestedTable(mUndoStack, *(mNestedModels.rbegin()), this); + + NestedTable* table = new NestedTable(mDocument, *(mNestedModels.rbegin()), this); tablesLayout->addWidget(table); } else @@ -517,7 +517,7 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM mMainLayout = new QVBoxLayout(mainWidget); - mEditWidget = new EditWidget(mainWidget, mTable->getModelIndex(mCurrentId, 0).row(), mTable, mUndoStack, false); + mEditWidget = new EditWidget(mainWidget, mTable->getModelIndex(mCurrentId, 0).row(), mTable, document, false); connect(mEditWidget, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), this, SLOT(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); @@ -570,7 +570,7 @@ void CSVWorld::DialogueSubView::prevId () setUniversalId(CSMWorld::UniversalId (static_cast (mTable->data (mTable->index (newRow, 2)).toInt()), mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); - changeCurrentId(std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); + changeCurrentId(std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); mEditWidget->setDisabled(mLocked); @@ -604,9 +604,9 @@ void CSVWorld::DialogueSubView::nextId () mEditWidget->remake(newRow); setUniversalId(CSMWorld::UniversalId (static_cast (mTable->data (mTable->index (newRow, 2)).toInt()), - mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); + mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); - changeCurrentId(std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); + changeCurrentId(std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData())); mEditWidget->setDisabled(mLocked); @@ -623,11 +623,11 @@ void CSVWorld::DialogueSubView::setEditLock (bool locked) if (currentIndex.isValid()) { - CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (currentIndex.row(), 1)).toInt()); + CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (currentIndex.row(), 1)).toInt()); - mEditWidget->setDisabled (state==CSMWorld::RecordBase::State_Deleted || locked); + mEditWidget->setDisabled (state==CSMWorld::RecordBase::State_Deleted || locked); - mCommandDispatcher.setEditLock (locked); + mCommandDispatcher.setEditLock (locked); } } @@ -640,14 +640,14 @@ void CSVWorld::DialogueSubView::dataChanged (const QModelIndex & index) { CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (currentIndex.row(), 1)).toInt()); - mEditWidget->setDisabled (state==CSMWorld::RecordBase::State_Deleted || mLocked); + mEditWidget->setDisabled (state==CSMWorld::RecordBase::State_Deleted || mLocked); } } void CSVWorld::DialogueSubView::tableMimeDataDropped (QWidget* editor, - const QModelIndex& index, - const CSMWorld::UniversalId& id, - const CSMDoc::Document* document) + const QModelIndex& index, + const CSMWorld::UniversalId& id, + const CSMDoc::Document* document) { if (document == &mDocument) { @@ -672,10 +672,10 @@ void CSVWorld::DialogueSubView::showPreview () QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); if (currentIndex.isValid() && - mTable->getFeatures() & CSMWorld::IdTable::Feature_Preview && - currentIndex.row() < mTable->rowCount()) + mTable->getFeatures() & CSMWorld::IdTable::Feature_Preview && + currentIndex.row() < mTable->rowCount()) { - emit focusId(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Preview, mCurrentId), ""); + emit focusId(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Preview, mCurrentId), ""); } } @@ -684,7 +684,7 @@ void CSVWorld::DialogueSubView::viewRecord () QModelIndex currentIndex(mTable->getModelIndex (mCurrentId, 0)); if (currentIndex.isValid() && - currentIndex.row() < mTable->rowCount()) + currentIndex.row() < mTable->rowCount()) { std::pair params = mTable->view (currentIndex.row()); diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 3f48aef42..45581bc3f 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -118,12 +118,12 @@ namespace CSVWorld NotEditableSubDelegate mNotEditableDelegate; std::vector mProxys; -//once we move to the C++11 we should use unique_ptr + //once we move to the C++11 we should use unique_ptr public: DialogueDelegateDispatcher(QObject* parent, CSMWorld::IdTable* table, - QUndoStack& undoStack); + CSMDoc::Document& document); ~DialogueDelegateDispatcher(); @@ -175,10 +175,10 @@ namespace CSVWorld public: EditWidget (QWidget *parent, int row, CSMWorld::IdTable* table, - QUndoStack& undoStack, bool createAndDelete = false); + CSMDoc::Document& document, bool createAndDelete = false); virtual ~EditWidget(); - + void remake(int row); signals: diff --git a/apps/opencs/view/world/nestedtable.cpp b/apps/opencs/view/world/nestedtable.cpp index 21bef504b..14e079c98 100644 --- a/apps/opencs/view/world/nestedtable.cpp +++ b/apps/opencs/view/world/nestedtable.cpp @@ -9,11 +9,11 @@ #include #include -CSVWorld::NestedTable::NestedTable(QUndoStack& undoStack, +CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document, CSMWorld::NestedTableModel* model, QWidget* parent) : QTableView(parent), - mUndoStack(undoStack), + mUndoStack(document.getUndoStack()), mModel(model) { @@ -31,9 +31,9 @@ CSVWorld::NestedTable::NestedTable(QUndoStack& undoStack, model->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); CommandDelegate *delegate = CommandDelegateFactoryCollection::get().makeDelegate(display, - undoStack, + document, this); - + setItemDelegateForColumn(i, delegate); } diff --git a/apps/opencs/view/world/nestedtable.hpp b/apps/opencs/view/world/nestedtable.hpp index 35fa22494..6b6b6aaba 100644 --- a/apps/opencs/view/world/nestedtable.hpp +++ b/apps/opencs/view/world/nestedtable.hpp @@ -29,23 +29,23 @@ namespace CSVWorld QAction *mRemoveRowAction; QUndoStack& mUndoStack; CSMWorld::NestedTableModel* mModel; - + public: - NestedTable(QUndoStack& undoStack, + NestedTable(CSMDoc::Document& document, CSMWorld::NestedTableModel* model, QWidget* parent = NULL); - + protected: void dragEnterEvent(QDragEnterEvent *event); - + void dragMoveEvent(QDragMoveEvent *event); - + private: void contextMenuEvent (QContextMenuEvent *event); - + private slots: void removeRowActionTriggered(); - + void addNewRowActionTriggered(); }; } From 727b68dd15472a2a647966db85bd2d1d6b931b90 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 6 Mar 2015 19:20:50 +1100 Subject: [PATCH 567/740] Reduce difference with the master branch where possible. --- apps/opencs/CMakeLists.txt | 5 +-- apps/opencs/model/doc/document.cpp | 5 ++- apps/opencs/model/tools/startscriptcheck.cpp | 31 +++++++++++++++++++ apps/opencs/model/tools/startscriptcheck.hpp | 28 +++++++++++++++++ apps/opencs/model/tools/tools.cpp | 3 ++ apps/opencs/model/world/collection.hpp | 4 +-- apps/opencs/model/world/collectionbase.cpp | 3 +- apps/opencs/model/world/columnimp.hpp | 1 - apps/opencs/view/world/enumdelegate.cpp | 1 + apps/opencs/view/world/util.cpp | 2 +- apps/openmw/mwmechanics/activespells.cpp | 2 +- .../mwscript/transformationextensions.cpp | 2 ++ .../contentselector/view/contentselector.cpp | 1 + 13 files changed, 75 insertions(+), 13 deletions(-) create mode 100644 apps/opencs/model/tools/startscriptcheck.cpp create mode 100644 apps/opencs/model/tools/startscriptcheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index ab3765bb6..2125deeff 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -19,7 +19,7 @@ opencs_hdrs_noqt (model/doc opencs_units (model/world idtable idtableproxymodel regionmap data commanddispatcher - idtablebase resourcetable nestedtablemodel + idtablebase resourcetable nestedtablemodel ) @@ -41,6 +41,7 @@ opencs_units (model/tools opencs_units_noqt (model/tools mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck + startscriptcheck ) @@ -64,7 +65,7 @@ opencs_units (view/world cellcreator referenceablecreator referencecreator scenesubview infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable ) - + opencs_units_noqt (view/world subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate scripthighlighter idvalidator dialoguecreator physicssystem diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 61fe4b322..e688a9474 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2,7 +2,6 @@ #include #include -#include #include @@ -2243,7 +2242,7 @@ void CSMDoc::Document::createBase() record.blank(); getData().getMagicEffects().add (record); -} + } } CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, @@ -2265,7 +2264,7 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, { boost::filesystem::path customFiltersPath (configuration.getUserDataPath()); customFiltersPath /= "defaultfilters"; - + std::ofstream destination (mProjectPath.string().c_str(), std::ios::binary); if (boost::filesystem::exists (customFiltersPath)) diff --git a/apps/opencs/model/tools/startscriptcheck.cpp b/apps/opencs/model/tools/startscriptcheck.cpp new file mode 100644 index 000000000..e3c01368b --- /dev/null +++ b/apps/opencs/model/tools/startscriptcheck.cpp @@ -0,0 +1,31 @@ + +#include "startscriptcheck.hpp" + +#include + +CSMTools::StartScriptCheckStage::StartScriptCheckStage ( + const CSMWorld::IdCollection& startScripts, + const CSMWorld::IdCollection& scripts) +: mStartScripts (startScripts), mScripts (scripts) +{} + +void CSMTools::StartScriptCheckStage::perform(int stage, CSMDoc::Messages& messages) +{ + const CSMWorld::Record& record = mStartScripts.getRecord (stage); + + if (record.isDeleted()) + return; + + std::string scriptId = record.get().mId; + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_StartScript, scriptId); + + if (mScripts.searchId (Misc::StringUtils::lowerCase (scriptId))==-1) + messages.push_back ( + std::make_pair (id, "Start script " + scriptId + " does not exist")); +} + +int CSMTools::StartScriptCheckStage::setup() +{ + return mStartScripts.getSize(); +} diff --git a/apps/opencs/model/tools/startscriptcheck.hpp b/apps/opencs/model/tools/startscriptcheck.hpp new file mode 100644 index 000000000..cb82cbae7 --- /dev/null +++ b/apps/opencs/model/tools/startscriptcheck.hpp @@ -0,0 +1,28 @@ +#ifndef CSM_TOOLS_STARTSCRIPTCHECK_H +#define CSM_TOOLS_STARTSCRIPTCHECK_H + +#include +#include + +#include "../doc/stage.hpp" + +#include "../world/idcollection.hpp" + +namespace CSMTools +{ + class StartScriptCheckStage : public CSMDoc::Stage + { + const CSMWorld::IdCollection& mStartScripts; + const CSMWorld::IdCollection& mScripts; + + public: + + StartScriptCheckStage (const CSMWorld::IdCollection& startScripts, + const CSMWorld::IdCollection& scripts); + + virtual void perform(int stage, CSMDoc::Messages& messages); + virtual int setup(); + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index e78758bb6..2139f890f 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -24,6 +24,7 @@ #include "scriptcheck.hpp" #include "bodypartcheck.hpp" #include "referencecheck.hpp" +#include "startscriptcheck.hpp" CSMDoc::Operation *CSMTools::Tools::get (int type) { @@ -84,6 +85,8 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier() mVerifier->appendStage (new ScriptCheckStage (mDocument)); + mVerifier->appendStage (new StartScriptCheckStage (mData.getStartScripts(), mData.getScripts())); + mVerifier->appendStage( new BodyPartCheckStage( mData.getBodyParts(), diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 5c32e7716..1fb3e1f1d 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -2,13 +2,11 @@ #define CSM_WOLRD_COLLECTION_H #include -#include #include #include #include #include #include -#include #include @@ -94,7 +92,7 @@ namespace CSMWorld virtual void purge(); ///< Remove records that are flagged as erased. - virtual void removeRows (int index, int count); + virtual void removeRows (int index, int count) ; virtual void appendBlankRecord (const std::string& id, UniversalId::Type type = UniversalId::Type_None); diff --git a/apps/opencs/model/world/collectionbase.cpp b/apps/opencs/model/world/collectionbase.cpp index 5b0c359c9..241f198cb 100644 --- a/apps/opencs/model/world/collectionbase.cpp +++ b/apps/opencs/model/world/collectionbase.cpp @@ -2,7 +2,6 @@ #include "collectionbase.hpp" #include -#include #include "columnbase.hpp" @@ -29,4 +28,4 @@ int CSMWorld::CollectionBase::findColumnIndex (Columns::ColumnId id) const throw std::logic_error ("invalid column index"); return index; -} +} \ No newline at end of file diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index dc8edbc51..da14bb495 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -6,7 +6,6 @@ #include #include -#include #include diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp index 7c305b1b6..168e5cb0a 100644 --- a/apps/opencs/view/world/enumdelegate.cpp +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -46,6 +46,7 @@ QWidget *CSVWorld::EnumDelegate::createEditor(QWidget *parent, const QModelIndex& index) const { return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_None); + //overloading virtual functions is HARD } QWidget *CSVWorld::EnumDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem& option, diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index 11521bb67..c65e12c60 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -186,7 +186,7 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO } case CSMWorld::ColumnBase::Display_Boolean: - + return new QCheckBox(parent); case CSMWorld::ColumnBase::Display_String: diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index eec4f2bd3..b4701126b 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -185,7 +185,7 @@ namespace MWMechanics bool missing = true; for (std::vector::const_iterator iter(addTo.begin()); iter != addTo.end(); ++iter) { - if (effect->mEffectId == iter->mEffectId) + if ((effect->mEffectId == iter->mEffectId) && (effect->mArg == iter->mArg)) { missing = false; break; diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 9166bf909..734df7d74 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -316,6 +316,7 @@ namespace MWScript store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); if(!cell) { + runtime.getContext().report ("unknown cell (" + cellID + ")"); std::cerr << "unknown cell (" << cellID << ")\n"; } } @@ -428,6 +429,7 @@ namespace MWScript store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); if(!cell) { + runtime.getContext().report ("unknown cell (" + cellID + ")"); std::cerr << "unknown cell (" << cellID << ")\n"; } } diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index 2363ae477..e3093d568 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -183,6 +183,7 @@ void ContentSelectorView::ContentSelector::setGameFileSelected(int index, bool s void ContentSelectorView::ContentSelector::slotAddonTableItemActivated(const QModelIndex &index) { + // toggles check state when an AddOn file is double clicked or activated by keyboard QModelIndex sourceIndex = mAddonProxyModel->mapToSource (index); if (!mContentModel->isEnabled (sourceIndex)) From 407cd50890d0949bf774cccb74feb8626055f18c Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 6 Mar 2015 21:36:42 +1300 Subject: [PATCH 568/740] fixed warning C4099: type name first seen using 'class' now seen using 'struct' --- apps/openmw/mwbase/soundmanager.hpp | 2 +- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwgui/bookpage.cpp | 4 ++-- apps/openmw/mwgui/savegamedialog.hpp | 2 +- apps/openmw/mwgui/tooltips.hpp | 2 +- apps/openmw/mwgui/windowmanagerimp.hpp | 2 +- apps/openmw/mwinput/inputmanagerimp.hpp | 2 +- apps/openmw/mwmechanics/aipackage.hpp | 2 +- apps/openmw/mwmechanics/aisequence.hpp | 2 +- apps/openmw/mwmechanics/aiwander.hpp | 2 +- apps/openmw/mwmechanics/character.hpp | 2 +- apps/openmw/mwmechanics/pathgrid.hpp | 2 +- apps/openmw/mwmechanics/spellcasting.hpp | 2 +- apps/openmw/mwrender/globalmap.hpp | 2 +- apps/openmw/mwrender/localmap.hpp | 2 +- apps/openmw/mwscript/globalscripts.hpp | 2 +- apps/openmw/mwscript/interpretercontext.hpp | 2 +- apps/openmw/mwscript/locals.hpp | 2 +- apps/openmw/mwscript/scriptmanagerimp.hpp | 2 +- apps/openmw/mwsound/openal_output.hpp | 2 +- apps/openmw/mwsound/sound_output.hpp | 2 +- apps/openmw/mwworld/localscripts.hpp | 2 +- apps/openmw/mwworld/ptr.hpp | 2 +- apps/openmw/mwworld/timestamp.hpp | 2 +- components/nif/node.hpp | 2 +- components/nif/recordptr.hpp | 4 ++-- components/nifbullet/bulletnifloader.hpp | 4 ++-- components/nifogre/mesh.hpp | 2 +- 29 files changed, 32 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index f3381a8fd..e71558de0 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -20,7 +20,7 @@ namespace MWWorld namespace MWSound { class Sound; - class Sound_Decoder; + struct Sound_Decoder; typedef boost::shared_ptr DecoderPtr; } diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 9eb272e1b..56f575d3a 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -49,7 +49,7 @@ namespace MWRender namespace MWMechanics { - class Movement; + struct Movement; } namespace MWWorld diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 9aece7368..c00665eb3 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -5,7 +5,7 @@ namespace ESM { - class GameSetting; + struct GameSetting; } namespace MWClass diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index c9cfc8c2c..57e171659 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -16,8 +16,8 @@ namespace MWGui { struct TypesetBookImpl; -struct PageDisplay; -struct BookPageImpl; +class PageDisplay; +class BookPageImpl; static bool ucsSpace (int codePoint); static bool ucsLineBreak (int codePoint); diff --git a/apps/openmw/mwgui/savegamedialog.hpp b/apps/openmw/mwgui/savegamedialog.hpp index 11470a20f..2192adbde 100644 --- a/apps/openmw/mwgui/savegamedialog.hpp +++ b/apps/openmw/mwgui/savegamedialog.hpp @@ -6,7 +6,7 @@ namespace MWState { class Character; - class Slot; + struct Slot; } namespace MWGui diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 4bd4d88aa..71b4a560f 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -9,7 +9,7 @@ namespace ESM { - class Class; + struct Class; struct Race; } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 735b02d2d..8417d00bf 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -65,7 +65,7 @@ namespace MWGui class MainMenu; class StatsWindow; class InventoryWindow; - class JournalWindow; + struct JournalWindow; class CharacterCreation; class DragAndDrop; class ToolTips; diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index c533296ff..39091b7b1 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -39,7 +39,7 @@ namespace ICS namespace MyGUI { - class MouseButton; + struct MouseButton; } namespace Files diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 80b48fc37..179ae440b 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -16,7 +16,7 @@ namespace ESM { namespace AiSequence { - class AiSequence; + struct AiSequence; } } diff --git a/apps/openmw/mwmechanics/aisequence.hpp b/apps/openmw/mwmechanics/aisequence.hpp index e43ce72f1..19f1e1454 100644 --- a/apps/openmw/mwmechanics/aisequence.hpp +++ b/apps/openmw/mwmechanics/aisequence.hpp @@ -15,7 +15,7 @@ namespace ESM { namespace AiSequence { - class AiSequence; + struct AiSequence; } } diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 5e1b41813..54e215cb9 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -17,7 +17,7 @@ namespace ESM { - class Cell; + struct Cell; namespace AiSequence { struct AiWander; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 8a77494b9..da74b2a33 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -21,7 +21,7 @@ namespace MWRender namespace MWMechanics { -class Movement; +struct Movement; class CreatureStats; enum Priority { diff --git a/apps/openmw/mwmechanics/pathgrid.hpp b/apps/openmw/mwmechanics/pathgrid.hpp index 2742957a6..67fbacded 100644 --- a/apps/openmw/mwmechanics/pathgrid.hpp +++ b/apps/openmw/mwmechanics/pathgrid.hpp @@ -6,7 +6,7 @@ namespace ESM { - class Cell; + struct Cell; } namespace MWWorld diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index dca4f0192..f50584edf 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -17,7 +17,7 @@ namespace ESM namespace MWMechanics { - class EffectKey; + struct EffectKey; class MagicEffects; ESM::Skill::SkillEnum spellSchoolToSkill(int school); diff --git a/apps/openmw/mwrender/globalmap.hpp b/apps/openmw/mwrender/globalmap.hpp index b3ae85b11..a162ab68f 100644 --- a/apps/openmw/mwrender/globalmap.hpp +++ b/apps/openmw/mwrender/globalmap.hpp @@ -12,7 +12,7 @@ namespace Loading namespace ESM { - class GlobalMap; + struct GlobalMap; } namespace MWRender diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index 7cfa38814..014c67f16 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -14,7 +14,7 @@ namespace MWWorld namespace ESM { - class FogTexture; + struct FogTexture; } namespace MWRender diff --git a/apps/openmw/mwscript/globalscripts.hpp b/apps/openmw/mwscript/globalscripts.hpp index 9f009db98..9b7aa0514 100644 --- a/apps/openmw/mwscript/globalscripts.hpp +++ b/apps/openmw/mwscript/globalscripts.hpp @@ -21,7 +21,7 @@ namespace Loading namespace MWWorld { - struct ESMStore; + class ESMStore; } namespace MWScript diff --git a/apps/openmw/mwscript/interpretercontext.hpp b/apps/openmw/mwscript/interpretercontext.hpp index 698df62c2..d3841befd 100644 --- a/apps/openmw/mwscript/interpretercontext.hpp +++ b/apps/openmw/mwscript/interpretercontext.hpp @@ -20,7 +20,7 @@ namespace MWInput namespace MWScript { - struct Locals; + class Locals; class InterpreterContext : public Interpreter::Context { diff --git a/apps/openmw/mwscript/locals.hpp b/apps/openmw/mwscript/locals.hpp index bd95835ac..a9fcf317c 100644 --- a/apps/openmw/mwscript/locals.hpp +++ b/apps/openmw/mwscript/locals.hpp @@ -7,7 +7,7 @@ namespace ESM { - struct Script; + class Script; struct Locals; } diff --git a/apps/openmw/mwscript/scriptmanagerimp.hpp b/apps/openmw/mwscript/scriptmanagerimp.hpp index 6026f6aba..e4a123b86 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.hpp +++ b/apps/openmw/mwscript/scriptmanagerimp.hpp @@ -16,7 +16,7 @@ namespace MWWorld { - struct ESMStore; + class ESMStore; } namespace Compiler diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index be12bfbec..1a95d6150 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -69,7 +69,7 @@ namespace MWSound OpenAL_Output(SoundManager &mgr); virtual ~OpenAL_Output(); - class StreamThread; + struct StreamThread; std::auto_ptr mStreamThread; friend class OpenAL_Sound; diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index a9a999a5c..4f5c210bb 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -13,7 +13,7 @@ namespace MWSound { class SoundManager; - class Sound_Decoder; + struct Sound_Decoder; class Sound; class Sound_Output diff --git a/apps/openmw/mwworld/localscripts.hpp b/apps/openmw/mwworld/localscripts.hpp index 840243fff..9d612cb33 100644 --- a/apps/openmw/mwworld/localscripts.hpp +++ b/apps/openmw/mwworld/localscripts.hpp @@ -8,7 +8,7 @@ namespace MWWorld { - struct ESMStore; + class ESMStore; class CellStore; class RefData; diff --git a/apps/openmw/mwworld/ptr.hpp b/apps/openmw/mwworld/ptr.hpp index 4d928dacf..c97d2e6d1 100644 --- a/apps/openmw/mwworld/ptr.hpp +++ b/apps/openmw/mwworld/ptr.hpp @@ -12,7 +12,7 @@ namespace MWWorld { class ContainerStore; class CellStore; - class LiveCellRefBase; + struct LiveCellRefBase; /// \brief Pointer to a LiveCellRef diff --git a/apps/openmw/mwworld/timestamp.hpp b/apps/openmw/mwworld/timestamp.hpp index 54cd40baf..36d11cee0 100644 --- a/apps/openmw/mwworld/timestamp.hpp +++ b/apps/openmw/mwworld/timestamp.hpp @@ -3,7 +3,7 @@ namespace ESM { - class TimeStamp; + struct TimeStamp; } namespace MWWorld diff --git a/components/nif/node.hpp b/components/nif/node.hpp index a26480d59..e6edf6432 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -14,7 +14,7 @@ namespace Nif { -class NiNode; +struct NiNode; /** A Node is an object that's part of the main NIF tree. It has parent node (unless it's the root), and transformation (location diff --git a/components/nif/recordptr.hpp b/components/nif/recordptr.hpp index 5eac277d0..25beaf098 100644 --- a/components/nif/recordptr.hpp +++ b/components/nif/recordptr.hpp @@ -122,10 +122,10 @@ class Controller; class Controlled; class NiSkinData; class NiFloatData; -class NiMorphData; +struct NiMorphData; class NiPixelData; class NiColorData; -class NiKeyframeData; +struct NiKeyframeData; class NiTriShapeData; class NiSkinInstance; class NiSourceTexture; diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index 56d98834d..0d81d84b6 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -38,8 +38,8 @@ namespace Nif { class Node; - class Transformation; - class NiTriShape; + struct Transformation; + struct NiTriShape; } namespace NifBullet diff --git a/components/nifogre/mesh.hpp b/components/nifogre/mesh.hpp index 731e49c90..69b3f2f78 100644 --- a/components/nifogre/mesh.hpp +++ b/components/nifogre/mesh.hpp @@ -10,7 +10,7 @@ namespace Nif { - class NiTriShape; + struct NiTriShape; } namespace NifOgre From 45b6538820482abef35f6ea0d4efb409fbde6d60 Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 6 Mar 2015 23:19:57 +1300 Subject: [PATCH 569/740] fixed MSVC 2013 warning C4800 forcing value to bool 'true' or 'false' --- apps/esmtool/record.cpp | 4 +-- apps/essimporter/convertacdt.cpp | 6 ++-- apps/essimporter/importcellref.cpp | 2 +- apps/mwiniimporter/main.cpp | 2 +- apps/openmw/mwclass/apparatus.cpp | 2 +- apps/openmw/mwclass/creature.cpp | 8 ++--- apps/openmw/mwclass/ingredient.cpp | 2 +- apps/openmw/mwclass/light.cpp | 4 +-- apps/openmw/mwclass/lockpick.cpp | 2 +- apps/openmw/mwclass/misc.cpp | 2 +- apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwclass/potion.cpp | 2 +- apps/openmw/mwclass/probe.cpp | 2 +- apps/openmw/mwclass/repair.cpp | 2 +- apps/openmw/mwgui/spellcreationdialog.cpp | 4 +-- apps/openmw/mwgui/widgets.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 8 ++--- apps/openmw/mwgui/windowmanagerimp.hpp | 2 +- apps/openmw/mwinput/inputmanagerimp.cpp | 2 +- apps/openmw/mwmechanics/alchemy.cpp | 2 +- apps/openmw/mwmechanics/creaturestats.cpp | 2 +- apps/openmw/mwmechanics/levelledlist.hpp | 2 +- apps/openmw/mwmechanics/spellcasting.cpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 4 +-- apps/openmw/mwscript/miscextensions.cpp | 2 +- apps/openmw/mwworld/refdata.cpp | 2 +- components/esm/aipackage.hpp | 2 +- components/esm/aisequence.hpp | 2 +- components/esm/loadcrea.cpp | 2 +- components/esm/loadnpc.cpp | 2 +- components/esm/loadstat.cpp | 2 +- components/nif/data.hpp | 4 +-- components/nifogre/ogrenifloader.cpp | 38 +++++++++++++---------- components/terrain/material.hpp | 2 +- extern/sdl4ogre/sdlinputwrapper.cpp | 4 +-- libs/openengine/bullet/physic.cpp | 6 ++-- libs/openengine/bullet/physic.hpp | 2 +- 37 files changed, 73 insertions(+), 69 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 6fd4b80fb..9e4b1496b 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -15,8 +15,8 @@ void printAIPackage(ESM::AIPackage p) std::cout << " Distance: " << p.mWander.mDistance << std::endl; std::cout << " Duration: " << p.mWander.mDuration << std::endl; std::cout << " Time of Day: " << (int)p.mWander.mTimeOfDay << std::endl; - if (p.mWander.mShouldRepeat != 1) - std::cout << " Should repeat: " << (bool)p.mWander.mShouldRepeat << std::endl; + if (!p.mWander.mShouldRepeat) + std::cout << " Should repeat: " << p.mWander.mShouldRepeat << std::endl; std::cout << " Idle: "; for (int i = 0; i != 8; i++) diff --git a/apps/essimporter/convertacdt.cpp b/apps/essimporter/convertacdt.cpp index 718403a8c..91dd8ef23 100644 --- a/apps/essimporter/convertacdt.cpp +++ b/apps/essimporter/convertacdt.cpp @@ -28,13 +28,13 @@ namespace ESSImport cStats.mAttributes[i].mCurrent = acdt.mAttributes[i][0]; } cStats.mGoldPool = acdt.mGoldPool; - cStats.mTalkedTo = acdt.mFlags & TalkedToPlayer; - cStats.mAttacked = acdt.mFlags & Attacked; + cStats.mTalkedTo = (acdt.mFlags & TalkedToPlayer) != 0; + cStats.mAttacked = (acdt.mFlags & Attacked) != 0; } void convertACSC (const ACSC& acsc, ESM::CreatureStats& cStats) { - cStats.mDead = acsc.mFlags & Dead; + cStats.mDead = (acsc.mFlags & Dead) != 0; } void convertNpcData (const ActorData& actorData, ESM::NpcStats& npcStats) diff --git a/apps/essimporter/importcellref.cpp b/apps/essimporter/importcellref.cpp index cca356b2a..442a7781c 100644 --- a/apps/essimporter/importcellref.cpp +++ b/apps/essimporter/importcellref.cpp @@ -43,7 +43,7 @@ namespace ESSImport { unsigned int deleted; esm.getHT(deleted); - mDeleted = (deleted >> 24) & 0x2; // the other 3 bytes seem to be uninitialized garbage + mDeleted = ((deleted >> 24) & 0x2) != 0; // the other 3 bytes seem to be uninitialized garbage } if (esm.isNextSub("MVRF")) diff --git a/apps/mwiniimporter/main.cpp b/apps/mwiniimporter/main.cpp index 3c48fedc9..a3f115fcf 100644 --- a/apps/mwiniimporter/main.cpp +++ b/apps/mwiniimporter/main.cpp @@ -110,7 +110,7 @@ int wmain(int argc, wchar_t *wargv[]) { std::cerr << "cfg file does not exist" << std::endl; MwIniImporter importer; - importer.setVerbose(vm.count("verbose")); + importer.setVerbose(vm.count("verbose") != 0); // Font encoding settings std::string encoding(vm["encoding"].as()); diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 316ba3ab6..2abd071bd 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -155,7 +155,7 @@ namespace MWClass bool Apparatus::canSell (const MWWorld::Ptr& item, int npcServices) const { - return npcServices & ESM::NPC::Apparatus; + return (npcServices & ESM::NPC::Apparatus) != 0; } float Apparatus::getWeight(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index e44f4ffc1..c59f8428c 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -164,7 +164,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); MWRender::Actors& actors = renderingInterface.getActors(); - actors.insertCreature(ptr, model, ref->mBase->mFlags & ESM::Creature::Weapon); + actors.insertCreature(ptr, model, (ref->mBase->mFlags & ESM::Creature::Weapon) != 0); } void Creature::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const @@ -493,7 +493,7 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return (ref->mBase->mFlags & ESM::Creature::Weapon); + return (ref->mBase->mFlags & ESM::Creature::Weapon) != 0; } std::string Creature::getScript (const MWWorld::Ptr& ptr) const @@ -508,7 +508,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->mBase->mFlags & ESM::Creature::Essential; + return (ref->mBase->mFlags & ESM::Creature::Essential) != 0; } void Creature::registerSelf() @@ -713,7 +713,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->mBase->mFlags & ESM::Creature::Flies; + return (ref->mBase->mFlags & ESM::Creature::Flies) != 0; } bool Creature::canSwim(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 9f662a60e..de43e818e 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -192,7 +192,7 @@ namespace MWClass bool Ingredient::canSell (const MWWorld::Ptr& item, int npcServices) const { - return npcServices & ESM::NPC::Ingredients; + return (npcServices & ESM::NPC::Ingredients) != 0; } diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 35a21b63e..032c40237 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -50,7 +50,7 @@ namespace MWClass assert (ref->mBase != NULL); if(!model.empty()) - physics.addObject(ptr, model, ref->mBase->mData.mFlags & ESM::Light::Carry); + physics.addObject(ptr, model, (ref->mBase->mData.mFlags & ESM::Light::Carry) != 0); 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, @@ -221,7 +221,7 @@ namespace MWClass bool Light::canSell (const MWWorld::Ptr& item, int npcServices) const { - return npcServices & ESM::NPC::Lights; + return (npcServices & ESM::NPC::Lights) != 0; } float Light::getWeight(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index e78c43eee..478c50301 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -173,7 +173,7 @@ namespace MWClass bool Lockpick::canSell (const MWWorld::Ptr& item, int npcServices) const { - return npcServices & ESM::NPC::Picks; + return (npcServices & ESM::NPC::Picks) != 0; } int Lockpick::getItemMaxHealth (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index f9cfd8e0b..f5daafeec 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -259,7 +259,7 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return ref->mBase->mData.mIsKey; + return ref->mBase->mData.mIsKey != 0; } } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 52e5a0a95..d06d7cfe1 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -993,7 +993,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->mBase->mFlags & ESM::NPC::Essential; + return (ref->mBase->mFlags & ESM::NPC::Essential) != 0; } void Npc::registerSelf() diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index bd06f89fc..ee299ab4f 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -185,7 +185,7 @@ namespace MWClass bool Potion::canSell (const MWWorld::Ptr& item, int npcServices) const { - return npcServices & ESM::NPC::Potions; + return (npcServices & ESM::NPC::Potions) != 0; } float Potion::getWeight(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index a11725f26..da22e9be6 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -172,7 +172,7 @@ namespace MWClass bool Probe::canSell (const MWWorld::Ptr& item, int npcServices) const { - return npcServices & ESM::NPC::Probes; + return (npcServices & ESM::NPC::Probes) != 0; } int Probe::getItemMaxHealth (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index e9c4ac9b1..c02146f12 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -172,7 +172,7 @@ namespace MWClass bool Repair::canSell (const MWWorld::Ptr& item, int npcServices) const { - return npcServices & ESM::NPC::RepairItem; + return (npcServices & ESM::NPC::RepairItem) != 0; } float Repair::getWeight(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index f4c9d021a..2757b7cae 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -114,7 +114,7 @@ namespace MWGui void EditEffectDialog::newEffect (const ESM::MagicEffect *effect) { - bool allowSelf = effect->mData.mFlags & ESM::MagicEffect::CastSelf; + bool allowSelf = (effect->mData.mFlags & ESM::MagicEffect::CastSelf) != 0; bool allowTouch = (effect->mData.mFlags & ESM::MagicEffect::CastTouch) && !mConstantEffect; bool allowTarget = (effect->mData.mFlags & ESM::MagicEffect::CastTarget) && !mConstantEffect; @@ -226,7 +226,7 @@ namespace MWGui // cycle through range types until we find something that's allowed // does not handle the case where nothing is allowed (this should be prevented before opening the Add Effect dialog) - bool allowSelf = mMagicEffect->mData.mFlags & ESM::MagicEffect::CastSelf; + bool allowSelf = (mMagicEffect->mData.mFlags & ESM::MagicEffect::CastSelf) != 0; bool allowTouch = (mMagicEffect->mData.mFlags & ESM::MagicEffect::CastTouch) && !mConstantEffect; bool allowTarget = (mMagicEffect->mData.mFlags & ESM::MagicEffect::CastTarget) && !mConstantEffect; if (mEffect.mRange == ESM::RT_Self && !allowSelf) diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 26fe31567..79c0f93f0 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -239,7 +239,7 @@ namespace MWGui params.mMagnMin = it->mMagnMin; params.mMagnMax = it->mMagnMax; params.mRange = it->mRange; - params.mIsConstant = (flags & MWEffectList::EF_Constant); + params.mIsConstant = (flags & MWEffectList::EF_Constant) != 0; params.mNoTarget = (flags & MWEffectList::EF_NoTarget); effect->setSpellEffect(params); effects.push_back(effect); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index c74cff31c..bd7e22e7c 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -566,10 +566,10 @@ namespace MWGui // Show the windows we want mMap ->setVisible(eff & GW_Map); - mStatsWindow ->setVisible(eff & GW_Stats); - mInventoryWindow->setVisible(eff & GW_Inventory); + mStatsWindow ->setVisible((eff & GW_Stats) != 0); + mInventoryWindow->setVisible((eff & GW_Inventory) != 0); mInventoryWindow->setGuiMode(mode); - mSpellWindow ->setVisible(eff & GW_Magic); + mSpellWindow ->setVisible((eff & GW_Magic) != 0); break; } case GM_Container: @@ -1301,7 +1301,7 @@ namespace MWGui bool WindowManager::isAllowed (GuiWindow wnd) const { - return mAllowed & wnd; + return (mAllowed & wnd) != 0; } void WindowManager::allow (GuiWindow wnd) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 8417d00bf..fbbc295b3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -277,7 +277,7 @@ namespace MWGui virtual void enableRest() { mRestAllowed = true; } virtual bool getRestEnabled(); - virtual bool getJournalAllowed() { return (mAllowed & GW_Magic); } + virtual bool getJournalAllowed() { return (mAllowed & GW_Magic) != 0; } virtual bool getPlayerSleeping(); virtual void wakeUpPlayer(); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 4212c562b..e84e2c5b3 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -250,7 +250,7 @@ namespace MWInput if (mControlSwitch["playercontrols"]) { if (action == A_Use) - mPlayer->getPlayer().getClass().getCreatureStats(mPlayer->getPlayer()).setAttackingOrSpell(currentValue); + mPlayer->getPlayer().getClass().getCreatureStats(mPlayer->getPlayer()).setAttackingOrSpell(currentValue != 0); else if (action == A_Jump) mAttemptJump = (currentValue == 1.0 && previousValue == 0.0); } diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index f3d376a70..6e54b6f83 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -67,7 +67,7 @@ void MWMechanics::Alchemy::applyTools (int flags, float& value) const { bool magnitude = !(flags & ESM::MagicEffect::NoMagnitude); bool duration = !(flags & ESM::MagicEffect::NoDuration); - bool negative = flags & (ESM::MagicEffect::Harmful); + bool negative = (flags & ESM::MagicEffect::Harmful) != 0; int tool = negative ? ESM::Apparatus::Retort : ESM::Apparatus::Albemic; diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 05ea9fb5e..1947ad839 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -439,7 +439,7 @@ namespace MWMechanics bool CreatureStats::getMovementFlag (Flag flag) const { - return mMovementFlags & flag; + return (mMovementFlags & flag) != 0; } void CreatureStats::setMovementFlag (Flag flag, bool state) diff --git a/apps/openmw/mwmechanics/levelledlist.hpp b/apps/openmw/mwmechanics/levelledlist.hpp index 691996410..db13c1a45 100644 --- a/apps/openmw/mwmechanics/levelledlist.hpp +++ b/apps/openmw/mwmechanics/levelledlist.hpp @@ -35,7 +35,7 @@ namespace MWMechanics } // For levelled creatures, the flags are swapped. This file format just makes so much sense. - bool allLevels = levItem->mFlags & ESM::ItemLevList::AllLevels; + bool allLevels = (levItem->mFlags & ESM::ItemLevList::AllLevels) != 0; if (creature) allLevels = levItem->mFlags & ESM::CreatureLevList::AllLevels; diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index b91ea9984..06a3c1dfd 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -573,7 +573,7 @@ namespace MWMechanics castStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_DefaultHit"); // TODO: VFX are no longer active after saving/reloading the game - bool loop = magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx; + bool loop = (magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx) != 0; // Note: in case of non actor, a free effect should be fine as well MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(target); if (anim) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 66ba25859..a2ad1e02c 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -377,7 +377,7 @@ void NpcAnimation::updateParts() }; static const size_t slotlistsize = sizeof(slotlist)/sizeof(slotlist[0]); - bool wasArrowAttached = (mAmmunition.get()); + bool wasArrowAttached = (mAmmunition.get() != NULL); MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr); for(size_t i = 0;i < slotlistsize && mViewMode != VM_HeadOnly;i++) @@ -941,7 +941,7 @@ void NpcAnimation::permanentEffectAdded(const ESM::MagicEffect *magicEffect, boo if (!magicEffect->mHit.empty()) { const ESM::Static* castStatic = MWBase::Environment::get().getWorld()->getStore().get().find (magicEffect->mHit); - bool loop = magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx; + bool loop = (magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx) != 0; // Don't play particle VFX unless the effect is new or it should be looping. if (isNew || loop) addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, ""); diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 52094947c..f69031b2c 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -81,7 +81,7 @@ namespace MWScript std::string name = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - bool allowSkipping = runtime[0].mInteger; + bool allowSkipping = runtime[0].mInteger != 0; runtime.pop(); MWBase::Environment::get().getWindowManager()->playVideo (name, allowSkipping); diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index c2a5e5f83..14a315a81 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -59,7 +59,7 @@ namespace MWWorld } RefData::RefData (const ESM::ObjectState& objectState) - : mBaseNode (0), mHasLocals (false), mEnabled (objectState.mEnabled), + : mBaseNode (0), mHasLocals (false), mEnabled (objectState.mEnabled != 0), mCount (objectState.mCount), mPosition (objectState.mPosition), mCustomData (0), mChanged(true), // Loading from a savegame -> assume changed mDeleted(false) diff --git a/components/esm/aipackage.hpp b/components/esm/aipackage.hpp index 5e08806c8..b164b3d62 100644 --- a/components/esm/aipackage.hpp +++ b/components/esm/aipackage.hpp @@ -32,7 +32,7 @@ namespace ESM short mDuration; unsigned char mTimeOfDay; unsigned char mIdle[8]; - unsigned char mShouldRepeat; + bool mShouldRepeat; }; struct AITravel diff --git a/components/esm/aisequence.hpp b/components/esm/aisequence.hpp index 2560fbe7d..c2142ab34 100644 --- a/components/esm/aisequence.hpp +++ b/components/esm/aisequence.hpp @@ -44,7 +44,7 @@ namespace ESM short mDuration; unsigned char mTimeOfDay; unsigned char mIdle[8]; - unsigned char mShouldRepeat; + bool mShouldRepeat; }; struct AiTravelData { diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index 2e9f924b7..86eede34e 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -10,7 +10,7 @@ namespace ESM { void Creature::load(ESMReader &esm) { - mPersistent = esm.getRecordFlags() & 0x0400; + mPersistent = (esm.getRecordFlags() & 0x0400) != 0; mAiPackage.mList.clear(); mInventory.mList.clear(); diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index d90b4816d..98cedbe42 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -10,7 +10,7 @@ namespace ESM void NPC::load(ESMReader &esm) { - mPersistent = esm.getRecordFlags() & 0x0400; + mPersistent = (esm.getRecordFlags() & 0x0400) != 0; mSpells.mList.clear(); mInventory.mList.clear(); diff --git a/components/esm/loadstat.cpp b/components/esm/loadstat.cpp index 2bb817332..ed90b0475 100644 --- a/components/esm/loadstat.cpp +++ b/components/esm/loadstat.cpp @@ -10,7 +10,7 @@ namespace ESM void Static::load(ESMReader &esm) { - mPersistent = esm.getRecordFlags() & 0x0400; + mPersistent = (esm.getRecordFlags() & 0x0400) != 0; mModel = esm.getHNString("MODL"); } diff --git a/components/nif/data.hpp b/components/nif/data.hpp index d9de12fb5..1fa94d9c2 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -234,7 +234,7 @@ class NiVisData : public Record public: struct VisData { float time; - char isSet; + bool isSet; }; std::vector mVis; @@ -245,7 +245,7 @@ public: for(size_t i = 0;i < mVis.size();i++) { mVis[i].time = nif->getFloat(); - mVis[i].isSet = nif->getChar(); + mVis[i].isSet = nif->getChar() != 0; } } }; diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 17df7a3cd..0009c9f83 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -379,7 +379,7 @@ public: return mData.back().isSet; } - static void setVisible(Ogre::Node *node, int vis) + static void setVisible(Ogre::Node *node, bool vis) { // Skinned meshes are attached to the scene node, not the bone. // We use the Node's user data to connect it with the mesh. @@ -746,16 +746,17 @@ private: { if (ctrl->flags & Nif::NiNode::ControllerFlag_Active) { + bool isAnimationAutoPlay = (animflags & Nif::NiNode::AnimFlag_AutoPlay) != 0; if(ctrl->recType == Nif::RC_NiUVController) { const Nif::NiUVController *uv = static_cast(ctrl.getPtr()); - Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? + Ogre::ControllerValueRealPtr srcval(isAnimationAutoPlay ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW UVController::Value(entity, uv->data.getPtr(), &scene->mMaterialControllerMgr)); - UVController::Function* function = OGRE_NEW UVController::Function(uv, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); + UVController::Function* function = OGRE_NEW UVController::Function(uv, isAnimationAutoPlay); scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); Ogre::ControllerFunctionRealPtr func(function); @@ -765,13 +766,13 @@ private: { const Nif::NiGeomMorpherController *geom = static_cast(ctrl.getPtr()); - Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? + Ogre::ControllerValueRealPtr srcval(isAnimationAutoPlay ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW GeomMorpherController::Value( entity, geom->data.getPtr(), geom->recIndex)); - GeomMorpherController::Function* function = OGRE_NEW GeomMorpherController::Function(geom, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); + GeomMorpherController::Function* function = OGRE_NEW GeomMorpherController::Function(geom, isAnimationAutoPlay); scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); Ogre::ControllerFunctionRealPtr func(function); @@ -796,7 +797,8 @@ private: const Nif::NiStencilProperty *stencilprop = NULL; node->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop, stencilprop); - Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? + bool isAnimationAutoPlay = (animflags & Nif::NiNode::AnimFlag_AutoPlay) != 0; + Ogre::ControllerValueRealPtr srcval(isAnimationAutoPlay ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : Ogre::ControllerValueRealPtr()); @@ -809,7 +811,7 @@ private: { const Nif::NiAlphaController *alphaCtrl = static_cast(ctrls.getPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW AlphaController::Value(movable, alphaCtrl->data.getPtr(), &scene->mMaterialControllerMgr)); - AlphaController::Function* function = OGRE_NEW AlphaController::Function(alphaCtrl, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); + AlphaController::Function* function = OGRE_NEW AlphaController::Function(alphaCtrl, isAnimationAutoPlay); scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); Ogre::ControllerFunctionRealPtr func(function); scene->mControllers.push_back(Ogre::Controller(srcval, dstval, func)); @@ -818,7 +820,7 @@ private: { const Nif::NiMaterialColorController *matCtrl = static_cast(ctrls.getPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW MaterialColorController::Value(movable, matCtrl->data.getPtr(), &scene->mMaterialControllerMgr)); - MaterialColorController::Function* function = OGRE_NEW MaterialColorController::Function(matCtrl, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); + MaterialColorController::Function* function = OGRE_NEW MaterialColorController::Function(matCtrl, isAnimationAutoPlay); scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); Ogre::ControllerFunctionRealPtr func(function); scene->mControllers.push_back(Ogre::Controller(srcval, dstval, func)); @@ -839,7 +841,7 @@ private: Ogre::ControllerValueRealPtr dstval(OGRE_NEW FlipController::Value( movable, flipCtrl, &scene->mMaterialControllerMgr)); - FlipController::Function* function = OGRE_NEW FlipController::Function(flipCtrl, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); + FlipController::Function* function = OGRE_NEW FlipController::Function(flipCtrl, isAnimationAutoPlay); scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); Ogre::ControllerFunctionRealPtr func(function); scene->mControllers.push_back(Ogre::Controller(srcval, dstval, func)); @@ -967,7 +969,7 @@ private: partsys->setCullIndividually(false); partsys->setParticleQuota(particledata->numParticles); - partsys->setKeepParticlesInLocalSpace(partflags & (Nif::NiNode::ParticleFlag_LocalSpace)); + partsys->setKeepParticlesInLocalSpace((partflags & Nif::NiNode::ParticleFlag_LocalSpace) != 0); int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partnode->recIndex); Ogre::Bone *trgtbone = scene->mSkelBase->getSkeleton()->getBone(trgtid); @@ -1017,13 +1019,14 @@ private: createParticleInitialState(partsys, particledata, partctrl); - Ogre::ControllerValueRealPtr srcval((partflags&Nif::NiNode::ParticleFlag_AutoPlay) ? + bool isParticleAutoPlay = (partflags&Nif::NiNode::ParticleFlag_AutoPlay) != 0; + Ogre::ControllerValueRealPtr srcval(isParticleAutoPlay ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW ParticleSystemController::Value(partsys, partctrl)); ParticleSystemController::Function* function = - OGRE_NEW ParticleSystemController::Function(partctrl, (partflags&Nif::NiNode::ParticleFlag_AutoPlay)); + OGRE_NEW ParticleSystemController::Function(partctrl, isParticleAutoPlay); scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); Ogre::ControllerFunctionRealPtr func(function); @@ -1032,7 +1035,7 @@ private: // Emitting state will be overwritten on frame update by the ParticleSystemController, // but set up an initial value anyway so the user can fast-forward particle systems // immediately after creation if desired. - partsys->setEmitting(partflags&Nif::NiNode::ParticleFlag_AutoPlay); + partsys->setEmitting(isParticleAutoPlay); } ctrl = ctrl->next; } @@ -1094,18 +1097,19 @@ private: do { if (ctrl->flags & Nif::NiNode::ControllerFlag_Active) { + bool isAnimationAutoPlay = (animflags & Nif::NiNode::AnimFlag_AutoPlay) != 0; if(ctrl->recType == Nif::RC_NiVisController) { const Nif::NiVisController *vis = static_cast(ctrl.getPtr()); int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); Ogre::Bone *trgtbone = scene->mSkelBase->getSkeleton()->getBone(trgtid); - Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? + Ogre::ControllerValueRealPtr srcval(isAnimationAutoPlay ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW VisController::Value(trgtbone, vis->data.getPtr())); - VisController::Function* function = OGRE_NEW VisController::Function(vis, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); + VisController::Function* function = OGRE_NEW VisController::Function(vis, isAnimationAutoPlay); scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); Ogre::ControllerFunctionRealPtr func(function); @@ -1120,11 +1124,11 @@ private: Ogre::Bone *trgtbone = scene->mSkelBase->getSkeleton()->getBone(trgtid); // The keyframe controller will control this bone manually trgtbone->setManuallyControlled(true); - Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? + Ogre::ControllerValueRealPtr srcval(isAnimationAutoPlay ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, nif, key->data.getPtr())); - KeyframeController::Function* function = OGRE_NEW KeyframeController::Function(key, (animflags&Nif::NiNode::AnimFlag_AutoPlay)); + KeyframeController::Function* function = OGRE_NEW KeyframeController::Function(key, isAnimationAutoPlay); scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); Ogre::ControllerFunctionRealPtr func(function); diff --git a/components/terrain/material.hpp b/components/terrain/material.hpp index f35080e7c..b79df9f48 100644 --- a/components/terrain/material.hpp +++ b/components/terrain/material.hpp @@ -35,7 +35,7 @@ namespace Terrain MaterialGenerator (); void setLayerList (const std::vector& layerList) { mLayerList = layerList; } - bool hasLayers() { return mLayerList.size(); } + bool hasLayers() { return mLayerList.size() > 0; } void setBlendmapList (const std::vector& blendmapList) { mBlendmapList = blendmapList; } const std::vector& getBlendmapList() { return mBlendmapList; } void setCompositeMap (const std::string& name) { mCompositeMap = name; } diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index 439c4c131..aaf669ff4 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -201,12 +201,12 @@ namespace SFO bool InputWrapper::isModifierHeld(SDL_Keymod mod) { - return SDL_GetModState() & mod; + return (SDL_GetModState() & mod) != 0; } bool InputWrapper::isKeyDown(SDL_Scancode key) { - return SDL_GetKeyboardState(NULL)[key]; + return (SDL_GetKeyboardState(NULL)[key]) != 0; } /// \brief Moves the mouse to the specified point within the viewport diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index b3e9f1395..e0482104a 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -283,14 +283,14 @@ namespace Physic } } - void PhysicEngine::setDebugRenderingMode(int mode) + void PhysicEngine::setDebugRenderingMode(bool isDebug) { if(!isDebugCreated) { createDebugRendering(); } - mDebugDrawer->setDebugMode(mode); - mDebugActive = mode; + mDebugDrawer->setDebugMode(isDebug); + mDebugActive = isDebug; } bool PhysicEngine::toggleDebugRendering() diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index f497150f9..1a16ff4e8 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -283,7 +283,7 @@ namespace Physic * Set the debug rendering mode. 0 to turn it off. * Important Note: this will crash if the Render is not yet initialise! */ - void setDebugRenderingMode(int mode); + void setDebugRenderingMode(bool isDebug); bool toggleDebugRendering(); From 27f91a83263a6ce1473f4859d9d9c16932d464e6 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 5 Mar 2015 20:21:22 +1300 Subject: [PATCH 570/740] correction from Scrawl. Now correctly handles skills/attributes. Also, document what ContentSelectorView::ContentSelector::slotAddonTableItemActivated() is doing. --- apps/openmw/mwmechanics/activespells.cpp | 2 +- components/contentselector/view/contentselector.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index eec4f2bd3..b4701126b 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -185,7 +185,7 @@ namespace MWMechanics bool missing = true; for (std::vector::const_iterator iter(addTo.begin()); iter != addTo.end(); ++iter) { - if (effect->mEffectId == iter->mEffectId) + if ((effect->mEffectId == iter->mEffectId) && (effect->mArg == iter->mArg)) { missing = false; break; diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index 2363ae477..e3093d568 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -183,6 +183,7 @@ void ContentSelectorView::ContentSelector::setGameFileSelected(int index, bool s void ContentSelectorView::ContentSelector::slotAddonTableItemActivated(const QModelIndex &index) { + // toggles check state when an AddOn file is double clicked or activated by keyboard QModelIndex sourceIndex = mAddonProxyModel->mapToSource (index); if (!mContentModel->isEnabled (sourceIndex)) From 900745f577c5f0ce55d354404205891dc2a1bdd4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 6 Mar 2015 20:05:05 +0100 Subject: [PATCH 571/740] updated changelog --- CHANGELOG.md | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2aa03dc2..8bbee6fe0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,41 @@ +0.35.1 +------ + + Bug #781: incorrect trajectory of the sun + Bug #1079: Wrong starting position in "Character Stuff Wonderland" + Bug #1443: Repetitive taking of a stolen object is repetitively considered as a crime + Bug #1533: Divine Intervention goes to the wrong place. + Bug #1714: No visual indicator for time passed during training + Bug #1916: Telekinesis does not allow safe opening of traps + Bug #2227: Editor: addon file name inconsistency + Bug #2271: Player can melee enemies from water with impunity + Bug #2275: Objects with bigger scale move further using Move script + Bug #2285: Aryon's Dominator enchantment does not work properly + Bug #2290: No punishment for stealing gold from owned containers + Bug #2328: Launcher does not respond to Ctrl+C + Bug #2334: Drag-and-drop on a content file in the launcher creates duplicate items + Bug #2338: Arrows reclaimed from corpses do not stack sometimes + Bug #2344: Launcher - Settings importer running correctly? + Bug #2348: Mod: H.E.L.L.U.V.A. Handy Holdables does not appear in the content list + Bug #2353: Detect Animal detects dead creatures + Bug #2354: Cmake does not respect LIB_SUFFIX + Bug #2356: Active magic set inactive when switching magic items + Bug #2361: ERROR: ESM Error: Previous record contains unread bytes + Bug #2382: Switching spells with "next spell" or "previous spell" while holding shift promps delete spell dialog + Bug #2388: Regression: Can't toggle map on/off + Bug #2392: MOD Shrines - Restore Health and Cancel Options adds 100 health points + Bug #2394: List of Data Files tab in openmw-laucher needs to show all content files. + Bug #2402: Editor: skills saved incorrectly + Bug #2408: Equipping a constant effect Restore Health/Magicka/Fatigue item will permanently boost the stat it's restoring + Bug #2415: It is now possible to fall off the prison ship into the water when starting a new game + Bug #2419: MOD MCA crash to desktop + Bug #2420: Game crashes when character enters a certain area + Bug #2421: infinite loop when using cycle weapon without having a weapon + Feature #2221: Cannot dress dead NPCs + Feature #2349: Check CMake sets correct MSVC compiler settings for release build. + Feature #2397: Set default values for global mandatory records. + Feature #2412: Basic joystick support + 0.35.0 ------ From f2ac939e61e60d106165b4ba98f723b63909ebfa Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 7 Mar 2015 11:04:54 +1300 Subject: [PATCH 572/740] reverted mShouldRepeat back to unsigned char. As recommended by Scrawl. --- apps/esmtool/record.cpp | 4 ++-- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- apps/openmw/mwmechanics/aisequence.cpp | 2 +- apps/openmw/mwmechanics/aiwander.cpp | 2 +- components/esm/aipackage.hpp | 2 +- components/esm/aisequence.hpp | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 9e4b1496b..be9b03e80 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -15,8 +15,8 @@ void printAIPackage(ESM::AIPackage p) std::cout << " Distance: " << p.mWander.mDistance << std::endl; std::cout << " Duration: " << p.mWander.mDuration << std::endl; std::cout << " Time of Day: " << (int)p.mWander.mTimeOfDay << std::endl; - if (!p.mWander.mShouldRepeat) - std::cout << " Should repeat: " << p.mWander.mShouldRepeat << std::endl; + if (p.mWander.mShouldRepeat != 1) + std::cout << " Should repeat: " << (bool)(p.mWander.mShouldRepeat != 0) << std::endl; std::cout << " Idle: "; for (int i = 0; i != 8; i++) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index bd7e22e7c..d8074a5d8 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -565,7 +565,7 @@ namespace MWGui int eff = mShown & mAllowed & ~mForceHidden; // Show the windows we want - mMap ->setVisible(eff & GW_Map); + mMap ->setVisible((eff & GW_Map) != 0); mStatsWindow ->setVisible((eff & GW_Stats) != 0); mInventoryWindow->setVisible((eff & GW_Inventory) != 0); mInventoryWindow->setGuiMode(mode); diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 533bcd17c..bb078f883 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -294,7 +294,7 @@ void AiSequence::fill(const ESM::AIPackageList &list) idles.reserve(8); for (int i=0; i<8; ++i) idles.push_back(data.mIdle[i]); - package = new MWMechanics::AiWander(data.mDistance, data.mDuration, data.mTimeOfDay, idles, data.mShouldRepeat); + package = new MWMechanics::AiWander(data.mDistance, data.mDuration, data.mTimeOfDay, idles, data.mShouldRepeat != 0); } else if (it->mType == ESM::AI_Escort) { diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index fbb147b34..738facb13 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -785,7 +785,7 @@ namespace MWMechanics , mDuration(wander->mData.mDuration) , mStartTime(MWWorld::TimeStamp(wander->mStartTime)) , mTimeOfDay(wander->mData.mTimeOfDay) - , mRepeat(wander->mData.mShouldRepeat) + , mRepeat(wander->mData.mShouldRepeat != 0) , mStoredInitialActorPosition(wander->mStoredInitialActorPosition) { if (mStoredInitialActorPosition) diff --git a/components/esm/aipackage.hpp b/components/esm/aipackage.hpp index b164b3d62..5e08806c8 100644 --- a/components/esm/aipackage.hpp +++ b/components/esm/aipackage.hpp @@ -32,7 +32,7 @@ namespace ESM short mDuration; unsigned char mTimeOfDay; unsigned char mIdle[8]; - bool mShouldRepeat; + unsigned char mShouldRepeat; }; struct AITravel diff --git a/components/esm/aisequence.hpp b/components/esm/aisequence.hpp index c2142ab34..2560fbe7d 100644 --- a/components/esm/aisequence.hpp +++ b/components/esm/aisequence.hpp @@ -44,7 +44,7 @@ namespace ESM short mDuration; unsigned char mTimeOfDay; unsigned char mIdle[8]; - bool mShouldRepeat; + unsigned char mShouldRepeat; }; struct AiTravelData { From ca21181483d203de200c3ee963a3abe07f5ede14 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 7 Mar 2015 11:42:50 +1100 Subject: [PATCH 573/740] Fix typo to get table display working. --- apps/opencs/model/world/columnbase.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 5926df269..607f585b7 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -145,9 +145,9 @@ namespace CSMWorld void addNestedColumn(int columnId, Display displayType); bool canHaveNestedColumns() const; - + const ColumnBase& nestedColumn(int subColumn) const; - + int nestedColumnCount() const; }; @@ -157,15 +157,15 @@ namespace CSMWorld public: NestedColumn(int columnId, Display displayType, int flag, const NestColumn* parent); - + virtual bool isEditable() const; }; - + template struct Column : public NestColumn { Column (int columnId, Display displayType, int flags = Flag_Table | Flag_Dialogue, bool canNest = false) - : NestColumn (columnId, displayType, canNest, flags) {} + : NestColumn (columnId, displayType, flags, canNest) {} virtual QVariant get (const Record& record) const = 0; From 58807064b4f427c45613f3feafaf1ae28c166230 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Mar 2015 15:31:21 +0100 Subject: [PATCH 574/740] Revert "Fix reference cell movement leaving behind deleted Ptrs for script access" This reverts commit 666248618eb2e4ca2003f51a5dbc1891baa98998. --- apps/openmw/mwworld/worldimp.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 3ef4f8e81..8a2b67bfc 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1206,10 +1206,6 @@ namespace MWWorld } } ptr.getRefData().setCount(0); - // Deleted references can still be accessed by scripts, - // so we need this extra step to remove access to the old reference completely. - // This will no longer be necessary once we have a proper cell movement tracker. - ptr.getCellRef().unsetRefNum(); } } if (haveToMove && ptr.getRefData().getBaseNode()) From a54ab153b0cdd226f9ad2e9c91913408dbf6a0da Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 8 Mar 2015 10:05:10 +1100 Subject: [PATCH 575/740] Cloned references should be considered "Base" rather than "Modified". Should fix bug #2429. --- apps/opencs/model/world/refidcollection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 779d5a40c..75429d906 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -471,7 +471,7 @@ void CSMWorld::RefIdCollection::cloneRecord(const std::string& origin, const CSMWorld::UniversalId::Type type) { std::auto_ptr newRecord(mData.getRecord(mData.searchId(origin)).clone()); - newRecord->mState = RecordBase::State_ModifiedOnly; + newRecord->mState = RecordBase::State_BaseOnly; mAdapters.find(type)->second->setId(*newRecord, destination); mData.insertRecord(*newRecord, type, destination); } From e197f5318b7a2f820694096e82964142635ad28c Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 8 Mar 2015 13:07:29 +1300 Subject: [PATCH 576/740] fixing MSVC 2013 warning C4244: & C4305 conversion from 'const float' to 'int', possible loss of data conversion from 'double' to 'int', possible loss of data conversion from 'float' to 'int', possible loss of data --- apps/esmtool/esmtool.cpp | 2 +- apps/essimporter/convertacdt.cpp | 6 +- apps/essimporter/converter.hpp | 2 +- apps/openmw/engine.cpp | 2 +- apps/openmw/mwclass/armor.cpp | 6 +- apps/openmw/mwclass/clothing.cpp | 2 +- apps/openmw/mwclass/creature.cpp | 16 ++-- apps/openmw/mwclass/door.cpp | 10 +-- apps/openmw/mwclass/light.cpp | 2 +- apps/openmw/mwclass/npc.cpp | 26 +++---- apps/openmw/mwclass/weapon.cpp | 2 +- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 6 +- apps/openmw/mwgui/backgroundimage.cpp | 4 +- apps/openmw/mwgui/bookpage.cpp | 26 +++---- apps/openmw/mwgui/bookpage.hpp | 2 +- apps/openmw/mwgui/companionwindow.cpp | 2 +- apps/openmw/mwgui/controllers.cpp | 4 +- apps/openmw/mwgui/dialogue.cpp | 6 +- apps/openmw/mwgui/hud.cpp | 4 +- apps/openmw/mwgui/inventorywindow.cpp | 12 +-- apps/openmw/mwgui/itemview.cpp | 4 +- apps/openmw/mwgui/jailscreen.cpp | 6 +- apps/openmw/mwgui/loadingscreen.cpp | 10 +-- apps/openmw/mwgui/mapwindow.cpp | 34 ++++---- apps/openmw/mwgui/merchantrepair.cpp | 12 +-- apps/openmw/mwgui/messagebox.cpp | 2 +- apps/openmw/mwgui/race.cpp | 4 +- apps/openmw/mwgui/recharge.cpp | 12 +-- apps/openmw/mwgui/review.cpp | 10 +-- apps/openmw/mwgui/settingswindow.cpp | 6 +- apps/openmw/mwgui/spellbuyingwindow.cpp | 4 +- apps/openmw/mwgui/spellcreationdialog.cpp | 8 +- apps/openmw/mwgui/spellicons.cpp | 2 +- apps/openmw/mwgui/spellmodel.cpp | 2 +- apps/openmw/mwgui/spellview.cpp | 4 +- apps/openmw/mwgui/statswindow.cpp | 6 +- apps/openmw/mwgui/tooltips.cpp | 4 +- apps/openmw/mwgui/tradewindow.cpp | 25 +++--- apps/openmw/mwgui/trainingwindow.cpp | 2 +- apps/openmw/mwgui/travelwindow.cpp | 8 +- apps/openmw/mwgui/videowidget.cpp | 4 +- apps/openmw/mwgui/waitdialog.cpp | 12 +-- apps/openmw/mwgui/widgets.cpp | 4 +- apps/openmw/mwgui/windowmanagerimp.cpp | 24 +++--- apps/openmw/mwinput/inputmanagerimp.cpp | 34 ++++---- apps/openmw/mwmechanics/disease.hpp | 10 +-- apps/openmw/mwmechanics/levelledlist.hpp | 2 +- .../mwmechanics/mechanicsmanagerimp.cpp | 77 +++++++++---------- apps/openmw/mwmechanics/stat.hpp | 1 - apps/openmw/mwrender/animation.cpp | 4 +- apps/openmw/mwrender/characterpreview.cpp | 4 +- apps/openmw/mwrender/globalmap.cpp | 35 +++++---- apps/openmw/mwrender/localmap.cpp | 42 +++++----- apps/openmw/mwrender/npcanimation.cpp | 2 +- apps/openmw/mwrender/refraction.cpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 24 +++--- apps/openmw/mwrender/ripplesimulation.cpp | 2 +- apps/openmw/mwrender/shadows.cpp | 4 +- apps/openmw/mwrender/sky.cpp | 24 +++--- apps/openmw/mwrender/terrainstorage.cpp | 8 +- apps/openmw/mwrender/water.cpp | 7 +- apps/openmw/mwrender/water.hpp | 2 +- apps/openmw/mwscript/aiextensions.cpp | 10 +-- apps/openmw/mwscript/interpretercontext.cpp | 2 +- apps/openmw/mwscript/locals.cpp | 4 +- apps/openmw/mwscript/miscextensions.cpp | 2 +- apps/openmw/mwscript/statsextensions.cpp | 9 +-- .../mwscript/transformationextensions.cpp | 4 +- apps/openmw/mwsound/loudness.cpp | 2 +- apps/openmw/mwsound/openal_output.cpp | 8 +- apps/openmw/mwsound/sound.cpp | 2 +- apps/openmw/mwsound/soundmanagerimp.cpp | 4 +- apps/openmw/mwworld/containerstore.cpp | 2 +- apps/openmw/mwworld/esmstore.cpp | 2 +- apps/openmw/mwworld/player.cpp | 8 +- apps/openmw/mwworld/projectilemanager.cpp | 2 +- apps/openmw/mwworld/timestamp.cpp | 2 +- apps/openmw/mwworld/weather.cpp | 16 ++-- apps/openmw/mwworld/worldimp.cpp | 64 ++++++--------- apps/openmw/mwworld/worldimp.hpp | 3 - components/esm/loadpgrd.cpp | 14 ++-- components/esm/loadrace.cpp | 2 +- components/esm/statstate.hpp | 2 +- components/esm/variantimp.cpp | 6 +- components/esmterrain/storage.cpp | 42 +++++----- components/fontloader/fontloader.cpp | 8 +- components/terrain/defaultworld.cpp | 10 +-- components/terrain/defaultworld.hpp | 2 +- components/terrain/material.cpp | 2 +- components/terrain/quadtreenode.cpp | 2 +- components/terrain/quadtreenode.hpp | 2 +- components/terrain/terraingrid.cpp | 14 ++-- components/widgets/list.cpp | 4 +- extern/sdl4ogre/sdlcursormanager.cpp | 5 +- extern/sdl4ogre/sdlwindowhelper.cpp | 3 +- libs/openengine/bullet/BtOgre.cpp | 10 +-- libs/openengine/bullet/physic.cpp | 6 +- libs/openengine/ogre/lights.cpp | 10 +-- libs/openengine/ogre/renderer.cpp | 2 +- libs/openengine/ogre/selectionbuffer.cpp | 4 +- 100 files changed, 457 insertions(+), 474 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 98e18521e..eef970d37 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -460,7 +460,7 @@ int clone(Arguments& info) for (Stats::iterator it = stats.begin(); it != stats.end(); ++it) { name.val = it->first; - float amount = it->second; + int amount = it->second; std::cout << std::setw(digitCount) << amount << " " << name.toString() << " "; if (++i % 3 == 0) diff --git a/apps/essimporter/convertacdt.cpp b/apps/essimporter/convertacdt.cpp index 91dd8ef23..55a20ec3d 100644 --- a/apps/essimporter/convertacdt.cpp +++ b/apps/essimporter/convertacdt.cpp @@ -23,9 +23,9 @@ namespace ESSImport } for (int i=0; i<8; ++i) { - cStats.mAttributes[i].mBase = acdt.mAttributes[i][1]; - cStats.mAttributes[i].mMod = acdt.mAttributes[i][0]; - cStats.mAttributes[i].mCurrent = acdt.mAttributes[i][0]; + cStats.mAttributes[i].mBase = static_cast(acdt.mAttributes[i][1]); + cStats.mAttributes[i].mMod = static_cast(acdt.mAttributes[i][0]); + cStats.mAttributes[i].mCurrent = static_cast(acdt.mAttributes[i][0]); } cStats.mGoldPool = acdt.mGoldPool; cStats.mTalkedTo = (acdt.mFlags & TalkedToPlayer) != 0; diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index c23083f8e..5711e6754 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -553,7 +553,7 @@ public: ESM::WeatherState weather; weather.mCurrentWeather = toString(mGame.mGMDT.mCurrentWeather); weather.mNextWeather = toString(mGame.mGMDT.mNextWeather); - weather.mRemainingTransitionTime = mGame.mGMDT.mWeatherTransition/100.f*(0.015*24*3600); + weather.mRemainingTransitionTime = mGame.mGMDT.mWeatherTransition/100.f*(0.015f*24*3600); weather.mHour = mContext->mHour; weather.mWindSpeed = 0.f; weather.mTimePassed = 0.0; diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 96cebd024..76b573941 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -191,7 +191,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) , mExportFonts(false) , mNewGame (false) { - std::srand ( std::time(NULL) ); + std::srand ( static_cast(std::time(NULL)) ); MWClass::registerClasses(); Uint32 flags = SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE|SDL_INIT_GAMECONTROLLER|SDL_INIT_JOYSTICK; diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 0f99d91da..686f5af61 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -154,9 +154,9 @@ namespace MWClass const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); - float iWeight = gmst.find (typeGmst)->getInt(); + float iWeight = floor(gmst.find(typeGmst)->getFloat()); - float epsilon = 5e-4; + float epsilon = 0.0005f; if (ref->mBase->mData.mWeight == 0) return ESM::Skill::Unarmored; @@ -262,7 +262,7 @@ namespace MWClass info.enchant = ref->mBase->mEnchant; if (!info.enchant.empty()) - info.remainingEnchantCharge = ptr.getCellRef().getEnchantmentCharge(); + info.remainingEnchantCharge = static_cast(ptr.getCellRef().getEnchantmentCharge()); info.text = text; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 0fa686dda..b387a3e9f 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -203,7 +203,7 @@ namespace MWClass info.enchant = ref->mBase->mEnchant; if (!info.enchant.empty()) - info.remainingEnchantCharge = ptr.getCellRef().getEnchantmentCharge(); + info.remainingEnchantCharge = static_cast(ptr.getCellRef().getEnchantmentCharge()); info.text = text; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index c59f8428c..ace4949ed 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -103,9 +103,9 @@ namespace MWClass data->mCreatureStats.setAttribute(ESM::Attribute::Endurance, ref->mBase->mData.mEndurance); data->mCreatureStats.setAttribute(ESM::Attribute::Personality, ref->mBase->mData.mPersonality); data->mCreatureStats.setAttribute(ESM::Attribute::Luck, ref->mBase->mData.mLuck); - data->mCreatureStats.setHealth (ref->mBase->mData.mHealth); - data->mCreatureStats.setMagicka (ref->mBase->mData.mMana); - data->mCreatureStats.setFatigue (ref->mBase->mData.mFatigue); + data->mCreatureStats.setHealth(static_cast(ref->mBase->mData.mHealth)); + data->mCreatureStats.setMagicka(static_cast(ref->mBase->mData.mMana)); + data->mCreatureStats.setFatigue(static_cast(ref->mBase->mData.mFatigue)); data->mCreatureStats.setLevel(ref->mBase->mData.mLevel); @@ -289,7 +289,7 @@ namespace MWClass { damage = attack[0] + ((attack[1]-attack[0])*stats.getAttackStrength()); damage *= gmst.find("fDamageStrengthBase")->getFloat() + - (stats.getAttribute(ESM::Attribute::Strength).getModified() * gmst.find("fDamageStrengthMult")->getFloat() * 0.1); + (stats.getAttribute(ESM::Attribute::Strength).getModified() * gmst.find("fDamageStrengthMult")->getFloat() * 0.1f); MWMechanics::adjustWeaponDamage(damage, weapon); MWMechanics::reduceWeaponCondition(damage, true, weapon, ptr); } @@ -376,8 +376,8 @@ namespace MWClass // Check for knockdown float agilityTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * getGmst().fKnockDownMult->getFloat(); float knockdownTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() - * getGmst().iKnockDownOddsMult->getInt() * 0.01 + getGmst().iKnockDownOddsBase->getInt(); - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + * getGmst().iKnockDownOddsMult->getInt() * 0.01f + getGmst().iKnockDownOddsBase->getInt(); + int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] if (ishealth && agilityTerm <= damage && knockdownTerm <= roll) { getCreatureStats(ptr).setKnockedDown(true); @@ -528,7 +528,7 @@ namespace MWClass MWMechanics::CreatureStats& stats = getCreatureStats(ptr); const GMST& gmst = getGmst(); - float walkSpeed = gmst.fMinWalkSpeedCreature->getFloat() + 0.01 * stats.getAttribute(ESM::Attribute::Speed).getModified() + float walkSpeed = gmst.fMinWalkSpeedCreature->getFloat() + 0.01f * stats.getAttribute(ESM::Attribute::Speed).getModified() * (gmst.fMaxWalkSpeedCreature->getFloat() - gmst.fMinWalkSpeedCreature->getFloat()); const MWBase::World *world = MWBase::Environment::get().getWorld(); @@ -626,7 +626,7 @@ namespace MWClass float Creature::getCapacity (const MWWorld::Ptr& ptr) const { const MWMechanics::CreatureStats& stats = getCreatureStats (ptr); - return stats.getAttribute(0).getModified()*5; + return static_cast(stats.getAttribute(0).getModified() * 5); } float Creature::getEncumbrance (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 10b9b437d..6e1d5334d 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -167,19 +167,19 @@ namespace MWClass if (opening) { MWBase::Environment::get().getSoundManager()->fadeOutSound3D(ptr, - closeSound, 0.5); - float offset = ptr.getRefData().getLocalRotation().rot[2]/ 3.14159265 * 2.0; + closeSound, 0.5f); + float offset = ptr.getRefData().getLocalRotation().rot[2]/ 3.14159265f * 2.0f; action->setSoundOffset(offset); action->setSound(openSound); } else { MWBase::Environment::get().getSoundManager()->fadeOutSound3D(ptr, - openSound, 0.5); - float offset = 1.0 - ptr.getRefData().getLocalRotation().rot[2]/ 3.14159265 * 2.0; + openSound, 0.5f); + float offset = 1.0 - ptr.getRefData().getLocalRotation().rot[2]/ 3.14159265f * 2.0f; //most if not all door have closing bang somewhere in the middle of the sound, //so we divide offset by two - action->setSoundOffset(offset * 0.5); + action->setSoundOffset(offset * 0.5f); action->setSound(closeSound); } diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 032c40237..90c708f97 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -205,7 +205,7 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); if (ptr.getCellRef().getCharge() == -1) - return ref->mBase->mData.mTime; + return static_cast(ref->mBase->mData.mTime); else return ptr.getCellRef().getChargeFloat(); } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index d06d7cfe1..c62257572 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -66,12 +66,12 @@ namespace double i = floor(d); d -= i; if(d < 0.5) - return i; + return static_cast(i); if(d > 0.5) - return i + 1.0; + return static_cast(i) + 1; if(is_even(i)) - return i; - return i + 1.0; + return static_cast(i); + return static_cast(i) + 1; } void autoCalculateAttributes (const ESM::NPC* npc, MWMechanics::CreatureStats& creatureStats) @@ -116,7 +116,7 @@ namespace continue; // is this a minor or major skill? - float add=0.2; + float add=0.2f; for (int k=0; k<5; ++k) { if (class_->mData.mSkills[k][0] == j) @@ -149,7 +149,7 @@ namespace || class_->mData.mAttribute[1] == ESM::Attribute::Endurance) multiplier += 1; - creatureStats.setHealth(static_cast (0.5 * (strength + endurance)) + multiplier * (creatureStats.getLevel() - 1)); + creatureStats.setHealth(floor(0.5f * (strength + endurance)) + multiplier * (creatureStats.getLevel() - 1)); } /** @@ -539,7 +539,7 @@ namespace MWClass { damage = attack[0] + ((attack[1]-attack[0])*stats.getAttackStrength()); damage *= gmst.fDamageStrengthBase->getFloat() + - (stats.getAttribute(ESM::Attribute::Strength).getModified() * gmst.fDamageStrengthMult->getFloat() * 0.1); + (stats.getAttribute(ESM::Attribute::Strength).getModified() * gmst.fDamageStrengthMult->getFloat() * 0.1f); } MWMechanics::adjustWeaponDamage(damage, weapon); MWMechanics::reduceWeaponCondition(damage, true, weapon, ptr); @@ -648,7 +648,7 @@ namespace MWClass const GMST& gmst = getGmst(); int chance = store.get().find("iVoiceHitOdds")->getInt(); - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] if (roll < chance) { MWBase::Environment::get().getDialogueManager()->say(ptr, "hit"); @@ -657,8 +657,8 @@ namespace MWClass // Check for knockdown float agilityTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * gmst.fKnockDownMult->getFloat(); float knockdownTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() - * gmst.iKnockDownOddsMult->getInt() * 0.01 + gmst.iKnockDownOddsBase->getInt(); - roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + * gmst.iKnockDownOddsMult->getInt() * 0.01f + gmst.iKnockDownOddsBase->getInt(); + roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] if (ishealth && agilityTerm <= damage && knockdownTerm <= roll) { getCreatureStats(ptr).setKnockedDown(true); @@ -690,7 +690,7 @@ namespace MWClass float unmitigatedDamage = damage; float x = damage / (damage + getArmorRating(ptr)); damage *= std::max(gmst.fCombatArmorMinMult->getFloat(), x); - int damageDiff = unmitigatedDamage - damage; + int damageDiff = static_cast(unmitigatedDamage - damage); if (damage < 1) damage = 1; @@ -938,7 +938,7 @@ namespace MWClass gmst.fJumpEncumbranceMultiplier->getFloat() * (1.0f - Npc::getEncumbrance(ptr)/Npc::getCapacity(ptr)); - float a = npcdata->mNpcStats.getSkill(ESM::Skill::Acrobatics).getModified(); + float a = static_cast(npcdata->mNpcStats.getSkill(ESM::Skill::Acrobatics).getModified()); float b = 0.0f; if(a > 50.0f) { @@ -1097,7 +1097,7 @@ namespace MWClass if (it == invStore.end() || it->getTypeName() != typeid(ESM::Armor).name()) { // unarmored - ratings[i] = (fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill); + ratings[i] = static_cast((fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill)); } else { diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index d1a44fd0e..a484ad668 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -345,7 +345,7 @@ namespace MWClass info.enchant = ref->mBase->mEnchant; if (!info.enchant.empty()) - info.remainingEnchantCharge = ptr.getCellRef().getEnchantmentCharge(); + info.remainingEnchantCharge = static_cast(ptr.getCellRef().getEnchantmentCharge()); if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { text += MWGui::ToolTips::getCellRefString(ptr.getCellRef()); diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 1d1f655aa..e8dcf535c 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -444,7 +444,7 @@ namespace MWDialogue if (mActor.getClass().isNpc()) { MWMechanics::NpcStats& npcStats = mActor.getClass().getNpcStats(mActor); - npcStats.setBaseDisposition(npcStats.getBaseDisposition() + mPermanentDispositionChange); + npcStats.setBaseDisposition(static_cast(npcStats.getBaseDisposition() + mPermanentDispositionChange)); } mPermanentDispositionChange = 0; mTemporaryDispositionChange = 0; @@ -521,7 +521,7 @@ namespace MWDialogue mPermanentDispositionChange += perm; // change temp disposition so that final disposition is between 0...100 - int curDisp = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor); + float curDisp = static_cast(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor)); if (curDisp + mTemporaryDispositionChange < 0) mTemporaryDispositionChange = -curDisp; else if (curDisp + mTemporaryDispositionChange > 100) @@ -564,7 +564,7 @@ namespace MWDialogue int DialogueManager::getTemporaryDispositionChange() const { - return mTemporaryDispositionChange; + return static_cast(mTemporaryDispositionChange); } void DialogueManager::applyDispositionChange(int delta) diff --git a/apps/openmw/mwgui/backgroundimage.cpp b/apps/openmw/mwgui/backgroundimage.cpp index 9c07c5780..ee966c189 100644 --- a/apps/openmw/mwgui/backgroundimage.cpp +++ b/apps/openmw/mwgui/backgroundimage.cpp @@ -41,8 +41,8 @@ void BackgroundImage::adjustSize() MyGUI::IntSize screenSize = getSize(); - int leftPadding = std::max(0.0, (screenSize.width - screenSize.height * mAspect) / 2); - int topPadding = std::max(0.0, (screenSize.height - screenSize.width / mAspect) / 2); + int leftPadding = std::max(0, static_cast(screenSize.width - screenSize.height * mAspect) / 2); + int topPadding = std::max(0, static_cast(screenSize.height - screenSize.width / mAspect) / 2); mChild->setCoord(leftPadding, topPadding, screenSize.width - leftPadding*2, screenSize.height - topPadding*2); } diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index 57e171659..9d2f52bfd 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -326,7 +326,7 @@ struct TypesetBookImpl::Typesetter : BookTypesetter mLine = NULL; } - void sectionBreak (float margin) + void sectionBreak (int margin) { add_partial_text(); @@ -465,7 +465,7 @@ struct TypesetBookImpl::Typesetter : BookTypesetter { MyGUI::GlyphInfo* gi = style->mFont->getGlyphInfo (stream.peek ()); if (gi) - space_width += gi->advance + gi->bearingX; + space_width += static_cast(gi->advance + gi->bearingX); stream.consume (); } @@ -475,7 +475,7 @@ struct TypesetBookImpl::Typesetter : BookTypesetter { MyGUI::GlyphInfo* gi = style->mFont->getGlyphInfo (stream.peek ()); if (gi) - word_width += gi->advance + gi->bearingX; + word_width += static_cast(gi->advance + gi->bearingX); stream.consume (); } @@ -623,15 +623,15 @@ namespace RenderXform (MyGUI::ICroppedRectangle* croppedParent, MyGUI::RenderTargetInfo const & renderTargetInfo) { - clipTop = croppedParent->_getMarginTop (); - clipLeft = croppedParent->_getMarginLeft (); - clipRight = croppedParent->getWidth () - croppedParent->_getMarginRight (); - clipBottom = croppedParent->getHeight () - croppedParent->_getMarginBottom (); + clipTop = static_cast(croppedParent->_getMarginTop()); + clipLeft = static_cast(croppedParent->_getMarginLeft ()); + clipRight = static_cast(croppedParent->getWidth () - croppedParent->_getMarginRight ()); + clipBottom = static_cast(croppedParent->getHeight() - croppedParent->_getMarginBottom()); - absoluteLeft = croppedParent->getAbsoluteLeft(); - absoluteTop = croppedParent->getAbsoluteTop(); - leftOffset = renderTargetInfo.leftOffset; - topOffset = renderTargetInfo.topOffset; + absoluteLeft = static_cast(croppedParent->getAbsoluteLeft()); + absoluteTop = static_cast(croppedParent->getAbsoluteTop()); + leftOffset = static_cast(renderTargetInfo.leftOffset); + topOffset = static_cast(renderTargetInfo.topOffset); pixScaleX = renderTargetInfo.pixScaleX; pixScaleY = renderTargetInfo.pixScaleY; @@ -1136,7 +1136,7 @@ public: MyGUI::Colour colour = isActive ? (this_->mItemActive ? run.mStyle->mActiveColour: run.mStyle->mHotColour) : run.mStyle->mNormalColour; - glyphStream.reset (section.mRect.left + line.mRect.left + run.mLeft, line.mRect.top, colour); + glyphStream.reset(static_cast(section.mRect.left + line.mRect.left + run.mLeft), static_cast(line.mRect.top), colour); Utf8Stream stream (run.mRange); @@ -1164,7 +1164,7 @@ public: RenderXform renderXform (mCroppedParent, textFormat.mRenderItem->getRenderTarget()->getInfo()); - GlyphStream glyphStream (textFormat.mFont, mCoord.left, mCoord.top-mViewTop, + GlyphStream glyphStream(textFormat.mFont, static_cast(mCoord.left), static_cast(mCoord.top - mViewTop), -1 /*mNode->getNodeDepth()*/, vertices, renderXform); int visit_top = (std::max) (mViewTop, mViewTop + int (renderXform.clipTop )); diff --git a/apps/openmw/mwgui/bookpage.hpp b/apps/openmw/mwgui/bookpage.hpp index 458cf2a19..c7340ec7c 100644 --- a/apps/openmw/mwgui/bookpage.hpp +++ b/apps/openmw/mwgui/bookpage.hpp @@ -71,7 +71,7 @@ namespace MWGui /// to begin when additional text is inserted. Pagination attempts to keep /// sections together on a single page. The margin parameter adds additional space /// before the next line of text. - virtual void sectionBreak (float margin = 0) = 0; + virtual void sectionBreak (int margin = 0) = 0; /// Changes the alignment for the current section of text. virtual void setSectionAlignment (Alignment sectionAlignment) = 0; diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index 8f709ec8d..fe47437ca 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -129,7 +129,7 @@ void CompanionWindow::updateEncumbranceBar() return; float capacity = mPtr.getClass().getCapacity(mPtr); float encumbrance = mPtr.getClass().getEncumbrance(mPtr); - mEncumbranceBar->setValue(encumbrance, capacity); + mEncumbranceBar->setValue(static_cast(encumbrance), static_cast(capacity)); if (mModel && mModel->hasProfit(mPtr)) { diff --git a/apps/openmw/mwgui/controllers.cpp b/apps/openmw/mwgui/controllers.cpp index ad804997a..72f2eb7f3 100644 --- a/apps/openmw/mwgui/controllers.cpp +++ b/apps/openmw/mwgui/controllers.cpp @@ -9,8 +9,8 @@ namespace MWGui { ControllerRepeatEvent::ControllerRepeatEvent() : - mInit(0.5), - mStep(0.1), + mInit(0.5f), + mStep(0.1f), mEnabled(true), mTimeLeft(0) { diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index eee86c6d2..3bc4292e3 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -549,7 +549,7 @@ namespace MWGui size_t range = book->getSize().second - viewHeight; mScrollBar->setScrollRange(range); mScrollBar->setScrollPosition(range-1); - mScrollBar->setTrackSize(viewHeight / static_cast(book->getSize().second) * mScrollBar->getLineSize()); + mScrollBar->setTrackSize(static_cast(viewHeight / static_cast(book->getSize().second) * mScrollBar->getLineSize())); onScrollbarMoved(mScrollBar, range-1); } else @@ -637,14 +637,14 @@ namespace MWGui if (dispositionVisible && !dispositionWasVisible) { mDispositionBar->setVisible(true); - float offset = mDispositionBar->getHeight()+5; + int offset = mDispositionBar->getHeight()+5; mTopicsList->setCoord(mTopicsList->getCoord() + MyGUI::IntCoord(0,offset,0,-offset)); mTopicsList->adjustSize(); } else if (!dispositionVisible && dispositionWasVisible) { mDispositionBar->setVisible(false); - float offset = mDispositionBar->getHeight()+5; + int offset = mDispositionBar->getHeight()+5; mTopicsList->setCoord(mTopicsList->getCoord() - MyGUI::IntCoord(0,offset,0,-offset)); mTopicsList->adjustSize(); } diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index a4e67e9b1..97a113527 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -262,7 +262,7 @@ namespace MWGui void HUD::setDrowningTimeLeft(float time, float maxTime) { - size_t progress = time/maxTime*200.0; + size_t progress = static_cast(time / maxTime * 200); mDrowning->setProgressPosition(progress); bool isDrowning = (progress == 0); @@ -631,7 +631,7 @@ namespace MWGui mEnemyHealth->setProgressRange(100); // Health is usually cast to int before displaying. Actors die whenever they are < 1 health. // Therefore any value < 1 should show as an empty health bar. We do the same in statswindow :) - mEnemyHealth->setProgressPosition(int(stats.getHealth().getCurrent()) / stats.getHealth().getModified() * 100); + mEnemyHealth->setProgressPosition(static_cast(stats.getHealth().getCurrent() / stats.getHealth().getModified() * 100)); static const float fNPCHealthBarFade = MWBase::Environment::get().getWorld()->getStore().get().find("fNPCHealthBarFade")->getFloat(); if (fNPCHealthBarFade > 0.f) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index b0adddffa..a6722319d 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -101,7 +101,7 @@ namespace MWGui void InventoryWindow::adjustPanes() { const float aspect = 0.5; // fixed aspect ratio for the avatar image - float leftPaneWidth = (mMainWidget->getSize().height-44-mArmorRating->getHeight()) * aspect; + int leftPaneWidth = static_cast(mMainWidget->getSize().height - 44 - mArmorRating->getHeight()) * aspect); mLeftPane->setSize( leftPaneWidth, mMainWidget->getSize().height-44 ); mRightPane->setCoord( mLeftPane->getPosition().left + leftPaneWidth + 4, mRightPane->getPosition().top, @@ -153,10 +153,10 @@ namespace MWGui } MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); - MyGUI::IntPoint pos (Settings::Manager::getFloat(setting + " x", "Windows") * viewSize.width, - Settings::Manager::getFloat(setting + " y", "Windows") * viewSize.height); - MyGUI::IntSize size (Settings::Manager::getFloat(setting + " w", "Windows") * viewSize.width, - Settings::Manager::getFloat(setting + " h", "Windows") * viewSize.height); + MyGUI::IntPoint pos(static_cast(Settings::Manager::getFloat(setting + " x", "Windows") * viewSize.width), + static_cast(Settings::Manager::getFloat(setting + " y", "Windows") * viewSize.height)); + MyGUI::IntSize size(static_cast(Settings::Manager::getFloat(setting + " w", "Windows") * viewSize.width), + static_cast(Settings::Manager::getFloat(setting + " h", "Windows") * viewSize.height)); if (size.width != mMainWidget->getWidth() || size.height != mMainWidget->getHeight()) mPreviewResize = true; @@ -519,7 +519,7 @@ namespace MWGui float capacity = player.getClass().getCapacity(player); float encumbrance = player.getClass().getEncumbrance(player); mTradeModel->adjustEncumbrance(encumbrance); - mEncumbranceBar->setValue(encumbrance, capacity); + mEncumbranceBar->setValue(static_cast(encumbrance), static_cast(capacity)); } void InventoryWindow::onFrame() diff --git a/apps/openmw/mwgui/itemview.cpp b/apps/openmw/mwgui/itemview.cpp index e30f6e7a8..aade232d2 100644 --- a/apps/openmw/mwgui/itemview.cpp +++ b/apps/openmw/mwgui/itemview.cpp @@ -141,10 +141,10 @@ void ItemView::onSelectedBackground(MyGUI::Widget *sender) void ItemView::onMouseWheel(MyGUI::Widget *_sender, int _rel) { - if (mScrollView->getViewOffset().left + _rel*0.3 > 0) + if (mScrollView->getViewOffset().left + _rel*0.3f > 0) mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); else - mScrollView->setViewOffset(MyGUI::IntPoint(mScrollView->getViewOffset().left + _rel*0.3, 0)); + mScrollView->setViewOffset(MyGUI::IntPoint(static_cast(mScrollView->getViewOffset().left + _rel*0.3f), 0)); } void ItemView::setSize(const MyGUI::IntSize &_value) diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index 58873c566..728c46023 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -17,7 +17,7 @@ namespace MWGui { JailScreen::JailScreen() : WindowBase("openmw_jail_screen.layout"), - mTimeAdvancer(0.01), + mTimeAdvancer(0.01f), mDays(1), mFadeTimeRemaining(0) { @@ -66,7 +66,7 @@ namespace MWGui void JailScreen::onJailProgressChanged(int cur, int /*total*/) { mProgressBar->setScrollPosition(0); - mProgressBar->setTrackSize(cur / (float)(mProgressBar->getScrollRange()) * mProgressBar->getLineSize()); + mProgressBar->setTrackSize(static_cast(cur / (float)(mProgressBar->getScrollRange()) * mProgressBar->getLineSize())); } void JailScreen::onJailFinished() @@ -83,7 +83,7 @@ namespace MWGui std::set skills; for (int day=0; day (RAND_MAX) + 1) * ESM::Skill::Length; + int skill = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * ESM::Skill::Length); skills.insert(skill); MWMechanics::SkillValue& value = player.getClass().getNpcStats(player).getSkill(skill); diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 9e3343c78..f920acf1a 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -33,8 +33,8 @@ namespace MWGui : mSceneMgr(sceneMgr) , mWindow(rw) , WindowBase("openmw_loading_screen.layout") - , mLastRenderTime(0.f) - , mLastWallpaperChangeTime(0.f) + , mLastRenderTime(0) + , mLastWallpaperChangeTime(0) , mProgress(0) , mVSyncWasEnabled(false) { @@ -173,7 +173,7 @@ namespace MWGui return; mProgress = value; mProgressBar->setScrollPosition(0); - mProgressBar->setTrackSize(value / (float)(mProgressBar->getScrollRange()) * mProgressBar->getLineSize()); + mProgressBar->setTrackSize(static_cast(value / (float)(mProgressBar->getScrollRange()) * mProgressBar->getLineSize())); draw(); } @@ -182,7 +182,7 @@ namespace MWGui mProgressBar->setScrollPosition(0); size_t value = mProgress + increase; mProgress = value; - mProgressBar->setTrackSize(value / (float)(mProgressBar->getScrollRange()) * mProgressBar->getLineSize()); + mProgressBar->setTrackSize(static_cast(value / (float)(mProgressBar->getScrollRange()) * mProgressBar->getLineSize())); draw(); } @@ -193,7 +193,7 @@ namespace MWGui time = (time-2)*-1; mProgressBar->setTrackSize(50); - mProgressBar->setScrollPosition(time * (mProgressBar->getScrollRange()-1)); + mProgressBar->setScrollPosition(static_cast(time * (mProgressBar->getScrollRange() - 1))); draw(); } diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 13e2e3904..271e43d29 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -244,14 +244,14 @@ namespace MWGui // Image space is -Y up, cells are Y up nY = 1 - (worldY - cellSize * cellY) / cellSize; - float cellDx = cellX - mCurX; - float cellDy = cellY - mCurY; + float cellDx = static_cast(cellX - mCurX); + float cellDy = static_cast(cellY - mCurY); markerPos.cellX = cellX; markerPos.cellY = cellY; - widgetPos = MyGUI::IntPoint(nX * mMapWidgetSize + (1+cellDx) * mMapWidgetSize, - nY * mMapWidgetSize - (cellDy-1) * mMapWidgetSize); + widgetPos = MyGUI::IntPoint(static_cast(nX * mMapWidgetSize + (1 + cellDx) * mMapWidgetSize), + static_cast(nY * mMapWidgetSize - (cellDy-1) * mMapWidgetSize)); } else { @@ -263,8 +263,8 @@ namespace MWGui markerPos.cellY = cellY; // Image space is -Y up, cells are Y up - widgetPos = MyGUI::IntPoint(nX * mMapWidgetSize + (1+(cellX-mCurX)) * mMapWidgetSize, - nY * mMapWidgetSize + (1-(cellY-mCurY)) * mMapWidgetSize); + widgetPos = MyGUI::IntPoint(static_cast(nX * mMapWidgetSize + (1 + (cellX - mCurX)) * mMapWidgetSize), + static_cast(nY * mMapWidgetSize + (1-(cellY-mCurY)) * mMapWidgetSize)); } markerPos.nX = nX; @@ -309,8 +309,8 @@ namespace MWGui markerWidget->setUserString("ToolTipType", "Layout"); markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); markerWidget->setUserString("Caption_TextOneLine", MyGUI::TextIterator::toTagsString(marker.mNote)); - markerWidget->setNormalColour(MyGUI::Colour(1.0,0.3,0.3)); - markerWidget->setHoverColour(MyGUI::Colour(1.0,0.5,0.5)); + markerWidget->setNormalColour(MyGUI::Colour(1.0f, 0.3f, 0.3f)); + markerWidget->setHoverColour(MyGUI::Colour(1.0f, 0.5f, 0.5f)); markerWidget->setUserData(marker); markerWidget->setNeedMouseFocus(true); customMarkerCreated(markerWidget); @@ -424,7 +424,7 @@ namespace MWGui void LocalMapBase::setPlayerPos(int cellX, int cellY, const float nx, const float ny) { - MyGUI::IntPoint pos(mMapWidgetSize+nx*mMapWidgetSize-16, mMapWidgetSize+ny*mMapWidgetSize-16); + MyGUI::IntPoint pos(static_cast(mMapWidgetSize + nx*mMapWidgetSize - 16), static_cast(mMapWidgetSize + ny*mMapWidgetSize - 16)); pos.left += (cellX - mCurX) * mMapWidgetSize; pos.top -= (cellY - mCurY) * mMapWidgetSize; @@ -435,7 +435,7 @@ namespace MWGui mCompass->setPosition(pos); MyGUI::IntPoint middle (pos.left+16, pos.top+16); MyGUI::IntCoord viewsize = mLocalMap->getCoord(); - MyGUI::IntPoint viewOffset(0.5*viewsize.width - middle.left, 0.5*viewsize.height - middle.top); + MyGUI::IntPoint viewOffset((viewsize.width / 2) - middle.left, (viewsize.height / 2) - middle.top); mLocalMap->setViewOffset(viewOffset); } } @@ -668,7 +668,7 @@ namespace MWGui else { worldPos.x = (x + nX) * cellSize; - worldPos.y = (y + (1.0-nY)) * cellSize; + worldPos.y = (y + (1.0f-nY)) * cellSize; } mEditingMarker.mWorldX = worldPos.x; @@ -737,8 +737,8 @@ namespace MWGui int markerSize = 12; int offset = mGlobalMapRender->getCellSize()/2 - markerSize/2; MyGUI::IntCoord widgetCoord( - worldX * mGlobalMapRender->getWidth()+offset, - worldY * mGlobalMapRender->getHeight()+offset, + static_cast(worldX * mGlobalMapRender->getWidth()+offset), + static_cast(worldY * mGlobalMapRender->getHeight() + offset), markerSize, markerSize); MyGUI::Widget* markerWidget = mGlobalMap->createWidget("MarkerButton", @@ -833,11 +833,11 @@ namespace MWGui worldX *= mGlobalMapRender->getWidth(); worldY *= mGlobalMapRender->getHeight(); - mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(worldX - 16, worldY - 16)); + mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(static_cast(worldX - 16), static_cast(worldY - 16))); // set the view offset so that player is in the center MyGUI::IntSize viewsize = mGlobalMap->getSize(); - MyGUI::IntPoint viewoffs(0.5*viewsize.width - worldX, 0.5*viewsize.height - worldY); + MyGUI::IntPoint viewoffs((viewsize.width / 2) - worldX, (viewsize.height / 2) - worldY); mGlobalMap->setViewOffset(viewoffs); } } @@ -854,11 +854,11 @@ namespace MWGui x *= mGlobalMapRender->getWidth(); y *= mGlobalMapRender->getHeight(); - mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(x - 16, y - 16)); + mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(static_cast(x - 16), static_cast(y - 16))); // set the view offset so that player is in the center MyGUI::IntSize viewsize = mGlobalMap->getSize(); - MyGUI::IntPoint viewoffs(0.5*viewsize.width - x, 0.5*viewsize.height - y); + MyGUI::IntPoint viewoffs((viewsize.width / 2) - x, (viewsize.height / 2) - y); mGlobalMap->setViewOffset(viewoffs); } diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 907c664b1..4407bf927 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -59,11 +59,11 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor) float fRepairMult = MWBase::Environment::get().getWorld()->getStore().get() .find("fRepairMult")->getFloat(); - float p = std::max(1, basePrice); - float r = std::max(1, static_cast(maxDurability / p)); + float p = static_cast(std::max(1, basePrice)); + float r = static_cast(std::max(1, static_cast(maxDurability / p))); - int x = ((maxDurability - durability) / r); - x = (fRepairMult * x); + int x = static_cast((maxDurability - durability) / r); + x = static_cast(fRepairMult * x); int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mActor, x, true); @@ -105,10 +105,10 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor) void MerchantRepair::onMouseWheel(MyGUI::Widget* _sender, int _rel) { - if (mList->getViewOffset().top + _rel*0.3 > 0) + if (mList->getViewOffset().top + _rel*0.3f > 0) mList->setViewOffset(MyGUI::IntPoint(0, 0)); else - mList->setViewOffset(MyGUI::IntPoint(0, mList->getViewOffset().top + _rel*0.3)); + mList->setViewOffset(MyGUI::IntPoint(0, static_cast(mList->getViewOffset().top + _rel*0.3f))); } void MerchantRepair::open() diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index cdbcf784d..b7c67e68b 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -70,7 +70,7 @@ namespace MWGui it = mMessageBoxes.begin(); while(it != mMessageBoxes.end()) { - (*it)->update(height); + (*it)->update(static_cast(height)); height += (*it)->getHeight(); ++it; } diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index b03bf758a..97dbfbafc 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -203,7 +203,7 @@ namespace MWGui void RaceDialog::onHeadRotate(MyGUI::ScrollBar* scroll, size_t _position) { - float angle = (float(_position) / (scroll->getScrollRange()-1) - 0.5) * 3.14 * 2; + float angle = (float(_position) / (scroll->getScrollRange()-1) - 0.5f) * 3.14f * 2; mPreview->update (angle); mPreviewDirty = true; mCurrentAngle = angle; @@ -404,7 +404,7 @@ namespace MWGui skillWidget = mSkillList->createWidget("MW_StatNameValue", coord1, MyGUI::Align::Default, std::string("Skill") + MyGUI::utility::toString(i)); skillWidget->setSkillNumber(skillId); - skillWidget->setSkillValue(Widgets::MWSkill::SkillValue(race->mData.mBonus[i].mBonus)); + skillWidget->setSkillValue(Widgets::MWSkill::SkillValue(static_cast(race->mData.mBonus[i].mBonus))); ToolTips::createSkillToolTip(skillWidget, skillId); diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 2c854a8f5..1af31373c 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -119,7 +119,7 @@ void Recharge::updateView() Widgets::MWDynamicStatPtr chargeWidget = mView->createWidget ("MW_ChargeBar", MyGUI::IntCoord(72, currentY+2, 199, 20), MyGUI::Align::Default); - chargeWidget->setValue(iter->getCellRef().getEnchantmentCharge(), enchantment->mData.mCharge); + chargeWidget->setValue(static_cast(iter->getCellRef().getEnchantmentCharge()), enchantment->mData.mCharge); chargeWidget->setNeedMouseFocus(false); currentY += 32 + 4; @@ -149,11 +149,11 @@ void Recharge::onItemClicked(MyGUI::Widget *sender) MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); MWMechanics::NpcStats& npcStats = player.getClass().getNpcStats(player); - float luckTerm = 0.1 * stats.getAttribute(ESM::Attribute::Luck).getModified(); + float luckTerm = 0.1f * stats.getAttribute(ESM::Attribute::Luck).getModified(); if (luckTerm < 1|| luckTerm > 10) luckTerm = 1; - float intelligenceTerm = 0.2 * stats.getAttribute(ESM::Attribute::Intelligence).getModified(); + float intelligenceTerm = 0.2f * stats.getAttribute(ESM::Attribute::Intelligence).getModified(); if (intelligenceTerm > 20) intelligenceTerm = 20; @@ -161,7 +161,7 @@ void Recharge::onItemClicked(MyGUI::Widget *sender) intelligenceTerm = 1; float x = (npcStats.getSkill(ESM::Skill::Enchant).getModified() + intelligenceTerm + luckTerm) * stats.getFatigueTerm(); - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] if (roll < x) { std::string soul = gem.getCellRef().getSoul(); @@ -197,10 +197,10 @@ void Recharge::onItemClicked(MyGUI::Widget *sender) void Recharge::onMouseWheel(MyGUI::Widget* _sender, int _rel) { - if (mView->getViewOffset().top + _rel*0.3 > 0) + if (mView->getViewOffset().top + _rel*0.3f > 0) mView->setViewOffset(MyGUI::IntPoint(0, 0)); else - mView->setViewOffset(MyGUI::IntPoint(0, mView->getViewOffset().top + _rel*0.3)); + mView->setViewOffset(MyGUI::IntPoint(0, static_cast(mView->getViewOffset().top + _rel*0.3f))); } } diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 1bcd2d31a..47c7cef21 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -146,21 +146,21 @@ namespace MWGui void ReviewDialog::setHealth(const MWMechanics::DynamicStat& value) { - mHealth->setValue(value.getCurrent(), value.getModified()); + mHealth->setValue(static_cast(value.getCurrent()), static_cast(value.getModified())); std::string valStr = MyGUI::utility::toString(value.getCurrent()) + "/" + MyGUI::utility::toString(value.getModified()); mHealth->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); } void ReviewDialog::setMagicka(const MWMechanics::DynamicStat& value) { - mMagicka->setValue(value.getCurrent(), value.getModified()); + mMagicka->setValue(static_cast(value.getCurrent()), static_cast(value.getModified())); std::string valStr = MyGUI::utility::toString(value.getCurrent()) + "/" + MyGUI::utility::toString(value.getModified()); mMagicka->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); } void ReviewDialog::setFatigue(const MWMechanics::DynamicStat& value) { - mFatigue->setValue(value.getCurrent(), value.getModified()); + mFatigue->setValue(static_cast(value.getCurrent()), static_cast(value.getModified())); std::string valStr = MyGUI::utility::toString(value.getCurrent()) + "/" + MyGUI::utility::toString(value.getModified()); mFatigue->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); } @@ -180,7 +180,7 @@ namespace MWGui MyGUI::TextBox* widget = mSkillWidgetMap[skillId]; if (widget) { - float modified = value.getModified(), base = value.getBase(); + float modified = static_cast(value.getModified()), base = static_cast(value.getBase()); std::string text = MyGUI::utility::toString(std::floor(modified)); std::string state = "normal"; if (modified > base) @@ -376,7 +376,7 @@ namespace MWGui if (mSkillView->getViewOffset().top + _rel*0.3 > 0) mSkillView->setViewOffset(MyGUI::IntPoint(0, 0)); else - mSkillView->setViewOffset(MyGUI::IntPoint(0, mSkillView->getViewOffset().top + _rel*0.3)); + mSkillView->setViewOffset(MyGUI::IntPoint(0, static_cast(mSkillView->getViewOffset().top + _rel*0.3))); } } diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 301e9de7e..5bb82bc69 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -152,7 +152,7 @@ namespace MWGui } else { - int value = Settings::Manager::getFloat(getSettingName(current), getSettingCategory(current)); + int value = Settings::Manager::getInt(getSettingName(current), getSettingCategory(current)); scroll->setScrollPosition(value); } scroll->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); @@ -557,10 +557,10 @@ namespace MWGui void SettingsWindow::onInputTabMouseWheel(MyGUI::Widget* _sender, int _rel) { - if (mControlsBox->getViewOffset().top + _rel*0.3 > 0) + if (mControlsBox->getViewOffset().top + _rel*0.3f > 0) mControlsBox->setViewOffset(MyGUI::IntPoint(0, 0)); else - mControlsBox->setViewOffset(MyGUI::IntPoint(0, mControlsBox->getViewOffset().top + _rel*0.3)); + mControlsBox->setViewOffset(MyGUI::IntPoint(0, static_cast(mControlsBox->getViewOffset().top + _rel*0.3f))); } void SettingsWindow::onResetDefaultBindings(MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 54094b606..57b02940e 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -46,7 +46,7 @@ namespace MWGui MWBase::Environment::get().getWorld()->getStore(); const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(spellId); - int price = spell->mData.mCost*store.get().find("fSpellValueMult")->getFloat(); + int price = static_cast(spell->mData.mCost*store.get().find("fSpellValueMult")->getFloat()); price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); @@ -187,7 +187,7 @@ namespace MWGui if (mSpellsView->getViewOffset().top + _rel*0.3 > 0) mSpellsView->setViewOffset(MyGUI::IntPoint(0, 0)); else - mSpellsView->setViewOffset(MyGUI::IntPoint(0, mSpellsView->getViewOffset().top + _rel*0.3)); + mSpellsView->setViewOffset(MyGUI::IntPoint(0, static_cast(mSpellsView->getViewOffset().top + _rel*0.3f))); } } diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 2757b7cae..c744d3ed6 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -440,14 +440,14 @@ namespace MWGui for (std::vector::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it) { - float x = 0.5 * (it->mMagnMin + it->mMagnMax); + float x = 0.5f * (it->mMagnMin + it->mMagnMax); const ESM::MagicEffect* effect = store.get().find(it->mEffectID); - x *= 0.1 * effect->mData.mBaseCost; + x *= 0.1f * effect->mData.mBaseCost; x *= 1 + it->mDuration; - x += 0.05 * std::max(1, it->mArea) * effect->mData.mBaseCost; + x += 0.05f * std::max(1, it->mArea) * effect->mData.mBaseCost; float fEffectCostMult = store.get().find("fEffectCostMult")->getFloat(); @@ -471,7 +471,7 @@ namespace MWGui float fSpellMakingValueMult = store.get().find("fSpellMakingValueMult")->getFloat(); - int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,int(y) * fSpellMakingValueMult,true); + int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, static_cast(y * fSpellMakingValueMult),true); mPriceLabel->setCaption(MyGUI::utility::toString(int(price))); diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index 20c6f3ba8..c597cfaeb 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -30,7 +30,7 @@ namespace MWGui { MagicEffectInfo newEffectSource; newEffectSource.mKey = key; - newEffectSource.mMagnitude = magnitude; + newEffectSource.mMagnitude = static_cast(magnitude); newEffectSource.mPermanent = mIsPermanent; newEffectSource.mRemainingTime = remainingTime; newEffectSource.mSource = sourceName; diff --git a/apps/openmw/mwgui/spellmodel.cpp b/apps/openmw/mwgui/spellmodel.cpp index 4713720cd..91512a011 100644 --- a/apps/openmw/mwgui/spellmodel.cpp +++ b/apps/openmw/mwgui/spellmodel.cpp @@ -103,7 +103,7 @@ namespace MWGui && item.getClass().canBeEquipped(item, mActor).first == 0) continue; - int castCost = MWMechanics::getEffectiveEnchantmentCastCost(enchant->mData.mCost, mActor); + int castCost = MWMechanics::getEffectiveEnchantmentCastCost(static_cast(enchant->mData.mCost), mActor); std::string cost = boost::lexical_cast(castCost); int currentCharge = int(item.getCellRef().getEnchantmentCharge()); diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index 1c17a11f6..668b239bc 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -236,10 +236,10 @@ namespace MWGui void SpellView::onMouseWheel(MyGUI::Widget* _sender, int _rel) { - if (mScrollView->getViewOffset().top + _rel*0.3 > 0) + if (mScrollView->getViewOffset().top + _rel*0.3f > 0) mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); else - mScrollView->setViewOffset(MyGUI::IntPoint(0, mScrollView->getViewOffset().top + _rel*0.3)); + mScrollView->setViewOffset(MyGUI::IntPoint(0, static_cast(mScrollView->getViewOffset().top + _rel*0.3f))); } } diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index 2a22f4239..cb1bf6f37 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -80,13 +80,13 @@ namespace MWGui if (mSkillView->getViewOffset().top + _rel*0.3 > 0) mSkillView->setViewOffset(MyGUI::IntPoint(0, 0)); else - mSkillView->setViewOffset(MyGUI::IntPoint(0, mSkillView->getViewOffset().top + _rel*0.3)); + mSkillView->setViewOffset(MyGUI::IntPoint(0, static_cast(mSkillView->getViewOffset().top + _rel*0.3))); } void StatsWindow::onWindowResize(MyGUI::Window* window) { - mLeftPane->setCoord( MyGUI::IntCoord(0, 0, 0.44*window->getSize().width, window->getSize().height) ); - mRightPane->setCoord( MyGUI::IntCoord(0.44*window->getSize().width, 0, 0.56*window->getSize().width, window->getSize().height) ); + mLeftPane->setCoord( MyGUI::IntCoord(0, 0, static_cast(0.44*window->getSize().width), window->getSize().height) ); + mRightPane->setCoord( MyGUI::IntCoord(static_cast(0.44*window->getSize().width), 0, static_cast(0.56*window->getSize().width), window->getSize().height) ); // Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden mSkillView->setVisibleVScroll(false); mSkillView->setCanvasSize (mSkillView->getWidth(), mSkillView->getCanvasSize().height); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 2c10004a6..4e03b788a 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -308,7 +308,7 @@ namespace MWGui void ToolTips::position(MyGUI::IntPoint& position, MyGUI::IntSize size, MyGUI::IntSize viewportSize) { position += MyGUI::IntPoint(0, 32) - - MyGUI::IntPoint((MyGUI::InputManager::getInstance().getMousePosition().left / float(viewportSize.width) * size.width), 0); + - MyGUI::IntPoint(static_cast(MyGUI::InputManager::getInstance().getMousePosition().left / float(viewportSize.width) * size.width), 0); if ((position.left + size.width) > viewportSize.width) { @@ -413,7 +413,7 @@ namespace MWGui { MyGUI::ImageBox* icon = mDynamicToolTipBox->createWidget("MarkerButton", MyGUI::IntCoord(padding.left, totalSize.height+padding.top, 8, 8), MyGUI::Align::Default); - icon->setColour(MyGUI::Colour(1.0,0.3,0.3)); + icon->setColour(MyGUI::Colour(1.0f, 0.3f, 0.3f)); MyGUI::EditBox* edit = mDynamicToolTipBox->createWidget("SandText", MyGUI::IntCoord(padding.left+8+4, totalSize.height+padding.top, 300-padding.left-8-4, 300-totalSize.height), MyGUI::Align::Default); diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 40cf3e9bf..5015ef456 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -34,18 +34,21 @@ namespace int getEffectiveValue (MWWorld::Ptr item, int count) { - int price = item.getClass().getValue(item) * count; + float price = item.getClass().getValue(item); if (item.getClass().hasItemHealth(item)) - price *= (static_cast(item.getClass().getItemHealth(item)) / item.getClass().getItemMaxHealth(item)); - return price; + { + price *= item.getClass().getItemHealth(item); + price /= item.getClass().getItemMaxHealth(item); + } + return static_cast(price * count); } } namespace MWGui { - const float TradeWindow::sBalanceChangeInitialPause = 0.5; - const float TradeWindow::sBalanceChangeInterval = 0.1; + const float TradeWindow::sBalanceChangeInitialPause = 0.5f; + const float TradeWindow::sBalanceChangeInterval = 0.1f; TradeWindow::TradeWindow() : WindowBase("openmw_trade_window.layout") @@ -340,16 +343,16 @@ namespace MWGui else d = int(100 * (b - a) / a); - float clampedDisposition = std::max(0,std::min(int(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr) - + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange()),100)); + float clampedDisposition = std::max(0,std::min(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr) + + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange(),100)); const MWMechanics::CreatureStats &sellerStats = mPtr.getClass().getCreatureStats(mPtr); const MWMechanics::CreatureStats &playerStats = player.getClass().getCreatureStats(player); - float a1 = player.getClass().getSkill(player, ESM::Skill::Mercantile); + float a1 = static_cast(player.getClass().getSkill(player, ESM::Skill::Mercantile)); float b1 = 0.1f * playerStats.getAttribute(ESM::Attribute::Luck).getModified(); float c1 = 0.2f * playerStats.getAttribute(ESM::Attribute::Personality).getModified(); - float d1 = mPtr.getClass().getSkill(mPtr, ESM::Skill::Mercantile); + float d1 = static_cast(mPtr.getClass().getSkill(mPtr, ESM::Skill::Mercantile)); float e1 = 0.1f * sellerStats.getAttribute(ESM::Attribute::Luck).getModified(); float f1 = 0.2f * sellerStats.getAttribute(ESM::Attribute::Personality).getModified(); @@ -379,9 +382,9 @@ namespace MWGui int finalPrice = std::abs(mCurrentBalance); int initialMerchantOffer = std::abs(mCurrentMerchantOffer); if (!buying && (finalPrice > initialMerchantOffer) && finalPrice > 0) - skillGain = int(100 * (finalPrice - initialMerchantOffer) / float(finalPrice)); + skillGain = floor(100 * (finalPrice - initialMerchantOffer) / float(finalPrice)); else if (buying && (finalPrice < initialMerchantOffer) && initialMerchantOffer > 0) - skillGain = int(100 * (initialMerchantOffer - finalPrice) / float(initialMerchantOffer)); + skillGain = floor(100 * (initialMerchantOffer - finalPrice) / float(initialMerchantOffer)); player.getClass().skillUsageSucceeded(player, ESM::Skill::Mercantile, 0, skillGain); } diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 5a5f61115..6376ced57 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -40,7 +40,7 @@ namespace MWGui TrainingWindow::TrainingWindow() : WindowBase("openmw_trainingwindow.layout") , mFadeTimeRemaining(0) - , mTimeAdvancer(0.05) + , mTimeAdvancer(0.05f) { getWidget(mTrainingOptions, "TrainingOptions"); getWidget(mCancelButton, "CancelButton"); diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 50e08223e..6a45e6026 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -66,13 +66,13 @@ namespace MWGui if(interior) { - price = gmst.find("fMagesGuildTravel")->getFloat(); + price = gmst.find("fMagesGuildTravel")->getInt(); } else { ESM::Position PlayerPos = player.getRefData().getPosition(); float d = sqrt( pow(pos.pos[0] - PlayerPos.pos[0],2) + pow(pos.pos[1] - PlayerPos.pos[1],2) + pow(pos.pos[2] - PlayerPos.pos[2],2) ); - price = d/gmst.find("fTravelMult")->getFloat(); + price = static_cast(d / gmst.find("fTravelMult")->getFloat()); } price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true); @@ -209,10 +209,10 @@ namespace MWGui void TravelWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) { - if (mDestinationsView->getViewOffset().top + _rel*0.3 > 0) + if (mDestinationsView->getViewOffset().top + _rel*0.3f > 0) mDestinationsView->setViewOffset(MyGUI::IntPoint(0, 0)); else - mDestinationsView->setViewOffset(MyGUI::IntPoint(0, mDestinationsView->getViewOffset().top + _rel*0.3)); + mDestinationsView->setViewOffset(MyGUI::IntPoint(0, static_cast(mDestinationsView->getViewOffset().top + _rel*0.3f))); } } diff --git a/apps/openmw/mwgui/videowidget.cpp b/apps/openmw/mwgui/videowidget.cpp index 046070841..f865de377 100644 --- a/apps/openmw/mwgui/videowidget.cpp +++ b/apps/openmw/mwgui/videowidget.cpp @@ -58,8 +58,8 @@ void VideoWidget::autoResize(bool stretch) { double imageaspect = static_cast(getVideoWidth())/getVideoHeight(); - int leftPadding = std::max(0.0, (screenSize.width - screenSize.height * imageaspect) / 2); - int topPadding = std::max(0.0, (screenSize.height - screenSize.width / imageaspect) / 2); + int leftPadding = std::max(0, static_cast(screenSize.width - screenSize.height * imageaspect) / 2); + int topPadding = std::max(0, static_cast(screenSize.height - screenSize.width / imageaspect) / 2); setCoord(leftPadding, topPadding, screenSize.width - leftPadding*2, screenSize.height - topPadding*2); diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index ad873a7c3..b73ab38f2 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -49,7 +49,7 @@ namespace MWGui WaitDialog::WaitDialog() : WindowBase("openmw_wait_dialog.layout") , mProgressBar() - , mTimeAdvancer(0.05) + , mTimeAdvancer(0.05f) , mSleeping(false) , mHours(1) , mManualHours(1) @@ -104,7 +104,7 @@ namespace MWGui mHourSlider->setScrollPosition (0); std::string month = MWBase::Environment::get().getWorld ()->getMonthName(); - int hour = MWBase::Environment::get().getWorld ()->getTimeStamp ().getHour (); + int hour = static_cast(MWBase::Environment::get().getWorld()->getTimeStamp().getHour()); bool pm = hour >= 12; if (hour >= 13) hour -= 12; if (hour == 0) hour = 12; @@ -135,8 +135,8 @@ namespace MWGui MWBase::Environment::get().getStateManager()->quickSave("Autosave"); MWBase::World* world = MWBase::Environment::get().getWorld(); - MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.2); - mFadeTimeRemaining = 0.4; + MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.2f); + mFadeTimeRemaining = 0.4f; setVisible(false); mHours = hoursToWait; @@ -153,7 +153,7 @@ namespace MWGui if (!region->mSleepList.empty()) { float fSleepRandMod = world->getStore().get().find("fSleepRandMod")->getFloat(); - int x = std::rand()/ (static_cast (RAND_MAX) + 1) * hoursToWait; // [0, hoursRested] + int x = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * hoursToWait); // [0, hoursRested] float y = fSleepRandMod * hoursToWait; if (x > y) { @@ -251,7 +251,7 @@ namespace MWGui void WaitDialog::stopWaiting () { - MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.2); + MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.2f); mProgressBar.setVisible (false); MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Rest); MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_RestBed); diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 79c0f93f0..718624a16 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -540,8 +540,8 @@ namespace MWGui MWScrollBar::MWScrollBar() : mEnableRepeat(true) - , mRepeatTriggerTime(0.5) - , mRepeatStepTime(0.1) + , mRepeatTriggerTime(0.5f) + , mRepeatStepTime(0.1f) , mIsIncreasing(true) { } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index d8074a5d8..815f342a4 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1103,10 +1103,10 @@ namespace MWGui for (std::map::iterator it = mTrackedWindows.begin(); it != mTrackedWindows.end(); ++it) { - MyGUI::IntPoint pos (Settings::Manager::getFloat(it->second + " x", "Windows") * x, - Settings::Manager::getFloat(it->second+ " y", "Windows") * y); - MyGUI::IntSize size (Settings::Manager::getFloat(it->second + " w", "Windows") * x, - Settings::Manager::getFloat(it->second + " h", "Windows") * y); + MyGUI::IntPoint pos(static_cast(Settings::Manager::getFloat(it->second + " x", "Windows") * x), + static_cast( Settings::Manager::getFloat(it->second+ " y", "Windows") * y)); + MyGUI::IntSize size(static_cast(Settings::Manager::getFloat(it->second + " w", "Windows") * x), + static_cast(Settings::Manager::getFloat(it->second + " h", "Windows") * y)); it->first->setPosition(pos); it->first->setSize(size); } @@ -1221,7 +1221,7 @@ namespace MWGui .find(item.getClass().getEnchantment(item)); int chargePercent = (item.getCellRef().getEnchantmentCharge() == -1) ? 100 - : (item.getCellRef().getEnchantmentCharge() / static_cast(ench->mData.mCharge) * 100); + : static_cast(item.getCellRef().getEnchantmentCharge() / static_cast(ench->mData.mCharge) * 100); mHud->setSelectedEnchantItem(item, chargePercent); mSpellWindow->setTitle(item.getClass().getName(item)); } @@ -1229,7 +1229,7 @@ namespace MWGui void WindowManager::setSelectedWeapon(const MWWorld::Ptr& item) { int durabilityPercent = - (item.getClass().getItemHealth(item) / static_cast(item.getClass().getItemMaxHealth(item)) * 100); + static_cast(item.getClass().getItemHealth(item) / static_cast(item.getClass().getItemMaxHealth(item)) * 100); mHud->setSelectedWeapon(item, durabilityPercent); mInventoryWindow->setTitle(item.getClass().getName(item)); } @@ -1262,8 +1262,8 @@ namespace MWGui void WindowManager::getMousePosition(float &x, float &y) { const MyGUI::IntPoint& pos = MyGUI::InputManager::getInstance().getMousePosition(); - x = pos.left; - y = pos.top; + x = static_cast(pos.left); + y = static_cast(pos.top); const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); x /= viewSize.width; y /= viewSize.height; @@ -1569,10 +1569,10 @@ namespace MWGui void WindowManager::trackWindow(OEngine::GUI::Layout *layout, const std::string &name) { MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); - MyGUI::IntPoint pos (Settings::Manager::getFloat(name + " x", "Windows") * viewSize.width, - Settings::Manager::getFloat(name + " y", "Windows") * viewSize.height); - MyGUI::IntSize size (Settings::Manager::getFloat(name + " w", "Windows") * viewSize.width, - Settings::Manager::getFloat(name + " h", "Windows") * viewSize.height); + MyGUI::IntPoint pos(static_cast(Settings::Manager::getFloat(name + " x", "Windows") * viewSize.width), + static_cast(Settings::Manager::getFloat(name + " y", "Windows") * viewSize.height)); + MyGUI::IntSize size (static_cast(Settings::Manager::getFloat(name + " w", "Windows") * viewSize.width), + static_cast(Settings::Manager::getFloat(name + " h", "Windows") * viewSize.height)); layout->mMainWidget->setPosition(pos); layout->mMainWidget->setSize(size); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index e84e2c5b3..829ea1482 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -377,7 +377,7 @@ namespace MWInput //cursor is if( !is_relative && was_relative != is_relative ) { - mInputManager->warpMouse(mMouseX, mMouseY); + mInputManager->warpMouse(static_cast(mMouseX), static_cast(mMouseY)); } } @@ -415,13 +415,13 @@ namespace MWInput // game mode does not move the position of the GUI cursor mMouseX += xAxis * dt * 1500.0f; mMouseY += yAxis * dt * 1500.0f; - mMouseWheel -= zAxis * dt * 1500.0f; + mMouseWheel -= static_cast(zAxis * dt * 1500.0f); mMouseX = std::max(0.f, std::min(mMouseX, float(viewSize.width))); mMouseY = std::max(0.f, std::min(mMouseY, float(viewSize.height))); - MyGUI::InputManager::getInstance().injectMouseMove( mMouseX, mMouseY, mMouseWheel); - mInputManager->warpMouse(mMouseX, mMouseY); + MyGUI::InputManager::getInstance().injectMouseMove(static_cast(mMouseX), static_cast(mMouseY), mMouseWheel); + mInputManager->warpMouse(static_cast(mMouseX), static_cast(mMouseY)); } if (mMouseLookEnabled) { @@ -703,7 +703,7 @@ namespace MWInput if (id == SDL_BUTTON_LEFT || id == SDL_BUTTON_RIGHT) // MyGUI only uses these mouse events { guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); - guiMode = MyGUI::InputManager::getInstance().injectMousePress(mMouseX, mMouseY, sdlButtonToMyGUI(id)) && guiMode; + guiMode = MyGUI::InputManager::getInstance().injectMousePress(static_cast(mMouseX), static_cast(mMouseY), sdlButtonToMyGUI(id)) && guiMode; if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0) { MyGUI::Button* b = MyGUI::InputManager::getInstance ().getMouseFocusWidget ()->castType(false); @@ -730,7 +730,7 @@ namespace MWInput mInputBinder->mouseReleased (arg, id); } else { bool guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); - guiMode = MyGUI::InputManager::getInstance().injectMouseRelease(mMouseX, mMouseY, sdlButtonToMyGUI(id)) && guiMode; + guiMode = MyGUI::InputManager::getInstance().injectMouseRelease(static_cast(mMouseX), static_cast(mMouseY), sdlButtonToMyGUI(id)) && guiMode; if(mInputBinder->detectingBindingState()) return; // don't allow same mouseup to bind as initiated bind @@ -752,8 +752,8 @@ namespace MWInput // We keep track of our own mouse position, so that moving the mouse while in // game mode does not move the position of the GUI cursor - mMouseX = arg.x; - mMouseY = arg.y; + mMouseX = static_cast(arg.x); + mMouseY = static_cast(arg.y); mMouseX = std::max(0.f, std::min(mMouseX, float(viewSize.width))); mMouseY = std::max(0.f, std::min(mMouseY, float(viewSize.height))); @@ -767,8 +767,8 @@ namespace MWInput { resetIdleTime(); - double x = arg.xrel * mCameraSensitivity * (1.0f/256.f); - double y = arg.yrel * mCameraSensitivity * (1.0f/256.f) * (mInvertY ? -1 : 1) * mCameraYMultiplier; + float x = arg.xrel * mCameraSensitivity * (1.0f/256.f); + float y = arg.yrel * mCameraSensitivity * (1.0f/256.f) * (mInvertY ? -1 : 1) * mCameraYMultiplier; float rot[3]; rot[0] = -y; @@ -784,10 +784,10 @@ namespace MWInput if (arg.zrel && mControlSwitch["playerviewswitch"] && mControlSwitch["playercontrols"]) //Check to make sure you are allowed to zoomout and there is a change { - MWBase::Environment::get().getWorld()->changeVanityModeScale(arg.zrel); + MWBase::Environment::get().getWorld()->changeVanityModeScale(static_cast(arg.zrel)); if (Settings::Manager::getBool("allow third person zoom", "Input")) - MWBase::Environment::get().getWorld()->setCameraDistance(arg.zrel, true, true); + MWBase::Environment::get().getWorld()->setCameraDistance(static_cast(arg.zrel), true, true); } } } @@ -802,7 +802,8 @@ namespace MWInput guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); if(!mInputBinder->detectingBindingState()) { - guiMode = MyGUI::InputManager::getInstance().injectMousePress(mMouseX, mMouseY, sdlButtonToMyGUI((arg.button == SDL_CONTROLLER_BUTTON_B) ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT)) && guiMode; + guiMode = MyGUI::InputManager::getInstance().injectMousePress(static_cast(mMouseX), static_cast(mMouseY), + sdlButtonToMyGUI((arg.button == SDL_CONTROLLER_BUTTON_B) ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT)) && guiMode; if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0) { MyGUI::Button* b = MyGUI::InputManager::getInstance ().getMouseFocusWidget ()->castType(false); @@ -833,7 +834,7 @@ namespace MWInput else if(arg.button == SDL_CONTROLLER_BUTTON_A || arg.button == SDL_CONTROLLER_BUTTON_B) { bool guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); - guiMode = MyGUI::InputManager::getInstance().injectMouseRelease(mMouseX, mMouseY, sdlButtonToMyGUI((arg.button == SDL_CONTROLLER_BUTTON_B) ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT)) && guiMode; + guiMode = MyGUI::InputManager::getInstance().injectMouseRelease(static_cast(mMouseX), static_cast(mMouseY), sdlButtonToMyGUI((arg.button == SDL_CONTROLLER_BUTTON_B) ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT)) && guiMode; if(mInputBinder->detectingBindingState()) return; // don't allow same mouseup to bind as initiated bind @@ -1236,10 +1237,7 @@ namespace MWInput bool controlExists = mInputBinder->getChannel(i)->getControlsCount () != 0; if (!controlExists) { - int inital; - if (defaultButtonBindings.find(i) != defaultButtonBindings.end()) - inital = 0.0f; - else inital = 0.5f; + float inital = (defaultButtonBindings.find(i) != defaultButtonBindings.end()) ? 0.0f : 0.5f; control = new ICS::Control(boost::lexical_cast(i), false, true, inital, ICS::ICS_MAX, ICS::ICS_MAX); mInputBinder->addControl(control); control->attachChannel(mInputBinder->getChannel(i), ICS::Channel::DIRECT); diff --git a/apps/openmw/mwmechanics/disease.hpp b/apps/openmw/mwmechanics/disease.hpp index a973c0e35..2f7d65dfd 100644 --- a/apps/openmw/mwmechanics/disease.hpp +++ b/apps/openmw/mwmechanics/disease.hpp @@ -37,19 +37,19 @@ namespace MWMechanics float resist = 0.f; if (spells.hasCorprusEffect(spell)) - resist = 1.f - 0.01 * (actorEffects.get(ESM::MagicEffect::ResistCorprusDisease).getMagnitude() + resist = 1.f - 0.01f * (actorEffects.get(ESM::MagicEffect::ResistCorprusDisease).getMagnitude() - actorEffects.get(ESM::MagicEffect::WeaknessToCorprusDisease).getMagnitude()); else if (spell->mData.mType == ESM::Spell::ST_Disease) - resist = 1.f - 0.01 * (actorEffects.get(ESM::MagicEffect::ResistCommonDisease).getMagnitude() + resist = 1.f - 0.01f * (actorEffects.get(ESM::MagicEffect::ResistCommonDisease).getMagnitude() - actorEffects.get(ESM::MagicEffect::WeaknessToCommonDisease).getMagnitude()); else if (spell->mData.mType == ESM::Spell::ST_Blight) - resist = 1.f - 0.01 * (actorEffects.get(ESM::MagicEffect::ResistBlightDisease).getMagnitude() + resist = 1.f - 0.01f * (actorEffects.get(ESM::MagicEffect::ResistBlightDisease).getMagnitude() - actorEffects.get(ESM::MagicEffect::WeaknessToBlightDisease).getMagnitude()); else continue; - int x = fDiseaseXferChance * 100 * resist; - float roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 10000; // [0, 9999] + int x = static_cast(fDiseaseXferChance * 100 * resist); + float roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 10000); // [0, 9999] if (roll < x) { diff --git a/apps/openmw/mwmechanics/levelledlist.hpp b/apps/openmw/mwmechanics/levelledlist.hpp index db13c1a45..cd1276038 100644 --- a/apps/openmw/mwmechanics/levelledlist.hpp +++ b/apps/openmw/mwmechanics/levelledlist.hpp @@ -22,7 +22,7 @@ namespace MWMechanics failChance += levItem->mChanceNone; - int random = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + int random = static_cast(static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100)); // [0, 99] if (random < failChance) return std::string(); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 4e4a1a8a6..5633ce3b7 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -556,7 +556,7 @@ namespace MWMechanics int MechanicsManager::getDerivedDisposition(const MWWorld::Ptr& ptr) { const MWMechanics::NpcStats& npcSkill = ptr.getClass().getNpcStats(ptr); - float x = npcSkill.getBaseDisposition(); + float x = static_cast(npcSkill.getBaseDisposition()); MWWorld::LiveCellRef* npc = ptr.get(); MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld()->getPlayerPtr(); @@ -583,7 +583,7 @@ namespace MWMechanics if (!playerStats.getExpelled(npcFaction)) { // faction reaction towards itself. yes, that exists - reaction = MWBase::Environment::get().getDialogueManager()->getFactionReaction(npcFaction, npcFaction); + reaction = static_cast(MWBase::Environment::get().getDialogueManager()->getFactionReaction(npcFaction, npcFaction)); rank = playerStats.getFactionRanks().find(npcFaction)->second; } @@ -597,7 +597,7 @@ namespace MWMechanics int itReaction = MWBase::Environment::get().getDialogueManager()->getFactionReaction(npcFaction, itFaction); if (playerFactionIt == playerStats.getFactionRanks().begin() || itReaction < reaction) - reaction = itReaction; + reaction = static_cast(itReaction); } } else @@ -643,17 +643,17 @@ namespace MWMechanics // otherwise one would get different prices when exiting and re-entering the dialogue window... int clampedDisposition = std::max(0, std::min(getDerivedDisposition(ptr) + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange(),100)); - float a = std::min(playerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100); + float a = static_cast(std::min(playerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100)); float b = std::min(0.1f * playerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f); float c = std::min(0.2f * playerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f); - float d = std::min(sellerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100); + float d = static_cast(std::min(sellerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100)); float e = std::min(0.1f * sellerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f); float f = std::min(0.2f * sellerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f); float pcTerm = (clampedDisposition - 50 + a + b + c) * playerStats.getFatigueTerm(); float npcTerm = (d + e + f) * sellerStats.getFatigueTerm(); - float buyTerm = 0.01 * (100 - 0.5 * (pcTerm - npcTerm)); - float sellTerm = 0.01 * (50 - 0.5 * (npcTerm - pcTerm)); + float buyTerm = 0.01f * (100 - 0.5f * (pcTerm - npcTerm)); + float sellTerm = 0.01f * (50 - 0.5f * (npcTerm - pcTerm)); float x; if(buying) x = buyTerm; @@ -704,7 +704,7 @@ namespace MWMechanics int currentDisposition = std::min(100, std::max(0, int(getDerivedDisposition(npc) + currentTemporaryDispositionDelta))); - float d = 1 - 0.02 * abs(currentDisposition - 50); + float d = 1 - 0.02f * abs(currentDisposition - 50); float target1 = d * (playerRating1 - npcRating1 + 50); float target2 = d * (playerRating2 - npcRating2 + 50); @@ -715,8 +715,8 @@ namespace MWMechanics float target3 = d * (playerRating3 - npcRating3 + 50) + bribeMod; - float iPerMinChance = gmst.find("iPerMinChance")->getInt(); - float iPerMinChange = gmst.find("iPerMinChange")->getInt(); + float iPerMinChance = floor(gmst.find("iPerMinChance")->getFloat()); + float iPerMinChange = floor(gmst.find("iPerMinChange")->getFloat()); float fPerDieRollMult = gmst.find("fPerDieRollMult")->getFloat(); float fPerTempMult = gmst.find("fPerTempMult")->getFloat(); @@ -729,7 +729,7 @@ namespace MWMechanics { target1 = std::max(iPerMinChance, target1); success = (roll <= target1); - float c = int(fPerDieRollMult * (target1 - roll)); + float c = floor(fPerDieRollMult * (target1 - roll)); x = success ? std::max(iPerMinChange, c) : c; } else if (type == PT_Intimidate) @@ -740,13 +740,13 @@ namespace MWMechanics float r; if (roll != target2) - r = int(target2 - roll); + r = floor(target2 - roll); else r = 1; if (roll <= target2) { - float s = int(r * fPerDieRollMult * fPerTempMult); + float s = floor(r * fPerDieRollMult * fPerTempMult); int flee = npcStats.getAiSetting(MWMechanics::CreatureStats::AI_Flee).getBase(); int fight = npcStats.getAiSetting(MWMechanics::CreatureStats::AI_Fight).getBase(); @@ -756,7 +756,7 @@ namespace MWMechanics std::max(0, std::min(100, fight + int(std::min(-iPerMinChange, -s))))); } - float c = -std::abs(int(r * fPerDieRollMult)); + float c = -std::abs(floor(r * fPerDieRollMult)); if (success) { if (std::abs(c) < iPerMinChange) @@ -766,13 +766,13 @@ namespace MWMechanics } else { - x = -int(c * fPerTempMult); + x = -floor(c * fPerTempMult); y = c; } } else { - x = int(c * fPerTempMult); + x = floor(c * fPerTempMult); y = c; } } @@ -781,7 +781,7 @@ namespace MWMechanics target1 = std::max(iPerMinChance, target1); success = (roll <= target1); - float c = std::abs(int(target1 - roll)); + float c = std::abs(floor(target1 - roll)); if (success) { @@ -793,7 +793,7 @@ namespace MWMechanics npcStats.setAiSetting (CreatureStats::AI_Fight, std::max(0, std::min(100, fight + std::max(int(iPerMinChange), int(s))))); } - x = int(-c * fPerDieRollMult); + x = floor(-c * fPerDieRollMult); if (success && std::abs(x) < iPerMinChange) x = -iPerMinChange; @@ -802,7 +802,7 @@ namespace MWMechanics { target3 = std::max(iPerMinChance, target3); success = (roll <= target3); - float c = int((target3 - roll) * fPerDieRollMult); + float c = floor((target3 - roll) * fPerDieRollMult); x = success ? std::max(iPerMinChange, c) : c; } @@ -812,11 +812,11 @@ namespace MWMechanics float cappedDispositionChange = tempChange; if (currentDisposition + tempChange > 100.f) - cappedDispositionChange = 100 - currentDisposition; + cappedDispositionChange = static_cast(100 - currentDisposition); if (currentDisposition + tempChange < 0.f) - cappedDispositionChange = -currentDisposition; + cappedDispositionChange = static_cast(-currentDisposition); - permChange = int(cappedDispositionChange / fPerTempMult); + permChange = floor(cappedDispositionChange / fPerTempMult); if (type == PT_Intimidate) { permChange = success ? -int(cappedDispositionChange/ fPerTempMult) : y; @@ -1104,7 +1104,7 @@ namespace MWMechanics if (type == OT_Trespassing || type == OT_SleepingInOwnedBed) { arg = store.find("iCrimeTresspass")->getInt(); - disp = dispVictim = store.find("iDispTresspass")->getInt(); + disp = dispVictim = store.find("iDispTresspass")->getFloat(); } else if (type == OT_Pickpocket) { @@ -1114,18 +1114,18 @@ namespace MWMechanics else if (type == OT_Assault) { arg = store.find("iCrimeAttack")->getInt(); - disp = store.find("iDispAttackMod")->getInt(); + disp = store.find("iDispAttackMod")->getFloat(); dispVictim = store.find("fDispAttacking")->getFloat(); } else if (type == OT_Murder) { arg = store.find("iCrimeKilling")->getInt(); - disp = dispVictim = store.find("iDispKilling")->getInt(); + disp = dispVictim = store.find("iDispKilling")->getFloat(); } else if (type == OT_Theft) { disp = dispVictim = store.find("fDispStealing")->getFloat() * arg; - arg *= store.find("fCrimeStealing")->getFloat(); + arg = static_cast(arg * store.find("fCrimeStealing")->getFloat()); arg = std::max(1, arg); // Minimum bounty of 1, in case items with zero value are stolen } @@ -1163,7 +1163,7 @@ namespace MWMechanics else if (type == OT_Murder) fight = fightVictim = esmStore.get().find("iFightKilling")->getInt(); else if (type == OT_Theft) - fight = fightVictim = esmStore.get().find("fFightStealing")->getFloat(); + fight = fightVictim = esmStore.get().find("fFightStealing")->getInt(); bool reported = false; @@ -1197,21 +1197,21 @@ namespace MWMechanics { float dispTerm = (*it == victim) ? dispVictim : disp; - float alarmTerm = 0.01 * it->getClass().getCreatureStats(*it).getAiSetting(CreatureStats::AI_Alarm).getBase(); + float alarmTerm = 0.01f * it->getClass().getCreatureStats(*it).getAiSetting(CreatureStats::AI_Alarm).getBase(); if (type == OT_Pickpocket && alarmTerm <= 0) alarmTerm = 1.0; if (*it != victim) dispTerm *= alarmTerm; - float fightTerm = (*it == victim) ? fightVictim : fight; + float fightTerm = static_cast((*it == victim) ? fightVictim : fight); fightTerm += getFightDispositionBias(dispTerm); fightTerm += getFightDistanceBias(*it, player); fightTerm *= alarmTerm; int observerFightRating = it->getClass().getCreatureStats(*it).getAiSetting(CreatureStats::AI_Fight).getBase(); if (observerFightRating + fightTerm > 100) - fightTerm = 100 - observerFightRating; + fightTerm = static_cast(100 - observerFightRating); fightTerm = std::max(0.f, fightTerm); if (observerFightRating + fightTerm >= 100) @@ -1221,9 +1221,9 @@ namespace MWMechanics NpcStats& observerStats = it->getClass().getNpcStats(*it); // Apply aggression value to the base Fight rating, so that the actor can continue fighting // after a Calm spell wears off - observerStats.setAiSetting(CreatureStats::AI_Fight, observerFightRating + fightTerm); + observerStats.setAiSetting(CreatureStats::AI_Fight, observerFightRating + static_cast(fightTerm)); - observerStats.setBaseDisposition(observerStats.getBaseDisposition()+dispTerm); + observerStats.setBaseDisposition(observerStats.getBaseDisposition() + static_cast(dispTerm)); // Set the crime ID, which we will use to calm down participants // once the bounty has been paid. @@ -1334,7 +1334,7 @@ namespace MWMechanics { static float fSneakSkillMult = store.find("fSneakSkillMult")->getFloat(); static float fSneakBootMult = store.find("fSneakBootMult")->getFloat(); - float sneak = ptr.getClass().getSkill(ptr, ESM::Skill::Sneak); + float sneak = static_cast(ptr.getClass().getSkill(ptr, ESM::Skill::Sneak)); int agility = stats.getAttribute(ESM::Attribute::Agility).getModified(); int luck = stats.getAttribute(ESM::Attribute::Luck).getModified(); float bootWeight = 0; @@ -1345,7 +1345,7 @@ namespace MWMechanics if (it != inv.end()) bootWeight = it->getClass().getWeight(*it); } - sneakTerm = fSneakSkillMult * sneak + 0.2 * agility + 0.1 * luck + bootWeight * fSneakBootMult; + sneakTerm = fSneakSkillMult * sneak + 0.2f * agility + 0.1f * luck + bootWeight * fSneakBootMult; } static float fSneakDistBase = store.find("fSneakDistanceBase")->getFloat(); @@ -1364,7 +1364,7 @@ namespace MWMechanics float obsBlind = observerStats.getMagicEffects().get(ESM::MagicEffect::Blind).getMagnitude(); int obsSneak = observer.getClass().getSkill(observer, ESM::Skill::Sneak); - float obsTerm = obsSneak + 0.2 * obsAgility + 0.1 * obsLuck - obsBlind; + float obsTerm = obsSneak + 0.2f * obsAgility + 0.1f * obsLuck - obsBlind; // is ptr behind the observer? static float fSneakNoViewMult = store.find("fSneakNoViewMult")->getFloat(); @@ -1378,7 +1378,7 @@ namespace MWMechanics y = obsTerm * observerStats.getFatigueTerm() * fSneakViewMult; float target = x - y; - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] return (roll >= target); } @@ -1479,9 +1479,8 @@ namespace MWMechanics if (ptr.getClass().isNpc()) disposition = getDerivedDisposition(ptr); - int fight = std::max(0.f, ptr.getClass().getCreatureStats(ptr).getAiSetting(CreatureStats::AI_Fight).getModified() - + getFightDistanceBias(ptr, target) - + getFightDispositionBias(disposition)); + int fight = std::max(0, ptr.getClass().getCreatureStats(ptr).getAiSetting(CreatureStats::AI_Fight).getModified() + + static_cast(getFightDistanceBias(ptr, target) + getFightDispositionBias(disposition))); if (ptr.getClass().isNpc() && target.getClass().isNpc()) { diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index 294dbcb6c..5c41e007e 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -251,7 +251,6 @@ namespace MWMechanics void damage(float damage) { mDamage = std::min(mDamage + damage, (float)(mBase + mFortified)); } void restore(float amount) { mDamage -= std::min(mDamage, amount); } - int getDamage() const { return mDamage; } void writeState (ESM::StatState& state) const; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 01a88faf2..871561bdc 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -365,7 +365,7 @@ void Animation::addExtraLight(Ogre::SceneManager *sceneMgr, NifOgre::ObjectScene // with the standard 1 / (c + d*l + d*d*q) equation the attenuation factor never becomes zero, // so we ignore lights if their attenuation falls below this factor. - const float threshold = 0.03; + const float threshold = 0.03f; float quadraticAttenuation = 0; float linearAttenuation = 0; @@ -1477,7 +1477,7 @@ void Animation::setLightEffect(float effect) } mGlowLight->setType(Ogre::Light::LT_POINT); effect += 3; - mGlowLight->setAttenuation(1.0f / (0.03 * (0.5/effect)), 0, 0.5/effect, 0); + mGlowLight->setAttenuation(1.0f / (0.03f * (0.5f/effect)), 0, 0.5f/effect, 0); } } diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 756c79ad8..8071dd5fd 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -69,13 +69,13 @@ namespace MWRender /// \todo Read the fallback values from INIImporter (Inventory:Directional*) l = mSceneMgr->createLight(); l->setType (Ogre::Light::LT_DIRECTIONAL); - l->setDirection (Ogre::Vector3(0.3, -0.7, 0.3)); + l->setDirection (Ogre::Vector3(0.3f, -0.7f, 0.3f)); l->setDiffuseColour (Ogre::ColourValue(1,1,1)); mSceneMgr->setAmbientLight (Ogre::ColourValue(0.25, 0.25, 0.25)); mCamera = mSceneMgr->createCamera (mName); - mCamera->setFOVy(Ogre::Degree(12.3)); + mCamera->setFOVy(Ogre::Degree(12.3f)); mCamera->setAspectRatio (float(mSizeX) / float(mSizeY)); Ogre::SceneNode* renderRoot = mSceneMgr->getRootSceneNode()->createChildSceneNode("renderRoot"); diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index de78748b5..95d4429d6 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -86,8 +86,8 @@ namespace MWRender { for (int cellX=0; cellX(float(cellX)/float(mCellSize) * 9); + int vertexY = static_cast(float(cellY) / float(mCellSize) * 9); int texelX = (x-mMinX) * mCellSize + cellX; @@ -102,9 +102,9 @@ namespace MWRender y = (SCHAR_MIN << 4) / 2048.f; if (y < 0) { - r = (14 * y + 38); - g = 20 * y + 56; - b = 18 * y + 51; + r = static_cast(14 * y + 38); + g = static_cast(20 * y + 56); + b = static_cast(18 * y + 51); } else if (y < 0.3f) { @@ -112,20 +112,20 @@ namespace MWRender y *= 8.f; else { - y -= 0.1; - y += 0.8; + y -= 0.1f; + y += 0.8f; } - r = 66 - 32 * y; - g = 48 - 23 * y; - b = 33 - 16 * y; + r = static_cast(66 - 32 * y); + g = static_cast(48 - 23 * y); + b = static_cast(33 - 16 * y); } else { y -= 0.3f; y *= 1.428f; - r = 34 - 29 * y; - g = 25 - 20 * y; - b = 17 - 12 * y; + r = static_cast(34 - 29 * y); + g = static_cast(25 - 20 * y); + b = static_cast(17 - 12 * y); } data[texelY * mWidth * 3 + texelX * 3] = r; @@ -172,9 +172,9 @@ namespace MWRender void GlobalMap::exploreCell(int cellX, int cellY) { - float originX = (cellX - mMinX) * mCellSize; + float originX = static_cast((cellX - mMinX) * mCellSize); // NB y + 1, because we want the top left corner, not bottom left where the origin of the cell is - float originY = mHeight - (cellY+1 - mMinY) * mCellSize; + float originY = static_cast(mHeight - (cellY + 1 - mMinY) * mCellSize); if (cellX > mMaxX || cellX < mMinX || cellY > mMaxY || cellY < mMinY) return; @@ -188,7 +188,8 @@ namespace MWRender int mapHeight = localMapTexture->getHeight(); mOverlayTexture->load(); mOverlayTexture->getBuffer()->blit(localMapTexture->getBuffer(), Ogre::Image::Box(0,0,mapWidth,mapHeight), - Ogre::Image::Box(originX,originY,originX+mCellSize,originY+mCellSize)); + Ogre::Image::Box(static_cast(originX), static_cast(originY), + static_cast(originX + mCellSize), static_cast(originY + mCellSize))); Ogre::Image backup; std::vector data; @@ -204,7 +205,7 @@ namespace MWRender assert (originY+y < mOverlayImage.getHeight()); assert (x < int(backup.getWidth())); assert (y < int(backup.getHeight())); - mOverlayImage.setColourAt(backup.getColourAt(x, y, 0), originX+x, originY+y, 0); + mOverlayImage.setColourAt(backup.getColourAt(x, y, 0), static_cast(originX + x), static_cast(originY + y), 0); } } } diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 638a08623..0299dc493 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -43,9 +43,9 @@ LocalMap::LocalMap(OEngine::Render::OgreRenderer* rend, MWRender::RenderingManag mLight = mRendering->getScene()->createLight(); mLight->setType (Ogre::Light::LT_DIRECTIONAL); - mLight->setDirection (Ogre::Vector3(0.3, 0.3, -0.7)); + mLight->setDirection (Ogre::Vector3(0.3f, 0.3f, -0.7f)); mLight->setVisible (false); - mLight->setDiffuseColour (ColourValue(0.7,0.7,0.7)); + mLight->setDiffuseColour (ColourValue(0.7f,0.7f,0.7f)); mRenderTexture = TextureManager::getSingleton().createManual( "localmap/rtt", @@ -114,8 +114,8 @@ void LocalMap::saveFogOfWar(MWWorld::CellStore* cell) Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().y); Vector2 length = max-min; - const int segsX = std::ceil( length.x / sSize ); - const int segsY = std::ceil( length.y / sSize ); + const int segsX = static_cast(std::ceil(length.x / sSize)); + const int segsY = static_cast(std::ceil(length.y / sSize)); mInteriorName = cell->getCell()->mName; @@ -175,7 +175,7 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, float zMin, float zMax) // Note: using force=true for exterior cell maps. // They must be updated even if they were visited before, because the set of surrounding active cells might be different // (and objects in a different cell can "bleed" into another cell's map if they cross the border) - render((x+0.5)*sSize, (y+0.5)*sSize, zMin, zMax, sSize, sSize, name, true); + render((x+0.5f)*sSize, (y+0.5f)*sSize, zMin, zMax, static_cast(sSize), static_cast(sSize), name, true); if (mBuffers.find(name) == mBuffers.end()) { @@ -226,7 +226,7 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, // Do NOT change padding! This will break older savegames. // If the padding really needs to be changed, then it must be saved in the ESM::FogState and // assume the old (500) value as default for older savegames. - const int padding = 500; + const Ogre::Real padding = 500.0f; // Apply a little padding mBounds.setMinimum (mBounds.getMinimum() - Vector3(padding,padding,0)); @@ -279,8 +279,8 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, mCameraPosNode->setPosition(Vector3(center.x, center.y, 0)); // divide into segments - const int segsX = std::ceil( length.x / sSize ); - const int segsY = std::ceil( length.y / sSize ); + const int segsX = static_cast(std::ceil(length.x / sSize)); + const int segsY = static_cast(std::ceil(length.y / sSize)); mInteriorName = cell->getCell()->mName; @@ -289,12 +289,12 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, { for (int y=0; y(sSize*x), static_cast(sSize*y)); Vector2 newcenter = start + sSize/2; std::string texturePrefix = cell->getCell()->mName + "_" + coordStr(x,y); - render(newcenter.x - center.x, newcenter.y - center.y, zMin, zMax, sSize, sSize, texturePrefix); + render(newcenter.x - center.x, newcenter.y - center.y, zMin, zMax, static_cast(sSize), static_cast(sSize), texturePrefix); if (!cell->getFog()) createFogOfWar(texturePrefix); @@ -397,7 +397,7 @@ void LocalMap::render(const float x, const float y, // set up lighting Ogre::ColourValue oldAmbient = mRendering->getScene()->getAmbientLight(); - mRendering->getScene()->setAmbientLight(Ogre::ColourValue(0.3, 0.3, 0.3)); + mRendering->getScene()->setAmbientLight(Ogre::ColourValue(0.3f, 0.3f, 0.3f)); mRenderingManager->disableLights(true); mLight->setVisible(true); @@ -439,11 +439,11 @@ void LocalMap::worldToInteriorMapPosition (Ogre::Vector2 pos, float& nX, float& Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); - x = std::ceil((pos.x - min.x)/sSize)-1; - y = std::ceil((pos.y - min.y)/sSize)-1; + x = static_cast(std::ceil((pos.x - min.x) / sSize) - 1); + y = static_cast(std::ceil((pos.y - min.y) / sSize) - 1); nX = (pos.x - min.x - sSize*x)/sSize; - nY = 1.0-(pos.y - min.y - sSize*y)/sSize; + nY = 1.0f-(pos.y - min.y - sSize*y)/sSize; } Ogre::Vector2 LocalMap::interiorMapToWorldPosition (float nX, float nY, int x, int y) @@ -452,7 +452,7 @@ Ogre::Vector2 LocalMap::interiorMapToWorldPosition (float nX, float nY, int x, i Ogre::Vector2 pos; pos.x = sSize * (nX + x) + min.x; - pos.y = sSize * (1.0-nY + y) + min.y; + pos.y = sSize * (1.0f-nY + y) + min.y; pos = rotatePoint(pos, Vector2(mBounds.getCenter().x, mBounds.getCenter().y), -mAngle); return pos; @@ -468,8 +468,8 @@ bool LocalMap::isPositionExplored (float nX, float nY, int x, int y, bool interi nX = std::max(0.f, std::min(1.f, nX)); nY = std::max(0.f, std::min(1.f, nY)); - int texU = (sFogOfWarResolution-1) * nX; - int texV = (sFogOfWarResolution-1) * nY; + int texU = static_cast((sFogOfWarResolution - 1) * nX); + int texV = static_cast((sFogOfWarResolution - 1) * nY); Ogre::uint32 clr = mBuffers[texName][texV * sFogOfWarResolution + texU]; uint8 alpha = (clr >> 24); @@ -522,8 +522,8 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni if (!mInterior) { - x = std::ceil(pos.x / sSize)-1; - y = std::ceil(pos.y / sSize)-1; + x = static_cast(std::ceil(pos.x / sSize) - 1); + y = static_cast(std::ceil(pos.y / sSize) - 1); } else MWBase::Environment::get().getWindowManager()->setActiveMap(x,y,mInterior); @@ -533,7 +533,7 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni if (!mInterior) { u = std::abs((pos.x - (sSize*x))/sSize); - v = 1.0-std::abs((pos.y - (sSize*y))/sSize); + v = 1.0f-std::abs((pos.y - (sSize*y))/sSize); texBaseName = "Cell_"; } else @@ -545,7 +545,7 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni MWBase::Environment::get().getWindowManager()->setPlayerDir(playerdirection.x, playerdirection.y); // explore radius (squared) - const float exploreRadius = (mInterior ? 0.1 : 0.3) * (sFogOfWarResolution-1); // explore radius from 0 to sFogOfWarResolution-1 + const float exploreRadius = (mInterior ? 0.1f : 0.3f) * (sFogOfWarResolution-1); // explore radius from 0 to sFogOfWarResolution-1 const float sqrExploreRadius = Math::Sqr(exploreRadius); const float exploreRadiusUV = exploreRadius / sFogOfWarResolution; // explore radius from 0 to 1 (UV space) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index a2ad1e02c..284788522 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -101,7 +101,7 @@ void HeadAnimationTime::setEnabled(bool enabled) void HeadAnimationTime::resetBlinkTimer() { - mBlinkTimer = -(2 + (std::rand() / double(RAND_MAX*1.0)) * 6); + mBlinkTimer = -(2 + (std::rand() / static_cast(RAND_MAX)) * 6); } void HeadAnimationTime::update(float dt) diff --git a/apps/openmw/mwrender/refraction.cpp b/apps/openmw/mwrender/refraction.cpp index 6cc49089a..739ed24d9 100644 --- a/apps/openmw/mwrender/refraction.cpp +++ b/apps/openmw/mwrender/refraction.cpp @@ -35,7 +35,7 @@ namespace MWRender vp->setShadowsEnabled(false); vp->setVisibilityMask(RV_Refraction); vp->setMaterialScheme("water_refraction"); - vp->setBackgroundColour (Ogre::ColourValue(0.090195, 0.115685, 0.12745)); + vp->setBackgroundColour (Ogre::ColourValue(0.090195f, 0.115685f, 0.12745f)); mRenderTarget->setAutoUpdated(true); mRenderTarget->addListener(this); } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 05b43d54f..78ab45881 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -148,8 +148,8 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b sh::Factory::getInstance ().setSharedParameter ("waterEnabled", sh::makeProperty (new sh::FloatValue(0.0))); sh::Factory::getInstance ().setSharedParameter ("waterLevel", sh::makeProperty(new sh::FloatValue(0))); sh::Factory::getInstance ().setSharedParameter ("waterTimer", sh::makeProperty(new sh::FloatValue(0))); - sh::Factory::getInstance ().setSharedParameter ("windDir_windSpeed", sh::makeProperty(new sh::Vector3(0.5, -0.8, 0.2))); - sh::Factory::getInstance ().setSharedParameter ("waterSunFade_sunHeight", sh::makeProperty(new sh::Vector2(1, 0.6))); + sh::Factory::getInstance ().setSharedParameter ("windDir_windSpeed", sh::makeProperty(new sh::Vector3(0.5f, -0.8f, 0.2f))); + sh::Factory::getInstance ().setSharedParameter ("waterSunFade_sunHeight", sh::makeProperty(new sh::Vector2(1, 0.6f))); sh::Factory::getInstance ().setGlobalSetting ("refraction", Settings::Manager::getBool("refraction", "Water") ? "true" : "false"); sh::Factory::getInstance ().setGlobalSetting ("viewproj_fix", "false"); sh::Factory::getInstance ().setSharedParameter ("vpRow2Fix", sh::makeProperty (new sh::Vector4(0,0,0,0))); @@ -346,7 +346,7 @@ void RenderingManager::update (float duration, bool paused) MWWorld::Ptr player = world->getPlayerPtr(); - int blind = player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::Blind).getMagnitude(); + int blind = static_cast(player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::Blind).getMagnitude()); MWBase::Environment::get().getWindowManager()->setBlindness(std::max(0, std::min(100, blind))); setAmbientMode(); @@ -365,7 +365,7 @@ void RenderingManager::update (float duration, bool paused) btVector3 btOrig(orig.x, orig.y, orig.z); btVector3 btDest(dest.x, dest.y, dest.z); - std::pair test = mPhysicsEngine->sphereCast(mRendering.getCamera()->getNearClipDistance()*2.5, btOrig, btDest); + std::pair test = mPhysicsEngine->sphereCast(mRendering.getCamera()->getNearClipDistance()*2.5f, btOrig, btDest); if(test.first) mCamera->setCameraDistance(test.second * orig.distance(dest), false, false); } @@ -375,8 +375,8 @@ void RenderingManager::update (float duration, bool paused) bool isInAir = !world->isOnGround(player); bool isSwimming = world->isSwimming(player); - static const int i1stPersonSneakDelta = MWBase::Environment::get().getWorld()->getStore().get() - .find("i1stPersonSneakDelta")->getInt(); + static const float i1stPersonSneakDelta = MWBase::Environment::get().getWorld()->getStore().get() + .find("i1stPersonSneakDelta")->getFloat(); if(!paused && isSneaking && !(isSwimming || isInAir)) mCamera->setSneakOffset(i1stPersonSneakDelta); @@ -538,7 +538,7 @@ void RenderingManager::applyFog (bool underwater) } else { - Ogre::ColourValue clv(0.090195, 0.115685, 0.12745); + Ogre::ColourValue clv(0.090195f, 0.115685f, 0.12745f); mRendering.getScene()->setFog (FOG_LINEAR, Ogre::ColourValue(clv), 0, 0, 1000); mRendering.getViewport()->setBackgroundColour (Ogre::ColourValue(clv)); mWater->setViewportBackground (Ogre::ColourValue(clv)); @@ -598,9 +598,9 @@ void RenderingManager::setAmbientColour(const Ogre::ColourValue& colour) mAmbientColor = colour; MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - int nightEye = player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::NightEye).getMagnitude(); + int nightEye = static_cast(player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::NightEye).getMagnitude()); Ogre::ColourValue final = colour; - final += Ogre::ColourValue(0.7,0.7,0.7,0) * std::min(1.f, (nightEye/100.f)); + final += Ogre::ColourValue(0.7f,0.7f,0.7f,0) * std::min(1.f, (nightEye/100.f)); mRendering.getScene()->setAmbientLight(final); } @@ -662,7 +662,7 @@ void RenderingManager::requestMap(MWWorld::CellStore* cell) assert(mTerrain); Ogre::AxisAlignedBox dims = mObjects->getDimensions(cell); - Ogre::Vector2 center (cell->getCell()->getGridX() + 0.5, cell->getCell()->getGridY() + 0.5); + Ogre::Vector2 center (cell->getCell()->getGridX() + 0.5f, cell->getCell()->getGridY() + 0.5f); dims.merge(mTerrain->getWorldBoundingBox(center)); mLocalMap->requestMap(cell, dims.getMinimum().z, dims.getMaximum().z); @@ -714,8 +714,8 @@ Ogre::Vector4 RenderingManager::boundingBoxToScreen(Ogre::AxisAlignedBox bounds) // make 2D relative/normalized coords from the view-space vertex // by dividing out the Z (depth) factor -- this is an approximation - float x = corner.x / corner.z + 0.5; - float y = corner.y / corner.z + 0.5; + float x = corner.x / corner.z + 0.5f; + float y = corner.y / corner.z + 0.5f; if (x < min_x) min_x = x; diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index bb1bccc0a..f75061af4 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -107,7 +107,7 @@ void RippleSimulation::update(float dt, Ogre::Vector2 position) Ogre::Radian& rotation = created->rotation; #endif timeToLive = totalTimeToLive = mRippleLifeTime; - colour = Ogre::ColourValue(0.f, 0.f, 0.f, 0.7); // Water_RippleAlphas.x? + colour = Ogre::ColourValue(0.f, 0.f, 0.f, 0.7f); // Water_RippleAlphas.x? direction = Ogre::Vector3(0,0,0); position = currentPos; position.z = 0; // Z is set by the Scene Node diff --git a/apps/openmw/mwrender/shadows.cpp b/apps/openmw/mwrender/shadows.cpp index 5a6ccaca6..f2e60b11b 100644 --- a/apps/openmw/mwrender/shadows.cpp +++ b/apps/openmw/mwrender/shadows.cpp @@ -21,7 +21,7 @@ using namespace MWRender; Shadows::Shadows(OEngine::Render::OgreRenderer* rend) : mRendering(rend), mSceneMgr(rend->getScene()), mPSSMSetup(NULL), - mShadowFar(1000), mFadeStart(0.9) + mShadowFar(1000), mFadeStart(0.9f) { recreate(); } @@ -58,7 +58,7 @@ void Shadows::recreate() mSceneMgr->setShadowTexturePixelFormat(PF_FLOAT32_R); mSceneMgr->setShadowDirectionalLightExtrusionDistance(1000000); - mShadowFar = split ? Settings::Manager::getInt("split shadow distance", "Shadows") : Settings::Manager::getInt("shadow distance", "Shadows"); + mShadowFar = Settings::Manager::getFloat(split ? "split shadow distance" : "shadow distance", "Shadows"); mSceneMgr->setShadowFarDistance(mShadowFar); mFadeStart = Settings::Manager::getFloat("fade start", "Shadows"); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index f6287de5e..6e9684475 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -310,22 +310,22 @@ void SkyManager::create() // Create light used for thunderstorm mLightning = mSceneMgr->createLight(); mLightning->setType (Ogre::Light::LT_DIRECTIONAL); - mLightning->setDirection (Ogre::Vector3(0.3, -0.7, 0.3)); + mLightning->setDirection (Ogre::Vector3(0.3f, -0.7f, 0.3f)); mLightning->setVisible (false); mLightning->setDiffuseColour (ColourValue(3,3,3)); const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); - mSecunda = new Moon("secunda_texture", fallback->getFallbackFloat("Moons_Secunda_Size")/100, Vector3(-0.4, 0.4, 0.5), mRootNode, "openmw_moon"); + mSecunda = new Moon("secunda_texture", fallback->getFallbackFloat("Moons_Secunda_Size")/100, Vector3(-0.4f, 0.4f, 0.5f), mRootNode, "openmw_moon"); mSecunda->setType(Moon::Type_Secunda); mSecunda->setRenderQueue(RQG_SkiesEarly+4); - mMasser = new Moon("masser_texture", fallback->getFallbackFloat("Moons_Masser_Size")/100, Vector3(-0.4, 0.4, 0.5), mRootNode, "openmw_moon"); + mMasser = new Moon("masser_texture", fallback->getFallbackFloat("Moons_Masser_Size")/100, Vector3(-0.4f, 0.4f, 0.5f), mRootNode, "openmw_moon"); mMasser->setRenderQueue(RQG_SkiesEarly+3); mMasser->setType(Moon::Type_Masser); - mSun = new BillboardObject("textures\\tx_sun_05.dds", 1, Vector3(0.4, 0.4, 0.4), mRootNode, "openmw_sun"); + mSun = new BillboardObject("textures\\tx_sun_05.dds", 1, Vector3(0.4f, 0.4f, 0.4f), mRootNode, "openmw_sun"); mSun->setRenderQueue(RQG_SkiesEarly+4); - mSunGlare = new BillboardObject("textures\\tx_sun_flash_grey_05.dds", 3, Vector3(0.4, 0.4, 0.4), mRootNode, "openmw_sun"); + mSunGlare = new BillboardObject("textures\\tx_sun_flash_grey_05.dds", 3, Vector3(0.4f, 0.4f, 0.4f), mRootNode, "openmw_sun"); mSunGlare->setRenderQueue(RQG_SkiesLate); mSunGlare->setVisibilityFlags(RV_NoReflection); @@ -464,8 +464,8 @@ void SkyManager::updateRain(float dt) // TODO: handle rain settings from Morrowind.ini const float rangeRandom = 100; - float xOffs = (std::rand()/(RAND_MAX+1.0)) * rangeRandom - (rangeRandom/2); - float yOffs = (std::rand()/(RAND_MAX+1.0)) * rangeRandom - (rangeRandom/2); + float xOffs = (std::rand()/(RAND_MAX+1.0f)) * rangeRandom - (rangeRandom/2); + float yOffs = (std::rand()/(RAND_MAX+1.0f)) * rangeRandom - (rangeRandom/2); // Create a separate node to control the offset, since a node with setInheritOrientation(false) will still // consider the orientation of the parent node for its position, just not for its orientation @@ -680,9 +680,9 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) if (mCloudColour != weather.mSunColor) { - ColourValue clr( weather.mSunColor.r*0.7 + weather.mAmbientColor.r*0.7, - weather.mSunColor.g*0.7 + weather.mAmbientColor.g*0.7, - weather.mSunColor.b*0.7 + weather.mAmbientColor.b*0.7); + ColourValue clr( weather.mSunColor.r*0.7f + weather.mAmbientColor.r*0.7f, + weather.mSunColor.g*0.7f + weather.mAmbientColor.g*0.7f, + weather.mSunColor.b*0.7f + weather.mAmbientColor.b*0.7f); sh::Factory::getInstance().setSharedParameter ("cloudColour", sh::makeProperty(new sh::Vector3(clr.r, clr.g, clr.b))); @@ -774,7 +774,7 @@ void SkyManager::setSunDirection(const Vector3& direction, bool is_night) mSunGlare->setPosition(direction); float height = direction.z; - float fade = is_night ? 0.0 : (( height > 0.5) ? 1.0 : height * 2); + float fade = is_night ? 0.0f : (( height > 0.5) ? 1.0f : height * 2); sh::Factory::getInstance ().setSharedParameter ("waterSunFade_sunHeight", sh::makeProperty(new sh::Vector2(fade, height))); } @@ -836,7 +836,7 @@ void SkyManager::setSecundaFade(const float fade) void SkyManager::setHour(double hour) { - mHour = hour; + mHour = static_cast(hour); } void SkyManager::setDate(int day, int month) diff --git a/apps/openmw/mwrender/terrainstorage.cpp b/apps/openmw/mwrender/terrainstorage.cpp index e74b6af12..8ad2ea321 100644 --- a/apps/openmw/mwrender/terrainstorage.cpp +++ b/apps/openmw/mwrender/terrainstorage.cpp @@ -36,13 +36,13 @@ namespace MWRender for (; it != esmStore.get().extEnd(); ++it) { if (it->getGridX() < minX) - minX = it->getGridX(); + minX = static_cast(it->getGridX()); if (it->getGridX() > maxX) - maxX = it->getGridX(); + maxX = static_cast(it->getGridX()); if (it->getGridY() < minY) - minY = it->getGridY(); + minY = static_cast(it->getGridY()); if (it->getGridY() > maxY) - maxY = it->getGridY(); + maxY = static_cast(it->getGridY()); } // since grid coords are at cell origin, we need to add 1 cell diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 456fc47e9..a16b156ae 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -210,7 +210,8 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const MWWorld::Fallb int waterScale = 30; MeshManager::getSingleton().createPlane("water", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, mWaterPlane, - CELL_SIZE*5*waterScale, CELL_SIZE*5*waterScale, 40, 40, true, 1, 3*waterScale,3*waterScale, Vector3::UNIT_Y); + static_cast(CELL_SIZE*5*waterScale), static_cast(CELL_SIZE*5*waterScale), + 40, 40, true, 1, static_cast(3 * waterScale), static_cast(3 * waterScale), Vector3::UNIT_Y); mWater = mSceneMgr->createEntity("water"); mWater->setVisibilityFlags(RV_Water); @@ -284,7 +285,7 @@ void Water::setActive(bool active) mActive = active; updateVisible(); - sh::Factory::getInstance ().setSharedParameter ("waterEnabled", sh::makeProperty (new sh::FloatValue(active ? 1.0 : 0.0))); + sh::Factory::getInstance ().setSharedParameter ("waterEnabled", sh::makeProperty (new sh::FloatValue(active ? 1.0f : 0.0f))); } Water::~Water() @@ -351,7 +352,7 @@ Water::updateUnderwater(bool underwater) Vector3 Water::getSceneNodeCoordinates(int gridX, int gridY) { - return Vector3(gridX * CELL_SIZE + (CELL_SIZE / 2), gridY * CELL_SIZE + (CELL_SIZE / 2), mTop); + return Vector3(static_cast(gridX * CELL_SIZE + (CELL_SIZE / 2)), static_cast(gridY * CELL_SIZE + (CELL_SIZE / 2)), mTop); } void Water::setViewportBackground(const ColourValue& bg) diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 10d0a06ff..775950431 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -122,7 +122,7 @@ namespace MWRender { bool mIsUnderwater; bool mActive; bool mToggled; - int mTop; + float mTop; float mWaterTimer; diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index a3f935487..d6eb80265 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -107,7 +107,7 @@ namespace MWScript // discard additional arguments (reset), because we have no idea what they mean. for (unsigned int i=0; i(duration), x, y, z); ptr.getClass().getCreatureStats (ptr).getAiSequence().stack(escortPackage, ptr); std::cout << "AiEscort: " << x << ", " << y << ", " << z << ", " << duration @@ -145,7 +145,7 @@ namespace MWScript // discard additional arguments (reset), because we have no idea what they mean. for (unsigned int i=0; i(duration), x, y, z); ptr.getClass().getCreatureStats (ptr).getAiSequence().stack(escortPackage, ptr); std::cout << "AiEscort: " << x << ", " << y << ", " << z << ", " << duration @@ -177,13 +177,13 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - Interpreter::Type_Integer range = runtime[0].mFloat; + Interpreter::Type_Integer range = static_cast(runtime[0].mFloat); runtime.pop(); - Interpreter::Type_Integer duration = runtime[0].mFloat; + Interpreter::Type_Integer duration = static_cast(runtime[0].mFloat); runtime.pop(); - Interpreter::Type_Integer time = runtime[0].mFloat; + Interpreter::Type_Integer time = static_cast(runtime[0].mFloat); runtime.pop(); std::vector idleList; diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index c4e0b4261..a8c04aa4b 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -475,7 +475,7 @@ namespace MWScript for (int i=0; i<3; ++i) diff[i] = pos1[i] - pos2[i]; - return std::sqrt (diff[0]*diff[0] + diff[1]*diff[1] + diff[2]*diff[2]); + return static_cast(std::sqrt(diff[0] * diff[0] + diff[1] * diff[1] + diff[2] * diff[2])); } bool InterpreterContext::hasBeenActivated (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwscript/locals.cpp b/apps/openmw/mwscript/locals.cpp index 9dbf07fba..a18d0d5ae 100644 --- a/apps/openmw/mwscript/locals.cpp +++ b/apps/openmw/mwscript/locals.cpp @@ -63,7 +63,7 @@ namespace MWScript return mLongs.at (index); case 'f': - return mFloats.at (index); + return static_cast(mFloats.at(index)); default: return 0; } @@ -87,7 +87,7 @@ namespace MWScript mLongs.at (index) = val; break; case 'f': - mFloats.at (index) = val; break; + mFloats.at(index) = static_cast(val); break; } return true; } diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index f69031b2c..446be1cbc 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -312,7 +312,7 @@ namespace MWScript Interpreter::Type_Float time = runtime[0].mFloat; runtime.pop(); - MWBase::Environment::get().getWindowManager()->fadeScreenTo(alpha, time, false); + MWBase::Environment::get().getWindowManager()->fadeScreenTo(static_cast(alpha), time, false); } }; diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index b8bb76388..d825b085e 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -169,7 +169,7 @@ namespace MWScript if (mIndex==0 && ptr.getClass().hasItemHealth (ptr)) { // health is a special case - value = ptr.getClass().getItemMaxHealth (ptr); + value = static_cast(ptr.getClass().getItemMaxHealth(ptr)); } else { value = ptr.getClass() @@ -402,7 +402,7 @@ namespace MWScript MWBase::World *world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = world->getPlayerPtr(); - int bounty = runtime[0].mFloat; + int bounty = static_cast(runtime[0].mFloat); runtime.pop(); player.getClass().getNpcStats (player).setBounty(bounty); @@ -420,7 +420,7 @@ namespace MWScript MWBase::World *world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = world->getPlayerPtr(); - player.getClass().getNpcStats (player).setBounty(runtime[0].mFloat + player.getClass().getNpcStats (player).getBounty()); + player.getClass().getNpcStats(player).setBounty(static_cast(runtime[0].mFloat) + player.getClass().getNpcStats(player).getBounty()); runtime.pop(); } }; @@ -1195,11 +1195,10 @@ namespace MWScript float currentValue = stats.getMagicEffects().get(mPositiveEffect).getMagnitude(); if (mNegativeEffect != -1) currentValue -= stats.getMagicEffects().get(mNegativeEffect).getMagnitude(); - currentValue = int(currentValue); int arg = runtime[0].mInteger; runtime.pop(); - stats.getMagicEffects().modifyBase(mPositiveEffect, (arg - currentValue)); + stats.getMagicEffects().modifyBase(mPositiveEffect, (arg - static_cast(currentValue))); } }; diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 734df7d74..1ed5f0c30 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -332,7 +332,7 @@ namespace MWScript // except for when you position the player, then degrees must be used. // See "Morrowind Scripting for Dummies (9th Edition)" pages 50 and 54 for reference. if(ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) - zRot = zRot/60.; + zRot = zRot/60.0f; MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,zRot); ptr.getClass().adjustPosition(ptr, false); @@ -389,7 +389,7 @@ namespace MWScript // except for when you position the player, then degrees must be used. // See "Morrowind Scripting for Dummies (9th Edition)" pages 50 and 54 for reference. if(ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) - zRot = zRot/60.; + zRot = zRot/60.0f; MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,zRot); ptr.getClass().adjustPosition(ptr, false); } diff --git a/apps/openmw/mwsound/loudness.cpp b/apps/openmw/mwsound/loudness.cpp index c64913b1f..007791984 100644 --- a/apps/openmw/mwsound/loudness.cpp +++ b/apps/openmw/mwsound/loudness.cpp @@ -8,7 +8,7 @@ namespace MWSound void analyzeLoudness(const std::vector &data, int sampleRate, ChannelConfig chans, SampleType type, std::vector &out, float valuesPerSecond) { - int samplesPerSegment = sampleRate / valuesPerSecond; + int samplesPerSegment = static_cast(sampleRate / valuesPerSecond); int numSamples = bytesToFrames(data.size(), chans, type); int advance = framesToBytes(1, chans, type); diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index bc9478945..1b3dced80 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -801,7 +801,7 @@ const CachedSound& OpenAL_Output::getBuffer(const std::string &fname) decoder->close(); CachedSound cached; - analyzeLoudness(data, srate, chans, type, cached.mLoudnessVector, loudnessFPS); + analyzeLoudness(data, srate, chans, type, cached.mLoudnessVector, static_cast(loudnessFPS)); alGenBuffers(1, &buf); throwALerror(); @@ -885,7 +885,7 @@ MWBase::SoundPtr OpenAL_Output::playSound(const std::string &fname, float vol, f offset=1; alSourcei(src, AL_BUFFER, buf); - alSourcef(src, AL_SEC_OFFSET, sound->getLength()*offset/pitch); + alSourcef(src, AL_SEC_OFFSET, static_cast(sound->getLength()*offset / pitch)); alSourcePlay(src); throwALerror(); @@ -910,7 +910,7 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre sound.reset(new OpenAL_Sound3D(*this, src, buf, pos, vol, basevol, pitch, min, max, flags)); if (extractLoudness) - sound->setLoudnessVector(cached.mLoudnessVector, loudnessFPS); + sound->setLoudnessVector(cached.mLoudnessVector, static_cast(loudnessFPS)); } catch(std::exception&) { @@ -929,7 +929,7 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre offset=1; alSourcei(src, AL_BUFFER, buf); - alSourcef(src, AL_SEC_OFFSET, sound->getLength()*offset/pitch); + alSourcef(src, AL_SEC_OFFSET, static_cast(sound->getLength()*offset / pitch)); alSourcePlay(src); throwALerror(); diff --git a/apps/openmw/mwsound/sound.cpp b/apps/openmw/mwsound/sound.cpp index b3105a82c..8b6bfda82 100644 --- a/apps/openmw/mwsound/sound.cpp +++ b/apps/openmw/mwsound/sound.cpp @@ -7,7 +7,7 @@ namespace MWSound { if (mLoudnessVector.empty()) return 0.f; - int index = getTimeOffset() * mLoudnessFPS; + int index = static_cast(getTimeOffset() * mLoudnessFPS); index = std::max(0, std::min(index, int(mLoudnessVector.size()-1))); diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 0bc155118..b3978f9d5 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -106,7 +106,7 @@ namespace MWSound MWBase::World* world = MWBase::Environment::get().getWorld(); const ESM::Sound *snd = world->getStore().get().find(soundId); - volume *= pow(10.0, (snd->mData.mVolume/255.0*3348.0 - 3348.0) / 2000.0); + volume *= static_cast(pow(10.0, (snd->mData.mVolume / 255.0*3348.0 - 3348.0) / 2000.0)); if(snd->mData.mMinRange == 0 && snd->mData.mMaxRange == 0) { @@ -559,7 +559,7 @@ namespace MWSound if(!cell->isExterior() || sTimePassed < sTimeToNextEnvSound) return; - float a = std::rand() / (double)RAND_MAX; + float a = std::rand() / static_cast(RAND_MAX); // NOTE: We should use the "Minimum Time Between Environmental Sounds" and // "Maximum Time Between Environmental Sounds" fallback settings here. sTimeToNextEnvSound = 5.0f*a + 15.0f*(1.0f-a); diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index c2906e447..8ef6799ba 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -185,7 +185,7 @@ bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2) { const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find( ptr1.getClass().getEnchantment(ptr1)); - float maxCharge = enchantment->mData.mCharge; + float maxCharge = static_cast(enchantment->mData.mCharge); float enchantCharge1 = ptr1.getCellRef().getEnchantmentCharge() == -1 ? maxCharge : ptr1.getCellRef().getEnchantmentCharge(); float enchantCharge2 = ptr2.getCellRef().getEnchantmentCharge() == -1 ? maxCharge : ptr2.getCellRef().getEnchantmentCharge(); if (enchantCharge1 != maxCharge || enchantCharge2 != maxCharge) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 36c198f01..5d9beecb6 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -124,7 +124,7 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener) mIds[Misc::StringUtils::lowerCase (id)] = n.val; } } - listener->setProgress(esm.getFileOffset() / (float)esm.getFileSize() * 1000); + listener->setProgress(static_cast(esm.getFileOffset() / (float)esm.getFileSize() * 1000)); } } diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 8f3560a69..58718074e 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -97,13 +97,13 @@ namespace MWWorld if (mAutoMove) value = 1; - ptr.getClass().getMovementSettings (ptr).mPosition[1] = value; + ptr.getClass().getMovementSettings(ptr).mPosition[1] = static_cast(value); } void Player::setLeftRight (int value) { MWWorld::Ptr ptr = getPlayer(); - ptr.getClass().getMovementSettings (ptr).mPosition[0] = value; + ptr.getClass().getMovementSettings(ptr).mPosition[0] = static_cast(value); } void Player::setForwardBackward (int value) @@ -115,13 +115,13 @@ namespace MWWorld if (mAutoMove) value = 1; - ptr.getClass().getMovementSettings (ptr).mPosition[1] = value; + ptr.getClass().getMovementSettings(ptr).mPosition[1] = static_cast(value); } void Player::setUpDown(int value) { MWWorld::Ptr ptr = getPlayer(); - ptr.getClass().getMovementSettings (ptr).mPosition[2] = value; + ptr.getClass().getMovementSettings(ptr).mPosition[2] = static_cast(value); } void Player::setRunState(bool run) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index c97e4e3a5..acbe819f1 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -68,7 +68,7 @@ namespace MWWorld { float height = 0; if (OEngine::Physic::PhysicActor* actor = mPhysEngine.getCharacter(caster.getRefData().getHandle())) - height = actor->getHalfExtents().z * 2 * 0.75; // Spawn at 0.75 * ActorHeight + height = actor->getHalfExtents().z * 2 * 0.75f; // Spawn at 0.75 * ActorHeight Ogre::Vector3 pos(caster.getRefData().getPosition().pos); pos.z += height; diff --git a/apps/openmw/mwworld/timestamp.cpp b/apps/openmw/mwworld/timestamp.cpp index a73ed7ca5..bd07b91f3 100644 --- a/apps/openmw/mwworld/timestamp.cpp +++ b/apps/openmw/mwworld/timestamp.cpp @@ -33,7 +33,7 @@ namespace MWWorld mHour = static_cast (std::fmod (hours, 24)); - mDay += hours / 24; + mDay += static_cast(hours / 24); return *this; } diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 4440ed030..69495cdd2 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -142,7 +142,7 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fa * These values are fallbacks attached to weather. */ mNightStart = mSunsetTime + mSunsetDuration; - mNightEnd = mSunriseTime - 0.5; + mNightEnd = mSunriseTime - 0.5f; mDayStart = mSunriseTime + mSunriseDuration; mDayEnd = mSunsetTime; @@ -368,7 +368,7 @@ void WeatherManager::transition(float factor) mResult.mParticleEffect = other.mParticleEffect; mResult.mRainSpeed = other.mRainSpeed; mResult.mRainFrequency = other.mRainFrequency; - mResult.mAmbientSoundVolume = 2*(factor-0.5); + mResult.mAmbientSoundVolume = 2*(factor-0.5f); mResult.mEffectFade = mResult.mAmbientSoundVolume; mResult.mAmbientLoopSoundID = other.mAmbientLoopSoundID; } @@ -376,7 +376,7 @@ void WeatherManager::transition(float factor) void WeatherManager::update(float duration, bool paused) { - float timePassed = mTimePassed; + float timePassed = static_cast(mTimePassed); mTimePassed = 0; mWeatherUpdateTime -= timePassed; @@ -454,9 +454,9 @@ void WeatherManager::update(float duration, bool paused) } Vector3 final( - cos( theta ), + static_cast(cos(theta)), -0.268f, // approx tan( -15 degrees ) - sin( theta ) ); + static_cast(sin(theta))); mRendering->setSunDirection( final, is_night ); } @@ -488,8 +488,8 @@ void WeatherManager::update(float duration, bool paused) moonHeight); Vector3 secunda( - (moonHeight - 1) * facing * 1.25, - (1 - moonHeight) * facing * 0.8, + (moonHeight - 1) * facing * 1.25f, + (1 - moonHeight) * facing * 0.8f, moonHeight); mRendering->getSkyManager()->setMasserDirection(masser); @@ -542,7 +542,7 @@ void WeatherManager::update(float duration, bool paused) mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); else { - mThunderChanceNeeded = rand() % 100; + mThunderChanceNeeded = static_cast(rand() % 100); mThunderChance = 0; mRendering->getSkyManager()->setLightningStrength( 0.f ); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 3ef4f8e81..ebd756781 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -570,9 +570,9 @@ namespace MWWorld if (name=="gamehour") setHour (value); else if (name=="day") - setDay (value); + setDay(static_cast(value)); else if (name=="month") - setMonth (value); + setMonth(static_cast(value)); else mGlobalVariables[name].setFloat (value); } @@ -800,7 +800,7 @@ namespace MWWorld void World::advanceTime (double hours) { - MWBase::Environment::get().getMechanicsManager()->advanceTime(hours*3600); + MWBase::Environment::get().getMechanicsManager()->advanceTime(static_cast(hours * 3600)); mWeatherManager->advanceTime (hours); @@ -808,7 +808,7 @@ namespace MWWorld setHour (hours); - int days = hours / 24; + int days = static_cast(hours / 24); if (days>0) mGlobalVariables["dayspassed"].setInteger ( @@ -820,15 +820,15 @@ namespace MWWorld if (hour<0) hour = 0; - int days = hour / 24; + int days = static_cast(hour / 24); hour = std::fmod (hour, 24); - mGlobalVariables["gamehour"].setFloat (hour); + mGlobalVariables["gamehour"].setFloat(static_cast(hour)); mRendering->skySetHour (hour); - mWeatherManager->setHour (hour); + mWeatherManager->setHour(static_cast(hour)); if (days>0) setDay (days + mGlobalVariables["day"].getInteger()); @@ -1015,25 +1015,9 @@ namespace MWWorld float World::getMaxActivationDistance () { if (mActivationDistanceOverride >= 0) - return mActivationDistanceOverride; - - return (std::max) (getNpcActivationDistance (), getObjectActivationDistance ()); - } - - float World::getNpcActivationDistance () - { - if (mActivationDistanceOverride >= 0) - return mActivationDistanceOverride; - - return getStore().get().find ("iMaxActivateDist")->getInt()*5/4; - } - - float World::getObjectActivationDistance () - { - if (mActivationDistanceOverride >= 0) - return mActivationDistanceOverride; + return static_cast(mActivationDistanceOverride); - return getStore().get().find ("iMaxActivateDist")->getInt(); + return getStore().get().find("iMaxActivateDist")->getFloat() * 5 / 4; } MWWorld::Ptr World::getFacedObject() @@ -1387,8 +1371,8 @@ namespace MWWorld { const int cellSize = 8192; - x = cellSize * cellX; - y = cellSize * cellY; + x = static_cast(cellSize * cellX); + y = static_cast(cellSize * cellY); if (centre) { @@ -1401,8 +1385,8 @@ namespace MWWorld { const int cellSize = 8192; - cellX = std::floor(x/cellSize); - cellY = std::floor(y/cellSize); + cellX = static_cast(std::floor(x / cellSize)); + cellY = static_cast(std::floor(y / cellSize)); } void World::queueMovement(const Ptr &ptr, const Vector3 &velocity) @@ -1621,7 +1605,7 @@ namespace MWWorld { Ogre::Vector3 playerPos = mPlayer->getPlayer().getRefData().getBaseNode()->getPosition(); const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(getPlayerPtr().getRefData().getHandle()); - if(actor) playerPos.z += 1.85*actor->getHalfExtents().z; + if(actor) playerPos.z += 1.85f * actor->getHalfExtents().z; Ogre::Quaternion playerOrient = Ogre::Quaternion(Ogre::Radian(getPlayerPtr().getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * Ogre::Quaternion(Ogre::Radian(getPlayerPtr().getRefData().getPosition().rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X) * Ogre::Quaternion(Ogre::Radian(getPlayerPtr().getRefData().getPosition().rot[1]), Ogre::Vector3::NEGATIVE_UNIT_Y); @@ -2013,7 +1997,7 @@ namespace MWWorld bool World::isSubmerged(const MWWorld::Ptr &object) const { - return isUnderwater(object, 1.0/mSwimHeightScale); + return isUnderwater(object, 1.0f/mSwimHeightScale); } bool World::isSwimming(const MWWorld::Ptr &object) const @@ -2371,8 +2355,8 @@ namespace MWWorld Ogre::Vector3 halfExt2 = actor2->getHalfExtents(); const float* pos2 = targetActor.getRefData().getPosition().pos; - btVector3 from(pos1[0],pos1[1],pos1[2]+halfExt1.z*2*0.9); // eye level - btVector3 to(pos2[0],pos2[1],pos2[2]+halfExt2.z*2*0.9); + btVector3 from(pos1[0],pos1[1],pos1[2]+halfExt1.z*2*0.9f); // eye level + btVector3 to(pos2[0],pos2[1],pos2[2]+halfExt2.z*2*0.9f); std::pair result = mPhysEngine->rayTest(from, to,false); if(result.first == "") return true; @@ -2591,7 +2575,7 @@ namespace MWWorld const Store &gmst = getStore().get(); MWMechanics::NpcStats &stats = actor.getClass().getNpcStats(actor); - stats.getSkill(ESM::Skill::Acrobatics).setBase(gmst.find("fWerewolfAcrobatics")->getFloat()); + stats.getSkill(ESM::Skill::Acrobatics).setBase(gmst.find("fWerewolfAcrobatics")->getInt()); } bool World::getGodModeState() @@ -3071,8 +3055,8 @@ namespace MWWorld float fCrimeGoldDiscountMult = getStore().get().find("fCrimeGoldDiscountMult")->getFloat(); float fCrimeGoldTurnInMult = getStore().get().find("fCrimeGoldTurnInMult")->getFloat(); - int discount = bounty * fCrimeGoldDiscountMult; - int turnIn = bounty * fCrimeGoldTurnInMult; + int discount = static_cast(bounty * fCrimeGoldDiscountMult); + int turnIn = static_cast(bounty * fCrimeGoldTurnInMult); if (bounty > 0) { @@ -3153,7 +3137,7 @@ namespace MWWorld const ESM::CreatureLevList* list = getStore().get().find(creatureList); int iNumberCreatures = getStore().get().find("iNumberCreatures")->getInt(); - int numCreatures = 1 + std::rand()/ (static_cast (RAND_MAX) + 1) * iNumberCreatures; // [1, iNumberCreatures] + int numCreatures = static_cast(1 + std::rand() / (static_cast (RAND_MAX)+1) * iNumberCreatures); // [1, iNumberCreatures] for (int i=0; i (RAND_MAX) + 1) * 3; // [0, 2] + int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 3); // [0, 2] modelName << roll; std::string model = "meshes\\" + getFallback()->getFallbackString(modelName.str()); @@ -3235,7 +3219,7 @@ namespace MWWorld else areaStatic = getStore().get().find ("VFX_DefaultArea"); - mRendering->spawnEffect("meshes\\" + areaStatic->mModel, "", origin, effectIt->mArea); + mRendering->spawnEffect("meshes\\" + areaStatic->mModel, "", origin, static_cast(effectIt->mArea)); // Play explosion sound (make sure to use NoTrack, since we will delete the projectile now) static const std::string schools[] = { @@ -3251,7 +3235,7 @@ namespace MWWorld // Get the actors in range of the effect std::vector objects; MWBase::Environment::get().getMechanicsManager()->getObjectsInRange( - origin, feetToGameUnits(effectIt->mArea), objects); + origin, feetToGameUnits(static_cast(effectIt->mArea)), objects); for (std::vector::iterator affected = objects.begin(); affected != objects.end(); ++affected) toApply[*affected].push_back(*effectIt); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 1db86f738..63d6506de 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -115,9 +115,6 @@ namespace MWWorld void performUpdateSceneQueries (); void getFacedHandle(std::string& facedHandle, float maxDistance, bool ignorePlayer=true); - float getNpcActivationDistance (); - float getObjectActivationDistance (); - void removeContainerScripts(const Ptr& reference); void addContainerScripts(const Ptr& reference, CellStore* cell); void PCDropped (const Ptr& item); diff --git a/components/esm/loadpgrd.cpp b/components/esm/loadpgrd.cpp index 61f56b511..fc0974c9d 100644 --- a/components/esm/loadpgrd.cpp +++ b/components/esm/loadpgrd.cpp @@ -10,22 +10,22 @@ namespace ESM Pathgrid::Point& Pathgrid::Point::operator=(const float rhs[3]) { - mX = rhs[0]; - mY = rhs[1]; - mZ = rhs[2]; + mX = static_cast(rhs[0]); + mY = static_cast(rhs[1]); + mZ = static_cast(rhs[2]); mAutogenerated = 0; mConnectionNum = 0; mUnknown = 0; return *this; } Pathgrid::Point::Point(const float rhs[3]) - : mAutogenerated(0), + : mX(static_cast(rhs[0])), + mY(static_cast(rhs[1])), + mZ(static_cast(rhs[2])), + mAutogenerated(0), mConnectionNum(0), mUnknown(0) { - mX = rhs[0]; - mY = rhs[1]; - mZ = rhs[2]; } Pathgrid::Point::Point():mX(0),mY(0),mZ(0),mAutogenerated(0), mConnectionNum(0),mUnknown(0) diff --git a/components/esm/loadrace.cpp b/components/esm/loadrace.cpp index 967c0d0d7..e88454d4c 100644 --- a/components/esm/loadrace.cpp +++ b/components/esm/loadrace.cpp @@ -15,7 +15,7 @@ namespace ESM int Race::MaleFemaleF::getValue (bool male) const { - return male ? mMale : mFemale; + return static_cast(male ? mMale : mFemale); } void Race::load(ESMReader &esm) diff --git a/components/esm/statstate.hpp b/components/esm/statstate.hpp index 801d0ce82..f57ba9f30 100644 --- a/components/esm/statstate.hpp +++ b/components/esm/statstate.hpp @@ -40,7 +40,7 @@ namespace ESM // mDamage was changed to a float; ensure backwards compatibility T oldDamage = 0; esm.getHNOT(oldDamage, "STDA"); - mDamage = oldDamage; + mDamage = static_cast(oldDamage); esm.getHNOT (mDamage, "STDF"); diff --git a/components/esm/variantimp.cpp b/components/esm/variantimp.cpp index fd068fc19..eeb0bf04f 100644 --- a/components/esm/variantimp.cpp +++ b/components/esm/variantimp.cpp @@ -128,7 +128,7 @@ int ESM::VariantIntegerData::getInteger (bool default_) const float ESM::VariantIntegerData::getFloat (bool default_) const { - return mValue; + return static_cast(mValue); } void ESM::VariantIntegerData::setInteger (int value) @@ -202,7 +202,7 @@ void ESM::VariantIntegerData::write (ESMWriter& esm, Variant::Format format, Var { if (type==VT_Short || type==VT_Long) { - float value = mValue; + float value = static_cast(mValue); esm.writeHNString ("FNAM", type==VT_Short ? "s" : "l"); esm.writeHNT ("FLTV", value); } @@ -262,7 +262,7 @@ float ESM::VariantFloatData::getFloat (bool default_) const void ESM::VariantFloatData::setInteger (int value) { - mValue = value; + mValue = static_cast(value); } void ESM::VariantFloatData::setFloat (float value) diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index 9c7beebce..763f0f4e0 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -27,8 +27,8 @@ namespace ESMTerrain assert(origin.x == (int) origin.x); assert(origin.y == (int) origin.y); - int cellX = origin.x; - int cellY = origin.y; + int cellX = static_cast(origin.x); + int cellY = static_cast(origin.y); const ESM::Land* land = getLand(cellX, cellY); if (!land || !(land->mDataTypes&ESM::Land::DATA_VHGT)) @@ -135,10 +135,10 @@ namespace ESMTerrain assert(origin.x == (int) origin.x); assert(origin.y == (int) origin.y); - int startX = origin.x; - int startY = origin.y; + int startX = static_cast(origin.x); + int startY = static_cast(origin.y); - size_t numVerts = size*(ESM::Land::LAND_SIZE-1)/increment + 1; + size_t numVerts = static_cast(size*(ESM::Land::LAND_SIZE - 1) / increment + 1); colours.resize(numVerts*numVerts*4); positions.resize(numVerts*numVerts*3); @@ -175,12 +175,12 @@ namespace ESMTerrain vertX = vertX_; for (int row=rowStart; row(vertX*numVerts * 3 + vertY * 3)] = ((vertX / float(numVerts - 1) - 0.5f) * size * 8192); + positions[static_cast(vertX*numVerts * 3 + vertY * 3 + 1)] = ((vertY / float(numVerts - 1) - 0.5f) * size * 8192); if (land) - positions[vertX*numVerts*3 + vertY*3 + 2] = land->mLandData->mHeights[col*ESM::Land::LAND_SIZE+row]; + positions[static_cast(vertX*numVerts * 3 + vertY * 3 + 2)] = land->mLandData->mHeights[col*ESM::Land::LAND_SIZE + row]; else - positions[vertX*numVerts*3 + vertY*3 + 2] = -2048; + positions[static_cast(vertX*numVerts * 3 + vertY * 3 + 2)] = -2048; if (land && land->mDataTypes&ESM::Land::DATA_VNML) { @@ -202,9 +202,9 @@ namespace ESMTerrain assert(normal.z > 0); - normals[vertX*numVerts*3 + vertY*3] = normal.x; - normals[vertX*numVerts*3 + vertY*3 + 1] = normal.y; - normals[vertX*numVerts*3 + vertY*3 + 2] = normal.z; + normals[static_cast(vertX*numVerts * 3 + vertY * 3)] = normal.x; + normals[static_cast(vertX*numVerts * 3 + vertY * 3 + 1)] = normal.y; + normals[static_cast(vertX*numVerts * 3 + vertY * 3 + 2)] = normal.z; if (land && land->mDataTypes&ESM::Land::DATA_VCLR) { @@ -226,7 +226,7 @@ namespace ESMTerrain color.a = 1; Ogre::uint32 rsColor; Ogre::Root::getSingleton().getRenderSystem()->convertColourValue(color, &rsColor); - memcpy(&colours[vertX*numVerts*4 + vertY*4], &rsColor, sizeof(Ogre::uint32)); + memcpy(&colours[static_cast(vertX*numVerts * 4 + vertY * 4)], &rsColor, sizeof(Ogre::uint32)); ++vertX; } @@ -293,7 +293,7 @@ namespace ESMTerrain { out.push_back(Terrain::LayerCollection()); out.back().mTarget = *it; - getBlendmapsImpl((*it)->getSize(), (*it)->getCenter(), pack, out.back().mBlendmaps, out.back().mLayers); + getBlendmapsImpl(static_cast((*it)->getSize()), (*it)->getCenter(), pack, out.back().mBlendmaps, out.back().mLayers); } } @@ -311,8 +311,8 @@ namespace ESMTerrain // and interpolate the rest of the cell by hand? :/ Ogre::Vector2 origin = chunkCenter - Ogre::Vector2(chunkSize/2.f, chunkSize/2.f); - int cellX = origin.x; - int cellY = origin.y; + int cellX = static_cast(origin.x); + int cellY = static_cast(origin.y); // Save the used texture indices so we know the total number of textures // and number of required blend maps @@ -343,7 +343,7 @@ namespace ESMTerrain int numTextures = textureIndices.size(); // numTextures-1 since the base layer doesn't need blending - int numBlendmaps = pack ? std::ceil((numTextures-1) / 4.f) : (numTextures-1); + int numBlendmaps = pack ? static_cast(std::ceil((numTextures - 1) / 4.f)) : (numTextures - 1); int channels = pack ? 4 : 1; @@ -364,7 +364,7 @@ namespace ESMTerrain { UniqueTextureId id = getVtexIndexAt(cellX, cellY, x, y); int layerIndex = textureIndicesMap.find(id)->second; - int blendIndex = (pack ? std::floor((layerIndex-1)/4.f) : layerIndex-1); + int blendIndex = (pack ? static_cast(std::floor((layerIndex - 1) / 4.f)) : layerIndex - 1); int channel = pack ? std::max(0, (layerIndex-1) % 4) : 0; if (blendIndex == i) @@ -379,8 +379,8 @@ namespace ESMTerrain float Storage::getHeightAt(const Ogre::Vector3 &worldPos) { - int cellX = std::floor(worldPos.x / 8192.f); - int cellY = std::floor(worldPos.y / 8192.f); + int cellX = static_cast(std::floor(worldPos.x / 8192.f)); + int cellY = static_cast(std::floor(worldPos.y / 8192.f)); ESM::Land* land = getLand(cellX, cellY); if (!land || !(land->mDataTypes&ESM::Land::DATA_VHGT)) @@ -519,7 +519,7 @@ namespace ESMTerrain float Storage::getCellWorldSize() { - return ESM::Land::REAL_SIZE; + return static_cast(ESM::Land::REAL_SIZE); } int Storage::getCellVertices() diff --git a/components/fontloader/fontloader.cpp b/components/fontloader/fontloader.cpp index 17c630fd9..0ca37ad11 100644 --- a/components/fontloader/fontloader.cpp +++ b/components/fontloader/fontloader.cpp @@ -288,7 +288,7 @@ namespace Gui code->addAttribute("advance", data[i].width); code->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " " + MyGUI::utility::toString((fontSize-data[i].ascent))); - code->addAttribute("size", MyGUI::IntSize(data[i].width, data[i].height)); + code->addAttribute("size", MyGUI::IntSize(static_cast(data[i].width), static_cast(data[i].height))); // More hacks! The french game uses several win1252 characters that are not included // in the cp437 encoding of the font. Fall back to similar available characters. @@ -334,7 +334,7 @@ namespace Gui code->addAttribute("advance", data[i].width); code->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " " + MyGUI::utility::toString((fontSize-data[i].ascent))); - code->addAttribute("size", MyGUI::IntSize(data[i].width, data[i].height)); + code->addAttribute("size", MyGUI::IntSize(static_cast(data[i].width), static_cast(data[i].height))); } } @@ -350,7 +350,7 @@ namespace Gui cursorCode->addAttribute("advance", data[i].width); cursorCode->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " " + MyGUI::utility::toString((fontSize-data[i].ascent))); - cursorCode->addAttribute("size", MyGUI::IntSize(data[i].width, data[i].height)); + cursorCode->addAttribute("size", MyGUI::IntSize(static_cast(data[i].width), static_cast(data[i].height))); } // Question mark, use for NotDefined marker (used for glyphs not existing in the font) @@ -365,7 +365,7 @@ namespace Gui cursorCode->addAttribute("advance", data[i].width); cursorCode->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " " + MyGUI::utility::toString((fontSize-data[i].ascent))); - cursorCode->addAttribute("size", MyGUI::IntSize(data[i].width, data[i].height)); + cursorCode->addAttribute("size", MyGUI::IntSize(static_cast(data[i].width), static_cast(data[i].height))); } } diff --git a/components/terrain/defaultworld.cpp b/components/terrain/defaultworld.cpp index e14c64f3a..c6f0f7136 100644 --- a/components/terrain/defaultworld.cpp +++ b/components/terrain/defaultworld.cpp @@ -108,8 +108,8 @@ namespace Terrain storage->getBounds(mMinX, mMaxX, mMinY, mMaxY); - int origSizeX = mMaxX-mMinX; - int origSizeY = mMaxY-mMinY; + int origSizeX = static_cast(mMaxX - mMinX); + int origSizeY = static_cast(mMaxY - mMinY); // Dividing a quad tree only works well for powers of two, so round up to the nearest one int size = nextPowerOfTwo(std::max(origSizeX, origSizeY)); @@ -124,7 +124,7 @@ namespace Terrain LayersRequestData data; data.mPack = getShadersEnabled(); - mRootNode = new QuadTreeNode(this, Root, size, Ogre::Vector2(centerX, centerY), NULL); + mRootNode = new QuadTreeNode(this, Root, static_cast(size), Ogre::Vector2(centerX, centerY), NULL); buildQuadTree(mRootNode, data.mNodes); //loadingListener->indicateProgress(); mRootNode->initAabb(); @@ -160,7 +160,7 @@ namespace Terrain float minZ,maxZ; Ogre::Vector2 center = node->getCenter(); float cellWorldSize = getStorage()->getCellWorldSize(); - if (mStorage->getMinMaxHeights(node->getSize(), center, minZ, maxZ)) + if (mStorage->getMinMaxHeights(static_cast(node->getSize()), center, minZ, maxZ)) { Ogre::AxisAlignedBox bounds(Ogre::Vector3(-halfSize*cellWorldSize, -halfSize*cellWorldSize, minZ), Ogre::Vector3(halfSize*cellWorldSize, halfSize*cellWorldSize, maxZ)); @@ -275,7 +275,7 @@ namespace Terrain LoadResponseData* responseData = new LoadResponseData(); - getStorage()->fillVertexBuffers(node->getNativeLodLevel(), node->getSize(), node->getCenter(), getAlign(), + getStorage()->fillVertexBuffers(node->getNativeLodLevel(), static_cast(node->getSize()), node->getCenter(), getAlign(), responseData->mPositions, responseData->mNormals, responseData->mColours); return OGRE_NEW Ogre::WorkQueue::Response(req, true, Ogre::Any(responseData)); diff --git a/components/terrain/defaultworld.hpp b/components/terrain/defaultworld.hpp index 90e8cc2b6..4caef8462 100644 --- a/components/terrain/defaultworld.hpp +++ b/components/terrain/defaultworld.hpp @@ -84,7 +84,7 @@ namespace Terrain /// adding or removing passes. This can only be achieved by a full rebuild.) virtual void applyMaterials(bool shadows, bool splitShadows); - int getMaxBatchSize() { return mMaxBatchSize; } + int getMaxBatchSize() { return static_cast(mMaxBatchSize); } /// Wait until all background loading is complete. void syncLoad(); diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index 4ff04ab93..4d2318aa6 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -36,7 +36,7 @@ namespace int getBlendmapIndexForLayer (int layerIndex) { - return std::floor((layerIndex-1)/4.f); + return static_cast(std::floor((layerIndex - 1) / 4.f)); } std::string getBlendmapComponentForLayer (int layerIndex) diff --git a/components/terrain/quadtreenode.cpp b/components/terrain/quadtreenode.cpp index 5fce5eae9..6a9964213 100644 --- a/components/terrain/quadtreenode.cpp +++ b/components/terrain/quadtreenode.cpp @@ -135,7 +135,7 @@ QuadTreeNode::QuadTreeNode(DefaultWorld* terrain, ChildDirection dir, float size : mMaterialGenerator(NULL) , mIsDummy(false) , mSize(size) - , mLodLevel(Log2(mSize)) + , mLodLevel(Log2(static_cast(mSize))) , mBounds(Ogre::AxisAlignedBox::BOX_NULL) , mWorldBounds(Ogre::AxisAlignedBox::BOX_NULL) , mDirection(dir) diff --git a/components/terrain/quadtreenode.hpp b/components/terrain/quadtreenode.hpp index 1ecd6fcd5..e44b64600 100644 --- a/components/terrain/quadtreenode.hpp +++ b/components/terrain/quadtreenode.hpp @@ -95,7 +95,7 @@ namespace Terrain Ogre::SceneNode* getSceneNode() { return mSceneNode; } - int getSize() { return mSize; } + int getSize() { return static_cast(mSize); } Ogre::Vector2 getCenter() { return mCenter; } bool hasChildren() { return mChildren[0] != 0; } diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 269152e61..bb99ca23e 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -56,16 +56,16 @@ void TerrainGrid::loadCell(int x, int y) if (mGrid.find(std::make_pair(x, y)) != mGrid.end()) return; // already loaded - Ogre::Vector2 center(x+0.5, y+0.5); + Ogre::Vector2 center(x+0.5f, y+0.5f); float minH, maxH; if (!mStorage->getMinMaxHeights(1, center, minH, maxH)) return; // no terrain defined - Ogre::Vector3 min (-0.5*mStorage->getCellWorldSize(), - -0.5*mStorage->getCellWorldSize(), + Ogre::Vector3 min (-0.5f*mStorage->getCellWorldSize(), + -0.5f*mStorage->getCellWorldSize(), minH); - Ogre::Vector3 max (0.5*mStorage->getCellWorldSize(), - 0.5*mStorage->getCellWorldSize(), + Ogre::Vector3 max (0.5f*mStorage->getCellWorldSize(), + 0.5f*mStorage->getCellWorldSize(), maxH); Ogre::AxisAlignedBox bounds(min, max); @@ -163,8 +163,8 @@ void TerrainGrid::setVisible(bool visible) Ogre::AxisAlignedBox TerrainGrid::getWorldBoundingBox (const Ogre::Vector2& center) { - int cellX = std::floor(center.x); - int cellY = std::floor(center.y); + int cellX = static_cast(std::floor(center.x)); + int cellY = static_cast(std::floor(center.y)); Grid::iterator it = mGrid.find(std::make_pair(cellX, cellY)); if (it == mGrid.end()) diff --git a/components/widgets/list.cpp b/components/widgets/list.cpp index f3d3a2c28..8517a0303 100644 --- a/components/widgets/list.cpp +++ b/components/widgets/list.cpp @@ -138,10 +138,10 @@ namespace Gui void MWList::onMouseWheel(MyGUI::Widget* _sender, int _rel) { //NB view offset is negative - if (mScrollView->getViewOffset().top + _rel*0.3 > 0) + if (mScrollView->getViewOffset().top + _rel*0.3f > 0) mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); else - mScrollView->setViewOffset(MyGUI::IntPoint(0, mScrollView->getViewOffset().top + _rel*0.3)); + mScrollView->setViewOffset(MyGUI::IntPoint(0, static_cast(mScrollView->getViewOffset().top + _rel*0.3))); } void MWList::onItemSelected(MyGUI::Widget* _sender) diff --git a/extern/sdl4ogre/sdlcursormanager.cpp b/extern/sdl4ogre/sdlcursormanager.cpp index 7623d57db..fab9051e7 100644 --- a/extern/sdl4ogre/sdlcursormanager.cpp +++ b/extern/sdl4ogre/sdlcursormanager.cpp @@ -91,7 +91,7 @@ namespace SFO // we use a render target to uncompress the DDS texture // just blitting doesn't seem to work on D3D9 - OEngine::Render::ImageRotate::rotate(tex->getName(), tempName, -rotDegrees); + OEngine::Render::ImageRotate::rotate(tex->getName(), tempName, static_cast(-rotDegrees)); Ogre::TexturePtr resultTexture = Ogre::TextureManager::getSingleton().getByName(tempName); @@ -110,7 +110,8 @@ namespace SFO Ogre::ColourValue clr = destImage.getColourAt(x, y, 0); //set the pixel on the SDL surface to the same value as the Ogre texture's - _putPixel(surf, x, y, SDL_MapRGBA(surf->format, clr.r*255, clr.g*255, clr.b*255, clr.a*255)); + _putPixel(surf, x, y, SDL_MapRGBA(surf->format, static_cast(clr.r * 255), + static_cast(clr.g * 255), static_cast(clr.b * 255), static_cast(clr.a * 255))); } } diff --git a/extern/sdl4ogre/sdlwindowhelper.cpp b/extern/sdl4ogre/sdlwindowhelper.cpp index 44993947f..637fae0ef 100644 --- a/extern/sdl4ogre/sdlwindowhelper.cpp +++ b/extern/sdl4ogre/sdlwindowhelper.cpp @@ -93,7 +93,8 @@ void SDLWindowHelper::setWindowIcon(const std::string &name) int bpp = surface->format->BytesPerPixel; /* Here p is the address to the pixel we want to set */ Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp; - Uint32 pixel = SDL_MapRGBA(surface->format, clr.r*255, clr.g*255, clr.b*255, clr.a*255); + Uint32 pixel = SDL_MapRGBA(surface->format, static_cast(clr.r * 255), + static_cast(clr.g * 255), static_cast(clr.b * 255), static_cast(clr.a * 255)); switch(bpp) { case 1: *p = pixel; diff --git a/libs/openengine/bullet/BtOgre.cpp b/libs/openengine/bullet/BtOgre.cpp index de9ea6f57..88619b7fc 100644 --- a/libs/openengine/bullet/BtOgre.cpp +++ b/libs/openengine/bullet/BtOgre.cpp @@ -215,7 +215,7 @@ namespace BtOgre { if (mBoundRadius == (-1)) { getSize(); - mBoundRadius = (std::max(mBounds.x,std::max(mBounds.y,mBounds.z)) * 0.5); + mBoundRadius = (std::max(mBounds.x,std::max(mBounds.y,mBounds.z)) * 0.5f); } return mBoundRadius; } @@ -737,7 +737,7 @@ namespace BtOgre { { box_kCenter += vertices[c]; } - const Ogre::Real invVertexCount = 1.0 / vertex_count; + const Ogre::Real invVertexCount = 1.0f / vertex_count; box_kCenter *= invVertexCount; } Quaternion orient = boneOrientation; @@ -782,9 +782,9 @@ namespace BtOgre { box_afExtent.y = ((Real)0.5)*(fY1Max - fY1Min); box_afExtent.z = ((Real)0.5)*(fY2Max - fY2Min); - box_kCenter += (0.5*(fY0Max+fY0Min))*box_akAxis[0] + - (0.5*(fY1Max+fY1Min))*box_akAxis[1] + - (0.5*(fY2Max+fY2Min))*box_akAxis[2]; + box_kCenter += (0.5f*(fY0Max+fY0Min))*box_akAxis[0] + + (0.5f*(fY1Max+fY1Min))*box_akAxis[1] + + (0.5f*(fY2Max+fY2Min))*box_akAxis[2]; box_afExtent *= 2.0; diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index e0482104a..81a2eb043 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -385,7 +385,7 @@ namespace Physic } btHeightfieldTerrainShape* hfShape = new btHeightfieldTerrainShape( - sqrtVerts, sqrtVerts, heights, 1, + static_cast(sqrtVerts), static_cast(sqrtVerts), heights, 1, minh, maxh, 2, PHY_FLOAT,true); @@ -396,7 +396,7 @@ namespace Physic btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo(0,0,hfShape); RigidBody* body = new RigidBody(CI,name); - body->getWorldTransform().setOrigin(btVector3( (x+0.5)*triSize*(sqrtVerts-1), (y+0.5)*triSize*(sqrtVerts-1), (maxh+minh)/2.f)); + body->getWorldTransform().setOrigin(btVector3( (x+0.5f)*triSize*(sqrtVerts-1), (y+0.5f)*triSize*(sqrtVerts-1), (maxh+minh)/2.f)); HeightField hf; hf.mBody = body; @@ -720,7 +720,7 @@ namespace Physic void PhysicEngine::stepSimulation(double deltaT) { // This seems to be needed for character controller objects - mDynamicsWorld->stepSimulation(deltaT,10, 1/60.0); + mDynamicsWorld->stepSimulation(static_cast(deltaT), 10, 1 / 60.0f); if(isDebugCreated) { mDebugDrawer->step(); diff --git a/libs/openengine/ogre/lights.cpp b/libs/openengine/ogre/lights.cpp index 348057b84..97fa938da 100644 --- a/libs/openengine/ogre/lights.cpp +++ b/libs/openengine/ogre/lights.cpp @@ -74,16 +74,16 @@ Ogre::Real LightFunction::calculate(Ogre::Real value) if(mType == LT_Normal) { // Less than 1/255 light modifier for a constant light: - brightness = 1.0 + flickerAmplitude(mDeltaCount*slow)/255.0f; + brightness = 1.0f + flickerAmplitude(mDeltaCount*slow)/255.0f; } else if(mType == LT_Flicker) - brightness = 0.75 + flickerAmplitude(mDeltaCount*fast)*0.25; + brightness = 0.75f + flickerAmplitude(mDeltaCount*fast)*0.25f; else if(mType == LT_FlickerSlow) - brightness = 0.75 + flickerAmplitude(mDeltaCount*slow)*0.25; + brightness = 0.75f + flickerAmplitude(mDeltaCount*slow)*0.25f; else if(mType == LT_Pulse) - brightness = 1.0 + pulseAmplitude(mDeltaCount*fast)*0.25; + brightness = 1.0f + pulseAmplitude(mDeltaCount*fast)*0.25f; else if(mType == LT_PulseSlow) - brightness = 1.0 + pulseAmplitude(mDeltaCount*slow)*0.25; + brightness = 1.0f + pulseAmplitude(mDeltaCount*slow)*0.25f; return brightness; } diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index 0e37d2802..bdeeeb8c4 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -184,7 +184,7 @@ void OgreRenderer::setWindowGammaContrast(float gamma, float contrast) if (value > 65535) value = 65535; else if (value < 0) value = 0; - red[i] = green[i] = blue[i] = value; + red[i] = green[i] = blue[i] = static_cast(value); } if (SDL_SetWindowGammaRamp(mSDLWindow, red, green, blue) < 0) std::cout << "Couldn't set gamma: " << SDL_GetError() << std::endl; diff --git a/libs/openengine/ogre/selectionbuffer.cpp b/libs/openengine/ogre/selectionbuffer.cpp index 0ca24676e..87b85732b 100644 --- a/libs/openengine/ogre/selectionbuffer.cpp +++ b/libs/openengine/ogre/selectionbuffer.cpp @@ -26,7 +26,7 @@ namespace Render setupRenderTarget(); - mCurrentColour = Ogre::ColourValue(0.3, 0.3, 0.3); + mCurrentColour = Ogre::ColourValue(0.3f, 0.3f, 0.3f); } void SelectionBuffer::setupRenderTarget() @@ -145,7 +145,7 @@ namespace Render void SelectionBuffer::getNextColour () { - Ogre::ARGB color = (float(rand()) / float(RAND_MAX)) * std::numeric_limits::max(); + Ogre::ARGB color = static_cast((float(rand()) / float(RAND_MAX)) * std::numeric_limits::max()); if (mCurrentColour.getAsARGB () == color) { From e6cd8484a2366c38f9bbfc3167ee1dafa93b896c Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 8 Mar 2015 13:22:56 +1300 Subject: [PATCH 577/740] fixing MSVC 2013 warning C4244: & C4305 fixes for mistakes in last commit. --- apps/openmw/mwclass/door.cpp | 2 +- apps/openmw/mwgui/bookpage.cpp | 16 ++++++++-------- apps/openmw/mwgui/inventorywindow.cpp | 2 +- apps/openmw/mwgui/mapwindow.cpp | 17 +++-------------- apps/openmw/mwgui/settingswindow.cpp | 2 +- apps/openmw/mwgui/tradewindow.cpp | 2 +- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 2 +- 8 files changed, 17 insertions(+), 28 deletions(-) diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 6e1d5334d..2d39881b1 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -176,7 +176,7 @@ namespace MWClass { MWBase::Environment::get().getSoundManager()->fadeOutSound3D(ptr, openSound, 0.5f); - float offset = 1.0 - ptr.getRefData().getLocalRotation().rot[2]/ 3.14159265f * 2.0f; + float offset = 1.0f - ptr.getRefData().getLocalRotation().rot[2]/ 3.14159265f * 2.0f; //most if not all door have closing bang somewhere in the middle of the sound, //so we divide offset by two action->setSoundOffset(offset * 0.5f); diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index 9d2f52bfd..962e594ae 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -624,14 +624,14 @@ namespace RenderXform (MyGUI::ICroppedRectangle* croppedParent, MyGUI::RenderTargetInfo const & renderTargetInfo) { clipTop = static_cast(croppedParent->_getMarginTop()); - clipLeft = static_cast(croppedParent->_getMarginLeft ()); - clipRight = static_cast(croppedParent->getWidth () - croppedParent->_getMarginRight ()); - clipBottom = static_cast(croppedParent->getHeight() - croppedParent->_getMarginBottom()); - - absoluteLeft = static_cast(croppedParent->getAbsoluteLeft()); - absoluteTop = static_cast(croppedParent->getAbsoluteTop()); - leftOffset = static_cast(renderTargetInfo.leftOffset); - topOffset = static_cast(renderTargetInfo.topOffset); + clipLeft = static_cast(croppedParent->_getMarginLeft ()); + clipRight = static_cast(croppedParent->getWidth () - croppedParent->_getMarginRight ()); + clipBottom = static_cast(croppedParent->getHeight() - croppedParent->_getMarginBottom()); + + absoluteLeft = static_cast(croppedParent->getAbsoluteLeft()); + absoluteTop = static_cast(croppedParent->getAbsoluteTop()); + leftOffset = static_cast(renderTargetInfo.leftOffset); + topOffset = static_cast(renderTargetInfo.topOffset); pixScaleX = renderTargetInfo.pixScaleX; pixScaleY = renderTargetInfo.pixScaleY; diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index a6722319d..919228195 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -101,7 +101,7 @@ namespace MWGui void InventoryWindow::adjustPanes() { const float aspect = 0.5; // fixed aspect ratio for the avatar image - int leftPaneWidth = static_cast(mMainWidget->getSize().height - 44 - mArmorRating->getHeight()) * aspect); + int leftPaneWidth = static_cast((mMainWidget->getSize().height - 44 - mArmorRating->getHeight()) * aspect); mLeftPane->setSize( leftPaneWidth, mMainWidget->getSize().height-44 ); mRightPane->setCoord( mLeftPane->getPosition().left + leftPaneWidth + 4, mRightPane->getPosition().top, diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 271e43d29..02e8ffdfe 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -264,7 +264,7 @@ namespace MWGui // Image space is -Y up, cells are Y up widgetPos = MyGUI::IntPoint(static_cast(nX * mMapWidgetSize + (1 + (cellX - mCurX)) * mMapWidgetSize), - static_cast(nY * mMapWidgetSize + (1-(cellY-mCurY)) * mMapWidgetSize)); + static_cast(nY * mMapWidgetSize + (1-(cellY-mCurY)) * mMapWidgetSize)); } markerPos.nX = nX; @@ -827,18 +827,7 @@ namespace MWGui if (MWBase::Environment::get().getWorld ()->isCellExterior ()) { Ogre::Vector3 pos = MWBase::Environment::get().getWorld ()->getPlayerPtr().getRefData ().getBaseNode ()->_getDerivedPosition (); - - float worldX, worldY; - mGlobalMapRender->worldPosToImageSpace (pos.x, pos.y, worldX, worldY); - worldX *= mGlobalMapRender->getWidth(); - worldY *= mGlobalMapRender->getHeight(); - - mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(static_cast(worldX - 16), static_cast(worldY - 16))); - - // set the view offset so that player is in the center - MyGUI::IntSize viewsize = mGlobalMap->getSize(); - MyGUI::IntPoint viewoffs((viewsize.width / 2) - worldX, (viewsize.height / 2) - worldY); - mGlobalMap->setViewOffset(viewoffs); + setGlobalMapPlayerPosition(pos.x, pos.y); } } @@ -858,7 +847,7 @@ namespace MWGui // set the view offset so that player is in the center MyGUI::IntSize viewsize = mGlobalMap->getSize(); - MyGUI::IntPoint viewoffs((viewsize.width / 2) - x, (viewsize.height / 2) - y); + MyGUI::IntPoint viewoffs(static_cast(viewsize.width * 0.5f - x), static_cast(viewsize.height *0.5 - y)); mGlobalMap->setViewOffset(viewoffs); } diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 5bb82bc69..d895a28ea 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -148,7 +148,7 @@ namespace MWGui value = std::max(min, std::min(value, max)); value = (value-min)/(max-min); - scroll->setScrollPosition( value * (scroll->getScrollRange()-1)); + scroll->setScrollPosition(static_cast(value * (scroll->getScrollRange() - 1))); } else { diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 5015ef456..841e2e185 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -34,7 +34,7 @@ namespace int getEffectiveValue (MWWorld::Ptr item, int count) { - float price = item.getClass().getValue(item); + float price = static_cast(item.getClass().getValue(item)); if (item.getClass().hasItemHealth(item)) { price *= item.getClass().getItemHealth(item); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 5633ce3b7..bf1d3ec19 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1480,7 +1480,7 @@ namespace MWMechanics disposition = getDerivedDisposition(ptr); int fight = std::max(0, ptr.getClass().getCreatureStats(ptr).getAiSetting(CreatureStats::AI_Fight).getModified() - + static_cast(getFightDistanceBias(ptr, target) + getFightDispositionBias(disposition))); + + static_cast(getFightDistanceBias(ptr, target) + getFightDispositionBias(static_cast(disposition)))); if (ptr.getClass().isNpc() && target.getClass().isNpc()) { diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ebd756781..97b2cd204 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1350,7 +1350,7 @@ namespace MWWorld pos.pos[2] += dist; actor.getRefData().setPosition(pos); - Ogre::Vector3 traced = mPhysics->traceDown(actor, dist*1.1); + Ogre::Vector3 traced = mPhysics->traceDown(actor, dist*1.1f); moveObject(actor, actor.getCell(), traced.x, traced.y, traced.z); } From ca8c8c6aa4ff1c6889e31a4c579f182f1ff7794f Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 8 Mar 2015 17:42:07 +1300 Subject: [PATCH 578/740] fixing MSVC 2013 warning C4244: & C4305 conversion from 'const float' to 'int', possible loss of data conversion from 'double' to 'int', possible loss of data conversion from 'float' to 'int', possible loss of data --- apps/openmw/mwgui/repair.cpp | 4 +- apps/openmw/mwmechanics/activespells.cpp | 10 ++-- apps/openmw/mwmechanics/actors.cpp | 30 +++++------ apps/openmw/mwmechanics/aiavoiddoor.cpp | 4 +- apps/openmw/mwmechanics/aicombat.cpp | 30 +++++------ apps/openmw/mwmechanics/aicombataction.cpp | 16 +++--- apps/openmw/mwmechanics/aiescort.cpp | 8 +-- apps/openmw/mwmechanics/aipackage.cpp | 2 +- apps/openmw/mwmechanics/aitravel.cpp | 12 ++--- apps/openmw/mwmechanics/aiwander.cpp | 57 +++++++------------- apps/openmw/mwmechanics/alchemy.cpp | 18 +++---- apps/openmw/mwmechanics/autocalcspell.cpp | 2 +- apps/openmw/mwmechanics/character.cpp | 16 +++--- apps/openmw/mwmechanics/combat.cpp | 26 ++++----- apps/openmw/mwmechanics/creaturestats.cpp | 6 +-- apps/openmw/mwmechanics/enchanting.cpp | 18 +++---- apps/openmw/mwmechanics/npcstats.cpp | 4 +- apps/openmw/mwmechanics/pathfinding.cpp | 23 ++++---- apps/openmw/mwmechanics/pathfinding.hpp | 26 +++++++-- apps/openmw/mwmechanics/pathgrid.cpp | 14 ++--- apps/openmw/mwmechanics/pickpocket.cpp | 14 ++--- apps/openmw/mwmechanics/repair.cpp | 6 +-- apps/openmw/mwmechanics/security.cpp | 16 +++--- apps/openmw/mwmechanics/spellcasting.cpp | 62 +++++++++++----------- apps/openmw/mwmechanics/stat.cpp | 6 +-- apps/openmw/mwmechanics/stat.hpp | 2 +- apps/openmw/mwrender/objects.cpp | 2 +- apps/openmw/mwworld/inventorystore.cpp | 2 +- 28 files changed, 214 insertions(+), 222 deletions(-) diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index c3c971400..9f26923d4 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -150,10 +150,10 @@ void Repair::onRepairItem(MyGUI::Widget *sender) void Repair::onMouseWheel(MyGUI::Widget* _sender, int _rel) { - if (mRepairView->getViewOffset().top + _rel*0.3 > 0) + if (mRepairView->getViewOffset().top + _rel*0.3f > 0) mRepairView->setViewOffset(MyGUI::IntPoint(0, 0)); else - mRepairView->setViewOffset(MyGUI::IntPoint(0, mRepairView->getViewOffset().top + _rel*0.3)); + mRepairView->setViewOffset(MyGUI::IntPoint(0, static_cast(mRepairView->getViewOffset().top + _rel*0.3f))); } } diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index b4701126b..5eea08caa 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -74,9 +74,9 @@ namespace MWMechanics for (std::vector::const_iterator effectIt = effects.begin(); effectIt != effects.end(); ++effectIt) { - int duration = effectIt->mDuration; + double duration = effectIt->mDuration; MWWorld::TimeStamp end = start; - end += static_cast (duration)* + end += duration * MWBase::Environment::get().getWorld()->getTimeScaleFactor()/(60*60); if (end>now) @@ -110,7 +110,7 @@ namespace MWMechanics { const std::vector& effects = iterator->second.mEffects; - int duration = 0; + float duration = 0; for (std::vector::const_iterator iter (effects.begin()); iter!=effects.end(); ++iter) @@ -216,7 +216,7 @@ namespace MWMechanics std::string name = it->second.mDisplayName; float remainingTime = effectIt->mDuration + - (it->second.mTimeStamp - MWBase::Environment::get().getWorld()->getTimeStamp())*3600/timeScale; + static_cast(it->second.mTimeStamp - MWBase::Environment::get().getWorld()->getTimeStamp())*3600/timeScale; float magnitude = effectIt->mMagnitude; if (magnitude) @@ -229,7 +229,7 @@ namespace MWMechanics { for (TContainer::iterator it = mSpells.begin(); it != mSpells.end(); ) { - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] if (roll < chance) mSpells.erase(it++); else diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index aa2cc8615..f9de97132 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -84,8 +84,8 @@ bool disintegrateSlot (MWWorld::Ptr ptr, int slot, float disintegrate) // FIXME: charge should be a float, not int so that damage < 1 per frame can be applied. // This was also a bug in the original engine. charge -= - std::min(disintegrate, - static_cast(charge)); + std::min(static_cast(disintegrate), + charge); item->getCellRef().setCharge(charge); if (charge == 0) @@ -163,7 +163,7 @@ void getRestorationPerHourOfSleep (const MWWorld::Ptr& ptr, float& health, float bool stunted = stats.getMagicEffects ().get(ESM::MagicEffect::StuntedMagicka).getMagnitude() > 0; int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified (); - health = 0.1 * endurance; + health = 0.1f * endurance; magicka = 0; if (!stunted) @@ -203,7 +203,7 @@ namespace MWMechanics static const float fSoulgemMult = world->getStore().get().find("fSoulgemMult")->getFloat(); - float creatureSoulValue = mCreature.get()->mBase->mData.mSoul; + int creatureSoulValue = mCreature.get()->mBase->mData.mSoul; if (creatureSoulValue == 0) return; @@ -519,8 +519,8 @@ namespace MWMechanics effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).getMagnitude(), effects.get(EffectKey(ESM::MagicEffect::AbsorbAttribute, i)).getMagnitude()); - stat.damage(effects.get(EffectKey(ESM::MagicEffect::DamageAttribute, i)).getMagnitude() * duration * 1.5); - stat.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreAttribute, i)).getMagnitude() * duration * 1.5); + stat.damage(effects.get(EffectKey(ESM::MagicEffect::DamageAttribute, i)).getMagnitude() * duration * 1.5f); + stat.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreAttribute, i)).getMagnitude() * duration * 1.5f); creatureStats.setAttribute(i, stat); } @@ -566,19 +566,19 @@ namespace MWMechanics if (!creature || ptr.get()->mBase->mData.mType == ESM::Creature::Creatures) { Stat stat = creatureStats.getAiSetting(CreatureStats::AI_Fight); - stat.setModifier(creatureStats.getMagicEffects().get(ESM::MagicEffect::FrenzyHumanoid+creature).getMagnitude() - - creatureStats.getMagicEffects().get(ESM::MagicEffect::CalmHumanoid+creature).getMagnitude()); + stat.setModifier(static_cast(creatureStats.getMagicEffects().get(ESM::MagicEffect::FrenzyHumanoid + creature).getMagnitude() + - creatureStats.getMagicEffects().get(ESM::MagicEffect::CalmHumanoid+creature).getMagnitude())); creatureStats.setAiSetting(CreatureStats::AI_Fight, stat); stat = creatureStats.getAiSetting(CreatureStats::AI_Flee); - stat.setModifier(creatureStats.getMagicEffects().get(ESM::MagicEffect::DemoralizeHumanoid+creature).getMagnitude() - - creatureStats.getMagicEffects().get(ESM::MagicEffect::RallyHumanoid+creature).getMagnitude()); + stat.setModifier(static_cast(creatureStats.getMagicEffects().get(ESM::MagicEffect::DemoralizeHumanoid + creature).getMagnitude() + - creatureStats.getMagicEffects().get(ESM::MagicEffect::RallyHumanoid+creature).getMagnitude())); creatureStats.setAiSetting(CreatureStats::AI_Flee, stat); } if (creature && ptr.get()->mBase->mData.mType == ESM::Creature::Undead) { Stat stat = creatureStats.getAiSetting(CreatureStats::AI_Flee); - stat.setModifier(creatureStats.getMagicEffects().get(ESM::MagicEffect::TurnUndead).getMagnitude()); + stat.setModifier(static_cast(creatureStats.getMagicEffects().get(ESM::MagicEffect::TurnUndead).getMagnitude())); creatureStats.setAiSetting(CreatureStats::AI_Flee, stat); } @@ -741,7 +741,7 @@ namespace MWMechanics for (std::map::iterator it = boundItemsMap.begin(); it != boundItemsMap.end(); ++it) { bool found = creatureStats.mBoundItems.find(it->first) != creatureStats.mBoundItems.end(); - int magnitude = creatureStats.getMagicEffects().get(it->first).getMagnitude(); + float magnitude = creatureStats.getMagicEffects().get(it->first).getMagnitude(); if (found != (magnitude > 0)) { std::string itemGmst = it->second; @@ -786,8 +786,8 @@ namespace MWMechanics effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).getMagnitude(), effects.get(EffectKey(ESM::MagicEffect::AbsorbSkill, i)).getMagnitude()); - skill.damage(effects.get(EffectKey(ESM::MagicEffect::DamageSkill, i)).getMagnitude() * duration * 1.5); - skill.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreSkill, i)).getMagnitude() * duration * 1.5); + skill.damage(effects.get(EffectKey(ESM::MagicEffect::DamageSkill, i)).getMagnitude() * duration * 1.5f); + skill.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreSkill, i)).getMagnitude() * duration * 1.5f); } } @@ -1331,7 +1331,7 @@ namespace MWMechanics ? (stats.getMagicka().getModified() - stats.getMagicka().getCurrent()) / magickaPerHour : 1.0f; - int autoHours = std::ceil(std::max(1.f, std::max(healthHours, magickaHours))); + int autoHours = static_cast(std::ceil(std::max(1.f, std::max(healthHours, magickaHours)))); return autoHours; } diff --git a/apps/openmw/mwmechanics/aiavoiddoor.cpp b/apps/openmw/mwmechanics/aiavoiddoor.cpp index b9954337d..a73d955c5 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.cpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.cpp @@ -31,12 +31,12 @@ bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor, AiState& stat float x = pos.pos[0] - mLastPos.pos[0]; float y = pos.pos[1] - mLastPos.pos[1]; float z = pos.pos[2] - mLastPos.pos[2]; - int distance = x * x + y * y + z * z; + float distance = x * x + y * y + z * z; if(distance < 10 * 10) { //Got stuck, didn't move if(mAdjAngle == 0) //Try going in various directions mAdjAngle = 1.57079632679f; //pi/2 else if (mAdjAngle == 1.57079632679f) - mAdjAngle = -1.57079632679; + mAdjAngle = -1.57079632679f; else mAdjAngle = 0; mDuration = 1; //reset timer diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index fd4fd293d..c16baefaa 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -404,7 +404,7 @@ namespace MWMechanics { const MWWorld::ESMStore &store = world->getStore(); int chance = store.get().find("iVoiceAttackOdds")->getInt(); - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] if (roll < chance) { MWBase::Environment::get().getDialogueManager()->say(actor, "attack"); @@ -521,7 +521,7 @@ namespace MWMechanics //apply sideway movement (kind of dodging) with some probability if(static_cast(rand())/RAND_MAX < 0.25) { - movement.mPosition[0] = static_cast(rand())/RAND_MAX < 0.5? 1: -1; + movement.mPosition[0] = static_cast(rand())/RAND_MAX < 0.5? 1.0f : -1.0f; timerCombatMove = 0.05f + 0.15f * static_cast(rand())/RAND_MAX; combatMove = true; } @@ -588,7 +588,7 @@ namespace MWMechanics // get point just before target std::list::const_iterator pntIter = --mPathFinder.getPath().end(); --pntIter; - Ogre::Vector3 vBeforeTarget = Ogre::Vector3(pntIter->mX, pntIter->mY, pntIter->mZ); + Ogre::Vector3 vBeforeTarget(PathFinder::MakeOgreVector3(*pntIter)); // if current actor pos is closer to target then last point of path (excluding target itself) then go straight on target if(distToTarget <= (vTargetPos - vBeforeTarget).length()) @@ -685,27 +685,21 @@ namespace MWMechanics if(!mPathFinder.getPath().empty()) { ESM::Pathgrid::Point lastPt = mPathFinder.getPath().back(); - Ogre::Vector3 currPathTarget(lastPt.mX, lastPt.mY, lastPt.mZ); + Ogre::Vector3 currPathTarget(PathFinder::MakeOgreVector3(lastPt)); dist = (newPathTarget - currPathTarget).length(); } else dist = 1e+38F; // necessarily construct a new path - float targetPosThreshold = (actor.getCell()->getCell()->isExterior())? 300 : 100; + float targetPosThreshold = (actor.getCell()->getCell()->isExterior())? 300.0f : 100.0f; //construct new path only if target has moved away more than on [targetPosThreshold] if(dist > targetPosThreshold) { ESM::Position pos = actor.getRefData().getPosition(); - ESM::Pathgrid::Point start; - start.mX = pos.pos[0]; - start.mY = pos.pos[1]; - start.mZ = pos.pos[2]; + ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); - ESM::Pathgrid::Point dest; - dest.mX = newPathTarget.x; - dest.mY = newPathTarget.y; - dest.mZ = newPathTarget.z; + ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(newPathTarget)); if(!mPathFinder.isPathConstructed()) mPathFinder.buildPath(start, dest, actor.getCell(), false); @@ -770,7 +764,7 @@ ESM::Weapon::AttackType chooseBestAttack(const ESM::Weapon* weapon, MWMechanics: float roll = static_cast(rand())/RAND_MAX; if(roll <= 0.333f) //side punch { - movement.mPosition[0] = (static_cast(rand())/RAND_MAX < 0.5f)? 1: -1; + movement.mPosition[0] = (static_cast(rand())/RAND_MAX < 0.5f)? 1.0f : -1.0f; movement.mPosition[1] = 0; attackType = ESM::Weapon::AT_Slash; } @@ -792,16 +786,16 @@ ESM::Weapon::AttackType chooseBestAttack(const ESM::Weapon* weapon, MWMechanics: int chop = (weapon->mData.mChop[0] + weapon->mData.mChop[1])/2; int thrust = (weapon->mData.mThrust[0] + weapon->mData.mThrust[1])/2; - float total = slash + chop + thrust; + float total = static_cast(slash + chop + thrust); float roll = static_cast(rand())/RAND_MAX; - if(roll <= static_cast(slash)/total) + if(roll <= (slash/total)) { - movement.mPosition[0] = (static_cast(rand())/RAND_MAX < 0.5f)? 1: -1; + movement.mPosition[0] = (static_cast(rand())/RAND_MAX < 0.5f)? 1.0f : -1.0f; movement.mPosition[1] = 0; attackType = ESM::Weapon::AT_Slash; } - else if(roll <= (static_cast(slash) + static_cast(thrust))/total) + else if(roll <= (slash + (thrust/total))) { movement.mPosition[1] = 1; attackType = ESM::Weapon::AT_Thrust; diff --git a/apps/openmw/mwmechanics/aicombataction.cpp b/apps/openmw/mwmechanics/aicombataction.cpp index 175b98001..33e3c3d67 100644 --- a/apps/openmw/mwmechanics/aicombataction.cpp +++ b/apps/openmw/mwmechanics/aicombataction.cpp @@ -323,14 +323,14 @@ namespace MWMechanics if (effect.mAttribute >= 0 && effect.mAttribute < ESM::Attribute::Length) { const float attributePriorities[ESM::Attribute::Length] = { - 1.f, // Strength - 0.5, // Intelligence - 0.6, // Willpower - 0.7, // Agility - 0.5, // Speed - 0.8, // Endurance - 0.7, // Personality - 0.3 // Luck + 1.0f, // Strength + 0.5f, // Intelligence + 0.6f, // Willpower + 0.7f, // Agility + 0.5f, // Speed + 0.8f, // Endurance + 0.7f, // Personality + 0.3f // Luck }; rating *= attributePriorities[effect.mAttribute]; } diff --git a/apps/openmw/mwmechanics/aiescort.cpp b/apps/openmw/mwmechanics/aiescort.cpp index c89cfe492..91bf7c9b0 100644 --- a/apps/openmw/mwmechanics/aiescort.cpp +++ b/apps/openmw/mwmechanics/aiescort.cpp @@ -23,7 +23,7 @@ namespace MWMechanics { AiEscort::AiEscort(const std::string &actorId, int duration, float x, float y, float z) - : mActorId(actorId), mX(x), mY(y), mZ(z), mRemainingDuration(duration) + : mActorId(actorId), mX(x), mY(y), mZ(z), mRemainingDuration(static_cast(duration)) , mCellX(std::numeric_limits::max()) , mCellY(std::numeric_limits::max()) { @@ -36,7 +36,7 @@ namespace MWMechanics } AiEscort::AiEscort(const std::string &actorId, const std::string &cellId,int duration, float x, float y, float z) - : mActorId(actorId), mCellId(cellId), mX(x), mY(y), mZ(z), mRemainingDuration(duration) + : mActorId(actorId), mCellId(cellId), mX(x), mY(y), mZ(z), mRemainingDuration(static_cast(duration)) , mCellX(std::numeric_limits::max()) , mCellY(std::numeric_limits::max()) { @@ -86,13 +86,13 @@ namespace MWMechanics for (short counter = 0; counter < 3; counter++) differenceBetween[counter] = (leaderPos[counter] - followerPos[counter]); - float distanceBetweenResult = + double distanceBetweenResult = (differenceBetween[0] * differenceBetween[0]) + (differenceBetween[1] * differenceBetween[1]) + (differenceBetween[2] * differenceBetween[2]); if(distanceBetweenResult <= mMaxDist * mMaxDist) { - ESM::Pathgrid::Point point(mX,mY,mZ); + ESM::Pathgrid::Point point(static_cast(mX), static_cast(mY), static_cast(mZ)); point.mAutogenerated = 0; point.mConnectionNum = 0; point.mUnknown = 0; diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index f015bb8a4..f93376779 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -16,7 +16,7 @@ MWMechanics::AiPackage::~AiPackage() {} -MWMechanics::AiPackage::AiPackage() : mTimer(.26), mStuckTimer(0) { //mTimer starts at .26 to force initial pathbuild +MWMechanics::AiPackage::AiPackage() : mTimer(0.26f), mStuckTimer(0) { //mTimer starts at .26 to force initial pathbuild } diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 7124a1102..a46fe7296 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -93,15 +93,9 @@ namespace MWMechanics mCellX = cell->mData.mX; mCellY = cell->mData.mY; - ESM::Pathgrid::Point dest; - dest.mX = mX; - dest.mY = mY; - dest.mZ = mZ; - - ESM::Pathgrid::Point start; - start.mX = pos.pos[0]; - start.mY = pos.pos[1]; - start.mZ = pos.pos[2]; + ESM::Pathgrid::Point dest(static_cast(mX), static_cast(mY), static_cast(mZ)); + + ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); mPathFinder.buildPath(start, dest, actor.getCell(), true); } diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 738facb13..842f03edf 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -192,7 +192,7 @@ namespace MWMechanics if(mDistance && // actor is not intended to be stationary idleNow && // but is in idle !walking && // FIXME: some actors are idle while walking - proximityToDoor(actor, MIN_DIST_TO_DOOR_SQUARED*1.6*1.6)) // NOTE: checks interior cells only + proximityToDoor(actor, MIN_DIST_TO_DOOR_SQUARED*1.6f*1.6f)) // NOTE: checks interior cells only { idleNow = false; moveNow = true; @@ -315,13 +315,13 @@ namespace MWMechanics static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore() .get().find("fVoiceIdleOdds")->getFloat(); - float roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 10000; + float roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 10000; // In vanilla MW the chance was FPS dependent, and did not allow proper changing of fVoiceIdleOdds // due to the roll being an integer. // Our implementation does not have these issues, so needs to be recalibrated. We chose to // use the chance MW would have when run at 60 FPS with the default value of the GMST for calibration. - float x = fVoiceIdleOdds * 0.6 * (MWBase::Environment::get().getFrameDuration() / 0.1); + float x = fVoiceIdleOdds * 0.6f * (MWBase::Environment::get().getFrameDuration() / 0.1f); // Only say Idle voices when player is in LOS // A bit counterintuitive, likely vanilla did this to reduce the appearance of @@ -393,18 +393,10 @@ namespace MWMechanics if (!storage.mPathFinder.isPathConstructed()) { - Ogre::Vector3 destNodePos = mReturnPosition; - - ESM::Pathgrid::Point dest; - dest.mX = destNodePos[0]; - dest.mY = destNodePos[1]; - dest.mZ = destNodePos[2]; + ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(mReturnPosition)); // actor position is already in world co-ordinates - ESM::Pathgrid::Point start; - start.mX = pos.pos[0]; - start.mY = pos.pos[1]; - start.mZ = pos.pos[2]; + ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); // don't take shortcuts for wandering storage.mPathFinder.buildPath(start, dest, actor.getCell(), false); @@ -422,7 +414,7 @@ namespace MWMechanics { // Play a random voice greeting if the player gets too close int hello = cStats.getAiSetting(CreatureStats::AI_Hello).getModified(); - float helloDistance = hello; + float helloDistance = static_cast(hello); static int iGreetDistanceMultiplier =MWBase::Environment::get().getWorld()->getStore() .get().find("iGreetDistanceMultiplier")->getInt(); @@ -500,15 +492,10 @@ namespace MWMechanics assert(mAllowedNodes.size()); unsigned int randNode = (int)(rand() / ((double)RAND_MAX + 1) * mAllowedNodes.size()); // NOTE: initially constructed with local (i.e. cell) co-ordinates - Ogre::Vector3 destNodePos(mAllowedNodes[randNode].mX, - mAllowedNodes[randNode].mY, - mAllowedNodes[randNode].mZ); + Ogre::Vector3 destNodePos(PathFinder::MakeOgreVector3(mAllowedNodes[randNode])); // convert dest to use world co-ordinates - ESM::Pathgrid::Point dest; - dest.mX = destNodePos[0]; - dest.mY = destNodePos[1]; - dest.mZ = destNodePos[2]; + ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(destNodePos)); if (currentCell->getCell()->isExterior()) { dest.mX += currentCell->getCell()->mData.mX * ESM::Land::REAL_SIZE; @@ -516,10 +503,7 @@ namespace MWMechanics } // actor position is already in world co-ordinates - ESM::Pathgrid::Point start; - start.mX = pos.pos[0]; - start.mY = pos.pos[1]; - start.mZ = pos.pos[2]; + ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); // don't take shortcuts for wandering storage.mPathFinder.buildPath(start, dest, actor.getCell(), false); @@ -652,7 +636,7 @@ namespace MWMechanics static float fIdleChanceMultiplier = MWBase::Environment::get().getWorld()->getStore() .get().find("fIdleChanceMultiplier")->getFloat(); - unsigned short idleChance = fIdleChanceMultiplier * mIdle[counter]; + unsigned short idleChance = static_cast(fIdleChanceMultiplier * mIdle[counter]); unsigned short randSelect = (int)(rand() / ((double)RAND_MAX + 1) * int(100 / fIdleChanceMultiplier)); if(randSelect < idleChance && randSelect > idleRoll) { @@ -675,12 +659,12 @@ namespace MWMechanics state.moveIn(new AiWanderStorage()); - int index = std::rand() / (static_cast (RAND_MAX) + 1) * mAllowedNodes.size(); + int index = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * mAllowedNodes.size()); ESM::Pathgrid::Point dest = mAllowedNodes[index]; // apply a slight offset to prevent overcrowding - dest.mX += Ogre::Math::RangeRandom(-64, 64); - dest.mY += Ogre::Math::RangeRandom(-64, 64); + dest.mX += static_cast(Ogre::Math::RangeRandom(-64, 64)); + dest.mY += static_cast(Ogre::Math::RangeRandom(-64, 64)); if (actor.getCell()->isExterior()) { @@ -688,7 +672,8 @@ namespace MWMechanics dest.mY += actor.getCell()->getCell()->mData.mY * ESM::Land::REAL_SIZE; } - MWBase::Environment::get().getWorld()->moveObject(actor, dest.mX, dest.mY, dest.mZ); + MWBase::Environment::get().getWorld()->moveObject(actor, static_cast(dest.mX), + static_cast(dest.mY), static_cast(dest.mZ)); actor.getClass().adjustPosition(actor, false); } @@ -720,8 +705,8 @@ namespace MWMechanics float cellYOffset = 0; if(cell->isExterior()) { - cellXOffset = cell->mData.mX * ESM::Land::REAL_SIZE; - cellYOffset = cell->mData.mY * ESM::Land::REAL_SIZE; + cellXOffset = static_cast(cell->mData.mX * ESM::Land::REAL_SIZE); + cellYOffset = static_cast(cell->mData.mY * ESM::Land::REAL_SIZE); } // convert npcPos to local (i.e. cell) co-ordinates @@ -733,20 +718,18 @@ namespace MWMechanics // NOTE: mPoints and mAllowedNodes are in local co-ordinates for(unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++) { - Ogre::Vector3 nodePos(pathgrid->mPoints[counter].mX, pathgrid->mPoints[counter].mY, - pathgrid->mPoints[counter].mZ); + Ogre::Vector3 nodePos(PathFinder::MakeOgreVector3(pathgrid->mPoints[counter])); if(npcPos.squaredDistance(nodePos) <= mDistance * mDistance) mAllowedNodes.push_back(pathgrid->mPoints[counter]); } if(!mAllowedNodes.empty()) { - Ogre::Vector3 firstNodePos(mAllowedNodes[0].mX, mAllowedNodes[0].mY, mAllowedNodes[0].mZ); + Ogre::Vector3 firstNodePos(PathFinder::MakeOgreVector3(mAllowedNodes[0])); float closestNode = npcPos.squaredDistance(firstNodePos); unsigned int index = 0; for(unsigned int counterThree = 1; counterThree < mAllowedNodes.size(); counterThree++) { - Ogre::Vector3 nodePos(mAllowedNodes[counterThree].mX, mAllowedNodes[counterThree].mY, - mAllowedNodes[counterThree].mZ); + Ogre::Vector3 nodePos(PathFinder::MakeOgreVector3(mAllowedNodes[counterThree])); float tempDist = npcPos.squaredDistance(nodePos); if(tempDist < closestNode) index = counterThree; diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index 6e54b6f83..a833e28d9 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -94,17 +94,17 @@ void MWMechanics::Alchemy::applyTools (int flags, float& value) const quality = negative ? 2 * toolQuality + 3 * calcinatorQuality : (magnitude && duration ? - 2 * toolQuality + calcinatorQuality : 2/3.0 * (toolQuality + calcinatorQuality) + 0.5); + 2 * toolQuality + calcinatorQuality : 2/3.0f * (toolQuality + calcinatorQuality) + 0.5f); break; case 2: - quality = negative ? 1+toolQuality : (magnitude && duration ? toolQuality : toolQuality + 0.5); + quality = negative ? 1+toolQuality : (magnitude && duration ? toolQuality : toolQuality + 0.5f); break; case 3: - quality = magnitude && duration ? calcinatorQuality : calcinatorQuality + 0.5; + quality = magnitude && duration ? calcinatorQuality : calcinatorQuality + 0.5f; break; } @@ -178,8 +178,8 @@ void MWMechanics::Alchemy::updateEffects() if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)) applyTools (magicEffect->mData.mFlags, duration); - duration = static_cast (duration+0.5); - magnitude = static_cast (magnitude+0.5); + duration = roundf(duration); + magnitude = roundf(magnitude); if (magnitude>0 && duration>0) { @@ -197,8 +197,8 @@ void MWMechanics::Alchemy::updateEffects() effect.mRange = 0; effect.mArea = 0; - effect.mDuration = duration; - effect.mMagnMin = effect.mMagnMax = magnitude; + effect.mDuration = static_cast(duration); + effect.mMagnMin = effect.mMagnMax = static_cast(magnitude); mEffects.push_back (effect); } @@ -323,8 +323,8 @@ float MWMechanics::Alchemy::getAlchemyFactor() const return (npcStats.getSkill (ESM::Skill::Alchemy).getModified() + - 0.1 * creatureStats.getAttribute (ESM::Attribute::Intelligence).getModified() - + 0.1 * creatureStats.getAttribute (ESM::Attribute::Luck).getModified()); + 0.1f * creatureStats.getAttribute (ESM::Attribute::Intelligence).getModified() + + 0.1f * creatureStats.getAttribute (ESM::Attribute::Luck).getModified()); } int MWMechanics::Alchemy::countIngredients() const diff --git a/apps/openmw/mwmechanics/autocalcspell.cpp b/apps/openmw/mwmechanics/autocalcspell.cpp index 7b8c43a06..e4b143826 100644 --- a/apps/openmw/mwmechanics/autocalcspell.cpp +++ b/apps/openmw/mwmechanics/autocalcspell.cpp @@ -187,7 +187,7 @@ namespace MWMechanics for (std::vector::const_iterator it = effects.mList.begin(); it != effects.mList.end(); ++it) { const ESM::ENAMstruct& effect = *it; - float x = effect.mDuration; + float x = static_cast(effect.mDuration); const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effect.mEffectID); if (!(magicEffect->mData.mFlags & ESM::MagicEffect::UncappedDamage)) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 449c030f4..c8834e095 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -112,7 +112,7 @@ float getFallDamage(const MWWorld::Ptr& ptr, float fallHeight) if (fallHeight >= fallDistanceMin) { - const float acrobaticsSkill = ptr.getClass().getSkill(ptr, ESM::Skill::Acrobatics); + const float acrobaticsSkill = static_cast(ptr.getClass().getSkill(ptr, ESM::Skill::Acrobatics)); const float jumpSpellBonus = ptr.getClass().getCreatureStats(ptr).getMagicEffects().get(ESM::MagicEffect::Jump).getMagnitude(); const float fallAcroBase = store.find("fFallAcroBase")->getFloat(); const float fallAcroMult = store.find("fFallAcroMult")->getFloat(); @@ -120,7 +120,7 @@ float getFallDamage(const MWWorld::Ptr& ptr, float fallHeight) const float fallDistanceMult = store.find("fFallDistanceMult")->getFloat(); float x = fallHeight - fallDistanceMin; - x -= (1.5 * acrobaticsSkill) + jumpSpellBonus; + x -= (1.5f * acrobaticsSkill) + jumpSpellBonus; x = std::max(0.0f, x); float a = fallAcroBase + fallAcroMult * (100 - acrobaticsSkill); @@ -220,7 +220,7 @@ std::string CharacterController::chooseRandomGroup (const std::string& prefix, i while (mAnimation->hasAnimation(prefix + Ogre::StringConverter::toString(numAnims+1))) ++numAnims; - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * numAnims + 1; // [1, numAnims] + int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * numAnims) + 1; // [1, numAnims] if (num) *num = roll; return prefix + Ogre::StringConverter::toString(roll); @@ -829,7 +829,7 @@ bool CharacterController::updateCreatureState() } if (weapType != WeapType_Spell || !mAnimation->hasAnimation("spellcast")) // Not all creatures have a dedicated spellcast animation { - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 3; // [0, 2] + int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 3); // [0, 2] if (roll == 0) mCurrentWeapon = "attack1"; else if (roll == 1) @@ -1531,7 +1531,7 @@ void CharacterController::update(float duration) float normalizedEncumbrance = mPtr.getClass().getNormalizedEncumbrance(mPtr); if (normalizedEncumbrance > 1) normalizedEncumbrance = 1; - const int fatigueDecrease = fatigueJumpBase + (1 - normalizedEncumbrance) * fatigueJumpMult; + const float fatigueDecrease = fatigueJumpBase + (1 - normalizedEncumbrance) * fatigueJumpMult; DynamicStat fatigue = cls.getCreatureStats(mPtr).getFatigue(); fatigue.setCurrent(fatigue.getCurrent() - fatigueDecrease); cls.getCreatureStats(mPtr).setFatigue(fatigue); @@ -1551,12 +1551,12 @@ void CharacterController::update(float duration) // inflict fall damages DynamicStat health = cls.getCreatureStats(mPtr).getHealth(); - int realHealthLost = healthLost * (1.0f - 0.25 * fatigueTerm); + float realHealthLost = static_cast(healthLost * (1.0f - 0.25f * fatigueTerm)); health.setCurrent(health.getCurrent() - realHealthLost); cls.getCreatureStats(mPtr).setHealth(health); cls.onHit(mPtr, realHealthLost, true, MWWorld::Ptr(), MWWorld::Ptr(), true); - const float acrobaticsSkill = cls.getSkill(mPtr, ESM::Skill::Acrobatics); + const int acrobaticsSkill = cls.getSkill(mPtr, ESM::Skill::Acrobatics); if (healthLost > (acrobaticsSkill * fatigueTerm)) { cls.getCreatureStats(mPtr).setKnockedDown(true); @@ -1612,7 +1612,7 @@ void CharacterController::update(float duration) mTurnAnimationThreshold -= duration; if (movestate == CharState_TurnRight || movestate == CharState_TurnLeft) - mTurnAnimationThreshold = 0.05; + mTurnAnimationThreshold = 0.05f; else if (movestate == CharState_None && (mMovementState == CharState_TurnRight || mMovementState == CharState_TurnLeft) && mTurnAnimationThreshold > 0) { diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index e22e9ec24..42380664b 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -83,8 +83,8 @@ namespace MWMechanics MWMechanics::CreatureStats& attackerStats = attacker.getClass().getCreatureStats(attacker); - float blockTerm = blocker.getClass().getSkill(blocker, ESM::Skill::Block) + 0.2 * blockerStats.getAttribute(ESM::Attribute::Agility).getModified() - + 0.1 * blockerStats.getAttribute(ESM::Attribute::Luck).getModified(); + float blockTerm = blocker.getClass().getSkill(blocker, ESM::Skill::Block) + 0.2f * blockerStats.getAttribute(ESM::Attribute::Agility).getModified() + + 0.1f * blockerStats.getAttribute(ESM::Attribute::Luck).getModified(); float enemySwing = attackerStats.getAttackStrength(); float swingTerm = enemySwing * gmst.find("fSwingBlockMult")->getFloat() + gmst.find("fSwingBlockBase")->getFloat(); @@ -93,13 +93,13 @@ namespace MWMechanics blockerTerm *= gmst.find("fBlockStillBonus")->getFloat(); blockerTerm *= blockerStats.getFatigueTerm(); - float attackerSkill = 0.f; + int attackerSkill = 0; if (weapon.isEmpty()) attackerSkill = attacker.getClass().getSkill(attacker, ESM::Skill::HandToHand); else attackerSkill = attacker.getClass().getSkill(attacker, weapon.getClass().getEquipmentSkill(weapon)); - float attackerTerm = attackerSkill + 0.2 * attackerStats.getAttribute(ESM::Attribute::Agility).getModified() - + 0.1 * attackerStats.getAttribute(ESM::Attribute::Luck).getModified(); + float attackerTerm = attackerSkill + 0.2f * attackerStats.getAttribute(ESM::Attribute::Agility).getModified() + + 0.1f * attackerStats.getAttribute(ESM::Attribute::Luck).getModified(); attackerTerm *= attackerStats.getFatigueTerm(); int x = int(blockerTerm - attackerTerm); @@ -107,7 +107,7 @@ namespace MWMechanics int iBlockMinChance = gmst.find("iBlockMinChance")->getInt(); x = std::min(iBlockMaxChance, std::max(iBlockMinChance, x)); - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] if (roll < x) { // Reduce shield durability by incoming damage @@ -183,7 +183,7 @@ namespace MWMechanics if(!weapon.isEmpty()) weapskill = weapon.getClass().getEquipmentSkill(weapon); - float skillValue = attacker.getClass().getSkill(attacker, + int skillValue = attacker.getClass().getSkill(attacker, weapon.getClass().getEquipmentSkill(weapon)); if((::rand()/(RAND_MAX+1.0)) > getHitChance(attacker, victim, skillValue)/100.0f) @@ -206,7 +206,7 @@ namespace MWMechanics } damage *= fDamageStrengthBase + - (attackerStats.getAttribute(ESM::Attribute::Strength).getModified() * fDamageStrengthMult * 0.1); + (attackerStats.getAttribute(ESM::Attribute::Strength).getModified() * fDamageStrengthMult * 0.1f); adjustWeaponDamage(damage, weapon); reduceWeaponCondition(damage, true, weapon, attacker); @@ -265,14 +265,14 @@ namespace MWMechanics + 0.2f * attackerStats.getAttribute(ESM::Attribute::Willpower).getModified() + 0.1f * attackerStats.getAttribute(ESM::Attribute::Luck).getModified(); - int fatigueMax = attackerStats.getFatigue().getModified(); - int fatigueCurrent = attackerStats.getFatigue().getCurrent(); + float fatigueMax = attackerStats.getFatigue().getModified(); + float fatigueCurrent = attackerStats.getFatigue().getCurrent(); - float normalisedFatigue = fatigueMax==0 ? 1 : std::max (0.0f, static_cast (fatigueCurrent)/fatigueMax); + float normalisedFatigue = floor(fatigueMax)==0 ? 1 : std::max (0.0f, (fatigueCurrent/fatigueMax)); saveTerm *= 1.25f * normalisedFatigue; - float roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + float roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] float x = std::max(0.f, saveTerm - roll); int element = ESM::MagicEffect::FireDamage; @@ -344,7 +344,7 @@ namespace MWMechanics const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); float minstrike = store.get().find("fMinHandToHandMult")->getFloat(); float maxstrike = store.get().find("fMaxHandToHandMult")->getFloat(); - damage = attacker.getClass().getSkill(attacker, ESM::Skill::HandToHand); + damage = static_cast(attacker.getClass().getSkill(attacker, ESM::Skill::HandToHand)); damage *= minstrike + ((maxstrike-minstrike)*attacker.getClass().getCreatureStats(attacker).getAttackStrength()); MWMechanics::CreatureStats& otherstats = victim.getClass().getCreatureStats(victim); diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 1947ad839..931c2f14e 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -42,10 +42,10 @@ namespace MWMechanics float CreatureStats::getFatigueTerm() const { - int max = getFatigue().getModified(); - int current = getFatigue().getCurrent(); + float max = getFatigue().getModified(); + float current = getFatigue().getCurrent(); - float normalised = max==0 ? 1 : std::max (0.0f, static_cast (current)/max); + float normalised = floor(max) == 0 ? 1 : std::max (0.0f, current / max); const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index de5921a70..d99b337d5 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -176,7 +176,7 @@ namespace MWMechanics int magMax = (it->mMagnMax == 0) ? 1 : it->mMagnMax; int area = (it->mArea == 0) ? 1 : it->mArea; - float magnitudeCost = (magMin + magMax) * baseCost * 0.05; + float magnitudeCost = (magMin + magMax) * baseCost * 0.05f; if (mCastStyle == ESM::Enchantment::ConstantEffect) { magnitudeCost *= store.get().find("fEnchantmentConstantDurationMult")->getFloat(); @@ -186,7 +186,7 @@ namespace MWMechanics magnitudeCost *= it->mDuration; } - float areaCost = area * 0.05 * baseCost; + float areaCost = area * 0.05f * baseCost; const float fEffectCostMult = store.get().find("fEffectCostMult")->getFloat(); @@ -215,7 +215,7 @@ namespace MWMechanics { int baseCost = getBaseCastCost(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - return getEffectiveEnchantmentCastCost(baseCost, player); + return getEffectiveEnchantmentCastCost(static_cast(baseCost), player); } @@ -225,7 +225,7 @@ namespace MWMechanics return 0; float priceMultipler = MWBase::Environment::get().getWorld()->getStore().get().find ("fEnchantmentValueMult")->getFloat(); - int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mEnchanter, (getEnchantPoints() * priceMultipler), true); + int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mEnchanter, static_cast(getEnchantPoints() * priceMultipler), true); return price; } @@ -247,7 +247,7 @@ namespace MWMechanics const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - return mOldItemPtr.getClass().getEnchantmentPoints(mOldItemPtr) * store.get().find("fEnchantmentMult")->getFloat(); + return static_cast(mOldItemPtr.getClass().getEnchantmentPoints(mOldItemPtr) * store.get().find("fEnchantmentMult")->getFloat()); } bool Enchanting::soulEmpty() const { @@ -274,13 +274,13 @@ namespace MWMechanics const NpcStats& npcStats = mEnchanter.getClass().getNpcStats (mEnchanter); float chance1 = (npcStats.getSkill (ESM::Skill::Enchant).getModified() + - (0.25 * npcStats.getAttribute (ESM::Attribute::Intelligence).getModified()) - + (0.125 * npcStats.getAttribute (ESM::Attribute::Luck).getModified())); + (0.25f * npcStats.getAttribute (ESM::Attribute::Intelligence).getModified()) + + (0.125f * npcStats.getAttribute (ESM::Attribute::Luck).getModified())); const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); - float chance2 = 7.5 / (gmst.find("fEnchantmentChanceMult")->getFloat() * ((mCastStyle == ESM::Enchantment::ConstantEffect) ? - gmst.find("fEnchantmentConstantChanceMult")->getFloat() : 1 )) + float chance2 = 7.5f / (gmst.find("fEnchantmentChanceMult")->getFloat() * ((mCastStyle == ESM::Enchantment::ConstantEffect) ? + gmst.find("fEnchantmentConstantChanceMult")->getFloat() : 1.0f )) * getEnchantPoints(); return (chance1-chance2); diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 58bf11cff..7f468f6d4 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -142,7 +142,7 @@ void MWMechanics::NpcStats::setFactionReputation (const std::string& faction, in float MWMechanics::NpcStats::getSkillProgressRequirement (int skillIndex, const ESM::Class& class_) const { - float progressRequirement = 1 + getSkill (skillIndex).getBase(); + float progressRequirement = static_cast(1 + getSkill(skillIndex).getBase()); const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); @@ -303,7 +303,7 @@ void MWMechanics::NpcStats::updateHealth() const int endurance = getAttribute(ESM::Attribute::Endurance).getBase(); const int strength = getAttribute(ESM::Attribute::Strength).getBase(); - setHealth(static_cast (0.5 * (strength + endurance))); + setHealth(floor(0.5f * (strength + endurance))); } int MWMechanics::NpcStats::getLevelupAttributeMultiplier(int attribute) const diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 0634725a8..e8abb9e98 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -17,7 +17,7 @@ namespace // float distanceSquared(ESM::Pathgrid::Point point, Ogre::Vector3 pos) { - return Ogre::Vector3(point.mX, point.mY, point.mZ).squaredDistance(pos); + return MWMechanics::PathFinder::MakeOgreVector3(point).squaredDistance(pos); } // Return the closest pathgrid point index from the specified position co @@ -95,7 +95,7 @@ namespace MWMechanics x -= point.mX; y -= point.mY; z -= point.mZ; - return (x * x + y * y + 0.1 * z * z); + return (x * x + y * y + 0.1f * z * z); } float distance(ESM::Pathgrid::Point point, float x, float y, float z) @@ -108,9 +108,9 @@ namespace MWMechanics float distance(ESM::Pathgrid::Point a, ESM::Pathgrid::Point b) { - float x = a.mX - b.mX; - float y = a.mY - b.mY; - float z = a.mZ - b.mZ; + float x = static_cast(a.mX - b.mX); + float y = static_cast(a.mY - b.mY); + float z = static_cast(a.mZ - b.mZ); return sqrt(x * x + y * y + z * z); } @@ -176,8 +176,9 @@ namespace MWMechanics if(allowShortcuts) { // if there's a ray cast hit, can't take a direct path - if(!MWBase::Environment::get().getWorld()->castRay(startPoint.mX, startPoint.mY, startPoint.mZ, - endPoint.mX, endPoint.mY, endPoint.mZ)) + if (!MWBase::Environment::get().getWorld()->castRay( + static_cast(startPoint.mX), static_cast(startPoint.mY), static_cast(startPoint.mZ), + static_cast(endPoint.mX), static_cast(endPoint.mY), static_cast(endPoint.mZ))) { mPath.push_back(endPoint); mIsPathConstructed = true; @@ -206,8 +207,8 @@ namespace MWMechanics float yCell = 0; if (mCell->isExterior()) { - xCell = mCell->getCell()->mData.mX * ESM::Land::REAL_SIZE; - yCell = mCell->getCell()->mData.mY * ESM::Land::REAL_SIZE; + xCell = static_cast(mCell->getCell()->mData.mX * ESM::Land::REAL_SIZE); + yCell = static_cast(mCell->getCell()->mData.mY * ESM::Land::REAL_SIZE); } // NOTE: It is possible that getClosestPoint returns a pathgrind point index @@ -216,12 +217,12 @@ namespace MWMechanics // point right behind the wall that is closer than any pathgrid // point outside the wall int startNode = getClosestPoint(mPathgrid, - Ogre::Vector3(startPoint.mX - xCell, startPoint.mY - yCell, startPoint.mZ)); + Ogre::Vector3(startPoint.mX - xCell, startPoint.mY - yCell, static_cast(startPoint.mZ))); // Some cells don't have any pathgrids at all if(startNode != -1) { std::pair endNode = getClosestReachablePoint(mPathgrid, cell, - Ogre::Vector3(endPoint.mX - xCell, endPoint.mY - yCell, endPoint.mZ), + Ogre::Vector3(endPoint.mX - xCell, endPoint.mY - yCell, static_cast(endPoint.mZ)), startNode); // this shouldn't really happen, but just in case diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 7ba2d22ba..490cf9b88 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -1,10 +1,12 @@ #ifndef GAME_MWMECHANICS_PATHFINDING_H #define GAME_MWMECHANICS_PATHFINDING_H +#include #include #include #include +#include namespace MWWorld { @@ -27,11 +29,11 @@ namespace MWMechanics return -1.0; } - static float sgn(float a) + static int sgn(int a) { if(a > 0) - return 1.0; - return -1.0; + return 1; + return -1; } void clearPath(); @@ -74,6 +76,24 @@ namespace MWMechanics mPath.push_back(point); } + /// utility function to convert a Ogre::Vector3 to a Pathgrid::Point + static ESM::Pathgrid::Point MakePathgridPoint(const Ogre::Vector3& v) + { + return ESM::Pathgrid::Point(static_cast(v[0]), static_cast(v[1]), static_cast(v[2])); + } + + /// utility function to convert an ESM::Position to a Pathgrid::Point + static ESM::Pathgrid::Point MakePathgridPoint(const ESM::Position& p) + { + return ESM::Pathgrid::Point(static_cast(p.pos[0]), static_cast(p.pos[1]), static_cast(p.pos[2])); + } + + /// utility function to convert a Pathgrid::Point to a Ogre::Vector3 + static Ogre::Vector3 MakeOgreVector3(const ESM::Pathgrid::Point& p) + { + return Ogre::Vector3(static_cast(p.mX), static_cast(p.mY), static_cast(p.mZ)); + } + private: bool mIsPathConstructed; diff --git a/apps/openmw/mwmechanics/pathgrid.cpp b/apps/openmw/mwmechanics/pathgrid.cpp index 9e50af2b8..c1e094bb1 100644 --- a/apps/openmw/mwmechanics/pathgrid.cpp +++ b/apps/openmw/mwmechanics/pathgrid.cpp @@ -27,7 +27,7 @@ namespace // float manhattan(const ESM::Pathgrid::Point& a, const ESM::Pathgrid::Point& b) { - return 300 * (abs(a.mX - b.mX) + abs(a.mY - b.mY) + abs(a.mZ - b.mZ)); + return 300.0f * (abs(a.mX - b.mX) + abs(a.mY - b.mY) + abs(a.mZ - b.mZ)); } // Choose a heuristics - Note that these may not be the best for directed @@ -317,23 +317,23 @@ namespace MWMechanics float yCell = 0; if (mIsExterior) { - xCell = mPathgrid->mData.mX * ESM::Land::REAL_SIZE; - yCell = mPathgrid->mData.mY * ESM::Land::REAL_SIZE; + xCell = static_cast(mPathgrid->mData.mX * ESM::Land::REAL_SIZE); + yCell = static_cast(mPathgrid->mData.mY * ESM::Land::REAL_SIZE); } while(graphParent[current] != -1) { ESM::Pathgrid::Point pt = mPathgrid->mPoints[current]; - pt.mX += xCell; - pt.mY += yCell; + pt.mX += static_cast(xCell); + pt.mY += static_cast(yCell); path.push_front(pt); current = graphParent[current]; } // add first node to path explicitly ESM::Pathgrid::Point pt = mPathgrid->mPoints[start]; - pt.mX += xCell; - pt.mY += yCell; + pt.mX += static_cast(xCell); + pt.mY += static_cast(yCell); path.push_front(pt); return path; } diff --git a/apps/openmw/mwmechanics/pickpocket.cpp b/apps/openmw/mwmechanics/pickpocket.cpp index 14abcd643..12db9d6f5 100644 --- a/apps/openmw/mwmechanics/pickpocket.cpp +++ b/apps/openmw/mwmechanics/pickpocket.cpp @@ -20,10 +20,10 @@ namespace MWMechanics float Pickpocket::getChanceModifier(const MWWorld::Ptr &ptr, float add) { NpcStats& stats = ptr.getClass().getNpcStats(ptr); - float agility = stats.getAttribute(ESM::Attribute::Agility).getModified(); - float luck = stats.getAttribute(ESM::Attribute::Luck).getModified(); - float sneak = ptr.getClass().getSkill(ptr, ESM::Skill::Sneak); - return (add + 0.2 * agility + 0.1 * luck + sneak) * stats.getFatigueTerm(); + float agility = static_cast(stats.getAttribute(ESM::Attribute::Agility).getModified()); + float luck = static_cast(stats.getAttribute(ESM::Attribute::Luck).getModified()); + float sneak = static_cast(ptr.getClass().getSkill(ptr, ESM::Skill::Sneak)); + return (add + 0.2f * agility + 0.1f * luck + sneak) * stats.getFatigueTerm(); } bool Pickpocket::getDetected(float valueTerm) @@ -33,13 +33,13 @@ namespace MWMechanics float t = 2*x - y; - float pcSneak = mThief.getClass().getSkill(mThief, ESM::Skill::Sneak); + float pcSneak = static_cast(mThief.getClass().getSkill(mThief, ESM::Skill::Sneak)); int iPickMinChance = MWBase::Environment::get().getWorld()->getStore().get() .find("iPickMinChance")->getInt(); int iPickMaxChance = MWBase::Environment::get().getWorld()->getStore().get() .find("iPickMaxChance")->getInt(); - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] if (t < pcSneak / iPickMinChance) { return (roll > int(pcSneak / iPickMinChance)); @@ -53,7 +53,7 @@ namespace MWMechanics bool Pickpocket::pick(MWWorld::Ptr item, int count) { - float stackValue = item.getClass().getValue(item) * count; + float stackValue = static_cast(item.getClass().getValue(item) * count); float fPickPocketMod = MWBase::Environment::get().getWorld()->getStore().get() .find("fPickPocketMod")->getFloat(); float valueTerm = 10 * fPickPocketMod * stackValue; diff --git a/apps/openmw/mwmechanics/repair.cpp b/apps/openmw/mwmechanics/repair.cpp index 6d6f889ed..486a9183d 100644 --- a/apps/openmw/mwmechanics/repair.cpp +++ b/apps/openmw/mwmechanics/repair.cpp @@ -44,12 +44,12 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair) float toolQuality = ref->mBase->mData.mQuality; - float x = (0.1 * pcStrength + 0.1 * pcLuck + armorerSkill) * fatigueTerm; + float x = (0.1f * pcStrength + 0.1f * pcLuck + armorerSkill) * fatigueTerm; - int roll = static_cast (std::rand()) / RAND_MAX * 100; + int roll = static_cast(static_cast (std::rand()) / RAND_MAX * 100); if (roll <= x) { - int y = fRepairAmountMult * toolQuality * roll; + int y = static_cast(fRepairAmountMult * toolQuality * roll); y = std::max(1, y); // repair by 'y' points diff --git a/apps/openmw/mwmechanics/security.cpp b/apps/openmw/mwmechanics/security.cpp index 4a049d60f..d987814e5 100644 --- a/apps/openmw/mwmechanics/security.cpp +++ b/apps/openmw/mwmechanics/security.cpp @@ -20,9 +20,9 @@ namespace MWMechanics { CreatureStats& creatureStats = actor.getClass().getCreatureStats(actor); NpcStats& npcStats = actor.getClass().getNpcStats(actor); - mAgility = creatureStats.getAttribute(ESM::Attribute::Agility).getModified(); - mLuck = creatureStats.getAttribute(ESM::Attribute::Luck).getModified(); - mSecuritySkill = npcStats.getSkill(ESM::Skill::Security).getModified(); + mAgility = static_cast(creatureStats.getAttribute(ESM::Attribute::Agility).getModified()); + mLuck = static_cast(creatureStats.getAttribute(ESM::Attribute::Luck).getModified()); + mSecuritySkill = static_cast(npcStats.getSkill(ESM::Skill::Security).getModified()); mFatigueTerm = creatureStats.getFatigueTerm(); } @@ -38,7 +38,7 @@ namespace MWMechanics float fPickLockMult = MWBase::Environment::get().getWorld()->getStore().get().find("fPickLockMult")->getFloat(); - float x = 0.2 * mAgility + 0.1 * mLuck + mSecuritySkill; + float x = 0.2f * mAgility + 0.1f * mLuck + mSecuritySkill; x *= pickQuality * mFatigueTerm; x += fPickLockMult * lockStrength; @@ -48,7 +48,7 @@ namespace MWMechanics else { MWBase::Environment::get().getMechanicsManager()->objectOpened(mActor, lock); - int roll = static_cast (std::rand()) / RAND_MAX * 100; + int roll = static_cast(static_cast (std::rand()) / RAND_MAX * 100); if (roll <= x) { lock.getClass().unlock(lock); @@ -76,11 +76,11 @@ namespace MWMechanics float probeQuality = probe.get()->mBase->mData.mQuality; const ESM::Spell* trapSpell = MWBase::Environment::get().getWorld()->getStore().get().find(trap.getCellRef().getTrap()); - float trapSpellPoints = trapSpell->mData.mCost; + int trapSpellPoints = trapSpell->mData.mCost; float fTrapCostMult = MWBase::Environment::get().getWorld()->getStore().get().find("fTrapCostMult")->getFloat(); - float x = 0.2 * mAgility + 0.1 * mLuck + mSecuritySkill; + float x = 0.2f * mAgility + 0.1f * mLuck + mSecuritySkill; x += fTrapCostMult * trapSpellPoints; x *= probeQuality * mFatigueTerm; @@ -90,7 +90,7 @@ namespace MWMechanics else { MWBase::Environment::get().getMechanicsManager()->objectOpened(mActor, trap); - int roll = static_cast (std::rand()) / RAND_MAX * 100; + int roll = static_cast(static_cast (std::rand()) / RAND_MAX * 100); if (roll <= x) { trap.getCellRef().setTrap(""); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 06a3c1dfd..3ca30977b 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -144,21 +144,21 @@ namespace MWMechanics for (std::vector::const_iterator it = spell->mEffects.mList.begin(); it != spell->mEffects.mList.end(); ++it) { - float x = it->mDuration; + float x = static_cast(it->mDuration); const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find( it->mEffectID); if (!(magicEffect->mData.mFlags & ESM::MagicEffect::UncappedDamage)) x = std::max(1.f, x); - x *= 0.1 * magicEffect->mData.mBaseCost; - x *= 0.5 * (it->mMagnMin + it->mMagnMax); - x *= it->mArea * 0.05 * magicEffect->mData.mBaseCost; + x *= 0.1f * magicEffect->mData.mBaseCost; + x *= 0.5f * (it->mMagnMin + it->mMagnMax); + x *= it->mArea * 0.05f * magicEffect->mData.mBaseCost; if (it->mRange == ESM::RT_Target) - x *= 1.5; + x *= 1.5f; static const float fEffectCostMult = MWBase::Environment::get().getWorld()->getStore().get().find( "fEffectCostMult")->getFloat(); x *= fEffectCostMult; - float s = 2 * actor.getClass().getSkill(actor, spellSchoolToSkill(magicEffect->mData.mSchool)); + float s = 2.0f * actor.getClass().getSkill(actor, spellSchoolToSkill(magicEffect->mData.mSchool)); if (s - x < y) { y = s - x; @@ -174,12 +174,12 @@ namespace MWMechanics if (spell->mData.mFlags & ESM::Spell::F_Always) return 100; - int castBonus = -stats.getMagicEffects().get(ESM::MagicEffect::Sound).getMagnitude(); + float castBonus = -stats.getMagicEffects().get(ESM::MagicEffect::Sound).getMagnitude(); int actorWillpower = stats.getAttribute(ESM::Attribute::Willpower).getModified(); int actorLuck = stats.getAttribute(ESM::Attribute::Luck).getModified(); - float castChance = (lowestSkill - spell->mData.mCost + castBonus + 0.2 * actorWillpower + 0.1 * actorLuck) * stats.getFatigueTerm(); + float castChance = (lowestSkill - spell->mData.mCost + castBonus + 0.2f * actorWillpower + 0.1f * actorLuck) * stats.getFatigueTerm(); if (MWBase::Environment::get().getWorld()->getGodModeState() && actor.getRefData().getHandle() == "player") castChance = 100; @@ -267,9 +267,9 @@ namespace MWMechanics float resistance = getEffectResistanceAttribute(effectId, magicEffects); - float willpower = stats.getAttribute(ESM::Attribute::Willpower).getModified(); - float luck = stats.getAttribute(ESM::Attribute::Luck).getModified(); - float x = (willpower + 0.1 * luck) * stats.getFatigueTerm(); + int willpower = stats.getAttribute(ESM::Attribute::Willpower).getModified(); + float luck = static_cast(stats.getAttribute(ESM::Attribute::Luck).getModified()); + float x = (willpower + 0.1f * luck) * stats.getFatigueTerm(); // This makes spells that are easy to cast harder to resist and vice versa float castChance = 100.f; @@ -383,7 +383,7 @@ namespace MWMechanics target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::ResistCommonDisease).getMagnitude() : target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::ResistBlightDisease).getMagnitude(); - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + int roll = static_cast(std::rand()/ (static_cast (RAND_MAX) + 1) * 100); // [0, 99] if (roll <= x) { // Fully resisted, show message @@ -413,8 +413,8 @@ namespace MWMechanics bool absorbed = false; if (spell && caster != target && target.getClass().isActor()) { - int absorb = target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::SpellAbsorption).getMagnitude(); - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + float absorb = target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::SpellAbsorption).getMagnitude(); + int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] absorbed = (roll < absorb); if (absorbed) { @@ -462,8 +462,8 @@ namespace MWMechanics // Try reflecting if (!reflected && magnitudeMult > 0 && !caster.isEmpty() && caster != target && !(magicEffect->mData.mFlags & ESM::MagicEffect::Unreflectable)) { - int reflect = target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Reflect).getMagnitude(); - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + float reflect = target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Reflect).getMagnitude(); + int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] bool isReflected = (roll < reflect); if (isReflected) { @@ -502,7 +502,7 @@ namespace MWMechanics ActiveSpells::ActiveEffect effect; effect.mEffectId = effectIt->mEffectID; effect.mArg = MWMechanics::EffectKey(*effectIt).mArg; - effect.mDuration = effectIt->mDuration; + effect.mDuration = static_cast(effectIt->mDuration); effect.mMagnitude = magnitude; targetEffects.add(MWMechanics::EffectKey(*effectIt), MWMechanics::EffectParam(effect.mMagnitude)); @@ -613,7 +613,7 @@ namespace MWMechanics { if (caster.getRefData().getHandle() == "player") MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicLockSuccess}"); - target.getCellRef().setLockLevel(magnitude); + target.getCellRef().setLockLevel(static_cast(magnitude)); } } else if (effectId == ESM::MagicEffect::Open) @@ -721,10 +721,10 @@ namespace MWMechanics // Check if there's enough charge left if (enchantment->mData.mType == ESM::Enchantment::WhenUsed || enchantment->mData.mType == ESM::Enchantment::WhenStrikes) { - const int castCost = getEffectiveEnchantmentCastCost(enchantment->mData.mCost, mCaster); + const int castCost = getEffectiveEnchantmentCastCost(static_cast(enchantment->mData.mCost), mCaster); if (item.getCellRef().getEnchantmentCharge() == -1) - item.getCellRef().setEnchantmentCharge(enchantment->mData.mCharge); + item.getCellRef().setEnchantmentCharge(static_cast(enchantment->mData.mCharge)); if (item.getCellRef().getEnchantmentCharge() < castCost) { @@ -823,8 +823,8 @@ namespace MWMechanics bool fail = false; // Check success - int successChance = getSpellSuccessChance(spell, mCaster); - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + float successChance = getSpellSuccessChance(spell, mCaster); + int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] if (!fail && roll >= successChance) { if (mCaster.getRefData().getHandle() == "player") @@ -899,11 +899,11 @@ namespace MWMechanics const MWMechanics::CreatureStats& creatureStats = mCaster.getClass().getCreatureStats(mCaster); float x = (npcStats.getSkill (ESM::Skill::Alchemy).getModified() + - 0.2 * creatureStats.getAttribute (ESM::Attribute::Intelligence).getModified() - + 0.1 * creatureStats.getAttribute (ESM::Attribute::Luck).getModified()) + 0.2f * creatureStats.getAttribute (ESM::Attribute::Intelligence).getModified() + + 0.1f * creatureStats.getAttribute (ESM::Attribute::Luck).getModified()) * creatureStats.getFatigueTerm(); - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] if (roll > x) { // "X has no effect on you" @@ -915,24 +915,24 @@ namespace MWMechanics float magnitude = 0; float y = roll / std::min(x, 100.f); - y *= 0.25 * x; + y *= 0.25f * x; if (magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration) - effect.mDuration = int(y); + effect.mDuration = static_cast(y); else effect.mDuration = 1; if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude)) { if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)) - magnitude = int((0.05 * y) / (0.1 * magicEffect->mData.mBaseCost)); + magnitude = floor((0.05f * y) / (0.1f * magicEffect->mData.mBaseCost)); else - magnitude = int(y / (0.1 * magicEffect->mData.mBaseCost)); + magnitude = floor(y / (0.1f * magicEffect->mData.mBaseCost)); magnitude = std::max(1.f, magnitude); } else magnitude = 1; - effect.mMagnMax = magnitude; - effect.mMagnMin = magnitude; + effect.mMagnMax = static_cast(magnitude); + effect.mMagnMin = static_cast(magnitude); ESM::EffectList effects; effects.mList.push_back(effect); diff --git a/apps/openmw/mwmechanics/stat.cpp b/apps/openmw/mwmechanics/stat.cpp index 554f619a5..3216a46e6 100644 --- a/apps/openmw/mwmechanics/stat.cpp +++ b/apps/openmw/mwmechanics/stat.cpp @@ -15,10 +15,10 @@ void MWMechanics::AttributeValue::readState (const ESM::StatState& state) mDamage = state.mDamage; } -void MWMechanics::AttributeValue::setModifiers(int fortify, int drain, int absorb) +void MWMechanics::AttributeValue::setModifiers(float fortify, float drain, float absorb) { - mFortified = fortify; - mModifier = (fortify - drain) - absorb; + mFortified = static_cast(fortify); + mModifier = mFortified - static_cast(drain + absorb); } void MWMechanics::SkillValue::writeState (ESM::StatState& state) const diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index 5c41e007e..528bfdbe7 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -247,7 +247,7 @@ namespace MWMechanics int getModifier() const { return mModifier; } void setBase(int base) { mBase = std::max(0, base); } - void setModifiers(int fortify, int drain, int absorb); + void setModifiers(float fortify, float drain, float absorb); void damage(float damage) { mDamage = std::min(mDamage + damage, (float)(mBase + mFortified)); } void restore(float amount) { mDamage -= std::min(mDamage, amount); } diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 965083019..bdaa2d515 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -111,7 +111,7 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool sg->setOrigin(ptr.getRefData().getBaseNode()->getPosition()); mStaticGeometrySmall[ptr.getCell()] = sg; - sg->setRenderingDistance(Settings::Manager::getInt("small object distance", "Viewing distance")); + sg->setRenderingDistance(static_cast(Settings::Manager::getInt("small object distance", "Viewing distance"))); } else sg = mStaticGeometrySmall[ptr.getCell()]; diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 020f9561a..9ad490d69 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -630,7 +630,7 @@ void MWWorld::InventoryStore::updateRechargingItems() it->getClass().getEnchantment(*it)); if (enchantment->mData.mType == ESM::Enchantment::WhenUsed || enchantment->mData.mType == ESM::Enchantment::WhenStrikes) - mRechargingItems.push_back(std::make_pair(it, enchantment->mData.mCharge)); + mRechargingItems.push_back(std::make_pair(it, static_cast(enchantment->mData.mCharge))); } } } From 128371c902cf40f98d6199e7dc267c9f3e778130 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 8 Mar 2015 15:50:50 +1100 Subject: [PATCH 579/740] Copy base data to modified. --- apps/opencs/model/world/record.hpp | 4 +++- apps/opencs/model/world/refidcollection.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp index 861fc47a3..2b556636f 100644 --- a/apps/opencs/model/world/record.hpp +++ b/apps/opencs/model/world/record.hpp @@ -61,7 +61,9 @@ namespace CSMWorld template RecordBase *Record::clone() const { - return new Record (*this); + Record *copy = new Record (*this); + copy->mModified = (*this).get(); + return copy; } template diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 75429d906..779d5a40c 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -471,7 +471,7 @@ void CSMWorld::RefIdCollection::cloneRecord(const std::string& origin, const CSMWorld::UniversalId::Type type) { std::auto_ptr newRecord(mData.getRecord(mData.searchId(origin)).clone()); - newRecord->mState = RecordBase::State_BaseOnly; + newRecord->mState = RecordBase::State_ModifiedOnly; mAdapters.find(type)->second->setId(*newRecord, destination); mData.insertRecord(*newRecord, type, destination); } From f19863b54577406d43f5a30552b26088263bf1f2 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 8 Mar 2015 18:11:54 +1300 Subject: [PATCH 580/740] fixing MSVC 2013 warning C4244: & C4305 conversion from 'const float' to 'int', possible loss of data conversion from 'double' to 'int', possible loss of data conversion from 'float' to 'int', possible loss of data --- apps/openmw/mwrender/debugging.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/debugging.cpp b/apps/openmw/mwrender/debugging.cpp index 972c1b6dd..79eeff2d0 100644 --- a/apps/openmw/mwrender/debugging.cpp +++ b/apps/openmw/mwrender/debugging.cpp @@ -21,6 +21,7 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwmechanics/pathfinding.hpp" #include "renderconst.hpp" @@ -81,12 +82,12 @@ ManualObject *Debugging::createPathgridLines(const ESM::Pathgrid *pathgrid) { const ESM::Pathgrid::Edge &edge = *it; const ESM::Pathgrid::Point &p1 = pathgrid->mPoints[edge.mV0], &p2 = pathgrid->mPoints[edge.mV1]; - Vector3 direction = (Vector3(p2.mX, p2.mY, p2.mZ) - Vector3(p1.mX, p1.mY, p1.mZ)); + Vector3 direction = (MWMechanics::PathFinder::MakeOgreVector3(p2) - MWMechanics::PathFinder::MakeOgreVector3(p1)); Vector3 lineDisplacement = direction.crossProduct(Vector3::UNIT_Z).normalisedCopy(); lineDisplacement = lineDisplacement * POINT_MESH_BASE + Vector3(0, 0, 10); // move lines up a little, so they will be less covered by meshes/landscape - result->position(Vector3(p1.mX, p1.mY, p1.mZ) + lineDisplacement); - result->position(Vector3(p2.mX, p2.mY, p2.mZ) + lineDisplacement); + result->position(MWMechanics::PathFinder::MakeOgreVector3(p1) + lineDisplacement); + result->position(MWMechanics::PathFinder::MakeOgreVector3(p2) + lineDisplacement); } result->end(); @@ -108,7 +109,7 @@ ManualObject *Debugging::createPathgridPoints(const ESM::Pathgrid *pathgrid) it != pathgrid->mPoints.end(); ++it, startIndex += 6) { - Vector3 pointPos(it->mX, it->mY, it->mZ); + Vector3 pointPos(MWMechanics::PathFinder::MakeOgreVector3(*it)); if (!first) { @@ -117,11 +118,13 @@ ManualObject *Debugging::createPathgridPoints(const ESM::Pathgrid *pathgrid) result->index(startIndex); // start point of current octahedron } + Ogre::Real pointMeshBase = static_cast(POINT_MESH_BASE); + result->position(pointPos + Vector3(0, 0, height)); // 0 - result->position(pointPos + Vector3(-POINT_MESH_BASE, -POINT_MESH_BASE, 0)); // 1 - result->position(pointPos + Vector3(POINT_MESH_BASE, -POINT_MESH_BASE, 0)); // 2 - result->position(pointPos + Vector3(POINT_MESH_BASE, POINT_MESH_BASE, 0)); // 3 - result->position(pointPos + Vector3(-POINT_MESH_BASE, POINT_MESH_BASE, 0)); // 4 + result->position(pointPos + Vector3(-pointMeshBase, -pointMeshBase, 0)); // 1 + result->position(pointPos + Vector3(pointMeshBase, -pointMeshBase, 0)); // 2 + result->position(pointPos + Vector3(pointMeshBase, pointMeshBase, 0)); // 3 + result->position(pointPos + Vector3(-pointMeshBase, pointMeshBase, 0)); // 4 result->position(pointPos + Vector3(0, 0, -height)); // 5 result->index(startIndex + 0); @@ -239,8 +242,8 @@ void Debugging::enableCellPathgrid(MWWorld::CellStore *store) Vector3 cellPathGridPos(0, 0, 0); if (store->getCell()->isExterior()) { - cellPathGridPos.x = store->getCell()->mData.mX * ESM::Land::REAL_SIZE; - cellPathGridPos.y = store->getCell()->mData.mY * ESM::Land::REAL_SIZE; + cellPathGridPos.x = static_cast(store->getCell()->mData.mX * ESM::Land::REAL_SIZE); + cellPathGridPos.y = static_cast(store->getCell()->mData.mY * ESM::Land::REAL_SIZE); } SceneNode *cellPathGrid = mPathGridRoot->createChildSceneNode(cellPathGridPos); cellPathGrid->attachObject(createPathgridLines(pathgrid)); From ba7fc8609cb2fadda7941431ef7585a64772d0bf Mon Sep 17 00:00:00 2001 From: Ivy Foster Date: Sun, 8 Mar 2015 15:23:46 -0500 Subject: [PATCH 581/740] Add toggle sneak option; fix bug #2119 To enable toggle sneak mode, set "toggle sneak = true" in the [Input] section of settings.cfg. Outstanding issues: - In toggle sneak mode, holding the Sneak button causes rapid, repeated toggling. - The button in the settings menu doesn't do anything. --- apps/openmw/mwinput/inputmanagerimp.cpp | 19 ++++++++++++++++++- apps/openmw/mwinput/inputmanagerimp.hpp | 3 +++ files/mygui/openmw_settings_window.layout | 18 ++++++++++++++---- files/settings-default.cfg | 2 ++ 4 files changed, 37 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 21576785c..462008b09 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -124,6 +124,8 @@ namespace MWInput , mTimeIdle(0.f) , mOverencumberedMessageDelay(0.f) , mAlwaysRunActive(Settings::Manager::getBool("always run", "Input")) + , mSneakToggles(Settings::Manager::getBool("toggle sneak", "Input")) + , mSneaking(false) , mAttemptJump(false) , mControlsDisabled(false) , mJoystickLastUsed(false) @@ -522,7 +524,16 @@ namespace MWInput } } - mPlayer->setSneak(actionIsActive(A_Sneak)); + if (mSneakToggles) + { + if (actionIsActive(A_Sneak)) + { + toggleSneaking(); + mPlayer->setSneak(mSneaking); + } + } + else + mPlayer->setSneak(actionIsActive(A_Sneak)); if (mAttemptJump && mControlSwitch["playerjumping"]) { @@ -1089,6 +1100,12 @@ namespace MWInput Settings::Manager::setBool("always run", "Input", mAlwaysRunActive); } + void InputManager::toggleSneaking() + { + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; + mSneaking = !mSneaking; + } + void InputManager::resetIdleTime() { if (mTimeIdle < 0) diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 39091b7b1..558801023 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -180,6 +180,8 @@ namespace MWInput int mMouseWheel; bool mUserFileExists; bool mAlwaysRunActive; + bool mSneakToggles; + bool mSneaking; bool mAttemptJump; std::map mControlSwitch; @@ -208,6 +210,7 @@ namespace MWInput void toggleJournal(); void activate(); void toggleWalking(); + void toggleSneaking(); void toggleAutoMove(); void rest(); void quickLoad(); diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 2efd5841e..73d05600a 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -196,10 +196,20 @@ - + + + + + + + + + + + - + @@ -209,11 +219,11 @@ - + - + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 19b570e2a..de22e1b56 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -194,6 +194,8 @@ always run = false allow third person zoom = false +toggle sneak = false + [Game] # Always use the most powerful attack when striking with a weapon (chop, slash or thrust) best attack = false From 4f100e687003c7c0e49fc1f78743d885c9c52369 Mon Sep 17 00:00:00 2001 From: Ivy Foster Date: Sun, 8 Mar 2015 16:08:45 -0500 Subject: [PATCH 582/740] Fix rapid toggling when holding sneak button. --- apps/openmw/mwinput/inputmanagerimp.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 462008b09..05fbbb1fe 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -356,6 +356,12 @@ namespace MWInput case A_CycleWeaponRight: MWBase::Environment::get().getWindowManager()->cycleWeapon(true); break; + case A_Sneak: + if (mSneakToggles) + { + toggleSneaking(); + } + break; } } } @@ -524,16 +530,10 @@ namespace MWInput } } - if (mSneakToggles) + if (!mSneakToggles) { - if (actionIsActive(A_Sneak)) - { - toggleSneaking(); - mPlayer->setSneak(mSneaking); - } - } - else mPlayer->setSneak(actionIsActive(A_Sneak)); + } if (mAttemptJump && mControlSwitch["playerjumping"]) { @@ -1104,6 +1104,7 @@ namespace MWInput { if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; mSneaking = !mSneaking; + mPlayer->setSneak(mSneaking); } void InputManager::resetIdleTime() From f7089446575de574b5d06a64ac98662ccfa2fcca Mon Sep 17 00:00:00 2001 From: Ivy Foster Date: Sun, 8 Mar 2015 16:15:43 -0500 Subject: [PATCH 583/740] Remove toggle sneak menu option Users can change the option in settings.cfg. --- files/mygui/openmw_settings_window.layout | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 73d05600a..2efd5841e 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -196,20 +196,10 @@ - - - - - - - - - - - + - + @@ -219,11 +209,11 @@ - + - + From 3d5c1d1190ffcb509ae9be48c9ee2d9252510482 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Mar 2015 16:23:02 +0100 Subject: [PATCH 584/740] Adjust fix for maximum attribute damage limit --- apps/openmw/mwmechanics/actors.cpp | 8 ++++---- apps/openmw/mwmechanics/stat.cpp | 8 +------- apps/openmw/mwmechanics/stat.hpp | 27 ++++++++++++++------------- 3 files changed, 19 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 56646a83b..eef30f112 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -515,8 +515,8 @@ namespace MWMechanics for(int i = 0;i < ESM::Attribute::Length;++i) { AttributeValue stat = creatureStats.getAttribute(i); - stat.setModifiers(effects.get(EffectKey(ESM::MagicEffect::FortifyAttribute, i)).getMagnitude(), - effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).getMagnitude(), + stat.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifyAttribute, i)).getMagnitude() - + effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).getMagnitude() - effects.get(EffectKey(ESM::MagicEffect::AbsorbAttribute, i)).getMagnitude()); stat.damage(effects.get(EffectKey(ESM::MagicEffect::DamageAttribute, i)).getMagnitude() * duration); @@ -782,8 +782,8 @@ namespace MWMechanics for(int i = 0;i < ESM::Skill::Length;++i) { SkillValue& skill = npcStats.getSkill(i); - skill.setModifiers(effects.get(EffectKey(ESM::MagicEffect::FortifySkill, i)).getMagnitude(), - effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).getMagnitude(), + skill.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifySkill, i)).getMagnitude() - + effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).getMagnitude() - effects.get(EffectKey(ESM::MagicEffect::AbsorbSkill, i)).getMagnitude()); skill.damage(effects.get(EffectKey(ESM::MagicEffect::DamageSkill, i)).getMagnitude() * duration); diff --git a/apps/openmw/mwmechanics/stat.cpp b/apps/openmw/mwmechanics/stat.cpp index 3216a46e6..1b909d579 100644 --- a/apps/openmw/mwmechanics/stat.cpp +++ b/apps/openmw/mwmechanics/stat.cpp @@ -15,12 +15,6 @@ void MWMechanics::AttributeValue::readState (const ESM::StatState& state) mDamage = state.mDamage; } -void MWMechanics::AttributeValue::setModifiers(float fortify, float drain, float absorb) -{ - mFortified = static_cast(fortify); - mModifier = mFortified - static_cast(drain + absorb); -} - void MWMechanics::SkillValue::writeState (ESM::StatState& state) const { AttributeValue::writeState (state); @@ -31,4 +25,4 @@ void MWMechanics::SkillValue::readState (const ESM::StatState& state) { AttributeValue::readState (state); mProgress = state.mProgress; -} \ No newline at end of file +} diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index 528bfdbe7..30c7d3130 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -235,28 +235,31 @@ namespace MWMechanics class AttributeValue { int mBase; - int mFortified; - int mModifier; // net effect of Fortified, Drain & Absorb + int mModifier; float mDamage; // needs to be float to allow continuous damage public: - AttributeValue() : mBase(0), mFortified(0), mModifier(0), mDamage(0) {} + AttributeValue() : mBase(0), mModifier(0), mDamage(0) {} int getModified() const { return std::max(0, mBase - (int) mDamage + mModifier); } int getBase() const { return mBase; } int getModifier() const { return mModifier; } void setBase(int base) { mBase = std::max(0, base); } - void setModifiers(float fortify, float drain, float absorb); - void damage(float damage) { mDamage = std::min(mDamage + damage, (float)(mBase + mFortified)); } + void setModifier(int mod) { mModifier = mod; } + + // Maximum attribute damage is limited to the modified value. + // Note: I think MW applies damage directly to mModified, since you can also + // "restore" drained attributes. We need to rewrite the magic effect system to support this. + void damage(float damage) { mDamage += std::min(damage, (float)getModified()); } void restore(float amount) { mDamage -= std::min(mDamage, amount); } + float getDamage() const { return mDamage; } + void writeState (ESM::StatState& state) const; void readState (const ESM::StatState& state); - - friend bool operator== (const AttributeValue& left, const AttributeValue& right); }; class SkillValue : public AttributeValue @@ -270,16 +273,13 @@ namespace MWMechanics void writeState (ESM::StatState& state) const; void readState (const ESM::StatState& state); - - friend bool operator== (const SkillValue& left, const SkillValue& right); }; inline bool operator== (const AttributeValue& left, const AttributeValue& right) { return left.getBase() == right.getBase() - && left.mFortified == right.mFortified && left.getModifier() == right.getModifier() - && left.mDamage == right.mDamage; + && left.getDamage() == right.getDamage(); } inline bool operator!= (const AttributeValue& left, const AttributeValue& right) { @@ -288,8 +288,9 @@ namespace MWMechanics inline bool operator== (const SkillValue& left, const SkillValue& right) { - // delegate to base class for most of the work - return (static_cast(left) == right) + return left.getBase() == right.getBase() + && left.getModifier() == right.getModifier() + && left.getDamage() == right.getDamage() && left.getProgress() == right.getProgress(); } inline bool operator!= (const SkillValue& left, const SkillValue& right) From 36e1b6cc4820491ecb246172830b96c578ca5f43 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Mar 2015 16:30:41 +0100 Subject: [PATCH 585/740] Support fatigue below zero for the Drain effect (Fixes #2430) --- apps/openmw/mwmechanics/actors.cpp | 4 +++- apps/openmw/mwmechanics/stat.hpp | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index eef30f112..ca4105bc6 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -547,7 +547,9 @@ namespace MWMechanics { DynamicStat stat = creatureStats.getDynamic(i); stat.setModifier(effects.get(ESM::MagicEffect::FortifyHealth+i).getMagnitude() - - effects.get(ESM::MagicEffect::DrainHealth+i).getMagnitude()); + effects.get(ESM::MagicEffect::DrainHealth+i).getMagnitude(), + // Fatigue can be decreased below zero meaning the actor will be knocked out + i == 2); float currentDiff = creatureStats.getMagicEffects().get(ESM::MagicEffect::RestoreHealth+i).getMagnitude() diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index 30c7d3130..ffbc19e15 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -170,10 +170,10 @@ namespace MWMechanics } /// Change modified relatively. - void modify (const T& diff) + void modify (const T& diff, bool allowCurrentDecreaseBelowZero=false) { mStatic.modify (diff); - setCurrent (getCurrent()+diff); + setCurrent (getCurrent()+diff, allowCurrentDecreaseBelowZero); } void setCurrent (const T& value, bool allowDecreaseBelowZero = false) @@ -198,11 +198,11 @@ namespace MWMechanics } } - void setModifier (const T& modifier) + void setModifier (const T& modifier, bool allowCurrentDecreaseBelowZero=false) { T diff = modifier - mStatic.getModifier(); mStatic.setModifier (modifier); - setCurrent (getCurrent()+diff); + setCurrent (getCurrent()+diff, allowCurrentDecreaseBelowZero); } void writeState (ESM::StatState& state) const From 457c13509790177c7d140602dcda7b07f5f80ab2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Mar 2015 19:03:35 +0100 Subject: [PATCH 586/740] Remove old workaround --- apps/openmw/engine.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 76b573941..92731ee1a 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -197,9 +197,6 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) Uint32 flags = SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE|SDL_INIT_GAMECONTROLLER|SDL_INIT_JOYSTICK; if(SDL_WasInit(flags) == 0) { - //kindly ask SDL not to trash our OGL context - //might this be related to http://bugzilla.libsdl.org/show_bug.cgi?id=748 ? - SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software"); SDL_SetMainReady(); if(SDL_Init(flags) != 0) { From e30f240ba273df552d3fbffbb32aef4c70239ccb Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Mar 2015 20:44:41 +0100 Subject: [PATCH 587/740] Add travel service support for creatures (Fixes #2432) --- apps/esmtool/record.cpp | 40 ++++++++++++------- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 3 +- apps/openmw/mwgui/travelwindow.cpp | 16 +++++--- components/CMakeLists.txt | 2 +- components/esm/loadcrea.cpp | 12 ++++++ components/esm/loadcrea.hpp | 4 ++ components/esm/loadnpc.cpp | 24 +++++------ components/esm/loadnpc.hpp | 12 +++--- components/esm/transport.cpp | 33 +++++++++++++++ components/esm/transport.hpp | 36 +++++++++++++++++ 10 files changed, 140 insertions(+), 42 deletions(-) create mode 100644 components/esm/transport.cpp create mode 100644 components/esm/transport.hpp diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index be9b03e80..2ee6c54bb 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -6,6 +6,9 @@ #include +namespace +{ + void printAIPackage(ESM::AIPackage p) { std::cout << " AI Type: " << aiTypeLabel(p.mType) @@ -149,6 +152,26 @@ void printEffectList(ESM::EffectList effects) } } +void printTransport(const std::vector& transport) +{ + std::vector::const_iterator dit; + for (dit = transport.begin(); dit != transport.end(); ++dit) + { + std::cout << " Destination Position: " + << boost::format("%12.3f") % dit->mPos.pos[0] << "," + << boost::format("%12.3f") % dit->mPos.pos[1] << "," + << boost::format("%12.3f") % dit->mPos.pos[2] << ")" << std::endl; + std::cout << " Destination Rotation: " + << boost::format("%9.6f") % dit->mPos.rot[0] << "," + << boost::format("%9.6f") % dit->mPos.rot[1] << "," + << boost::format("%9.6f") % dit->mPos.rot[2] << ")" << std::endl; + if (dit->mCellName != "") + std::cout << " Destination Cell: " << dit->mCellName << std::endl; + } +} + +} + namespace EsmTool { RecordBase * @@ -631,6 +654,8 @@ void Record::print() for (sit = mData.mSpells.mList.begin(); sit != mData.mSpells.mList.end(); ++sit) std::cout << " Spell: " << *sit << std::endl; + printTransport(mData.getTransport()); + std::cout << " Artifical Intelligence: " << mData.mHasAI << std::endl; std::cout << " AI Hello:" << (int)mData.mAiData.mHello << std::endl; std::cout << " AI Fight:" << (int)mData.mAiData.mFight << std::endl; @@ -1042,20 +1067,7 @@ void Record::print() for (sit = mData.mSpells.mList.begin(); sit != mData.mSpells.mList.end(); ++sit) std::cout << " Spell: " << *sit << std::endl; - std::vector::iterator dit; - for (dit = mData.mTransport.begin(); dit != mData.mTransport.end(); ++dit) - { - std::cout << " Destination Position: " - << boost::format("%12.3f") % dit->mPos.pos[0] << "," - << boost::format("%12.3f") % dit->mPos.pos[1] << "," - << boost::format("%12.3f") % dit->mPos.pos[2] << ")" << std::endl; - std::cout << " Destination Rotation: " - << boost::format("%9.6f") % dit->mPos.rot[0] << "," - << boost::format("%9.6f") % dit->mPos.rot[1] << "," - << boost::format("%9.6f") % dit->mPos.rot[2] << ")" << std::endl; - if (dit->mCellName != "") - std::cout << " Destination Cell: " << dit->mCellName << std::endl; - } + printTransport(mData.getTransport()); std::cout << " Artifical Intelligence: " << mData.mHasAI << std::endl; std::cout << " AI Hello:" << (int)mData.mAiData.mHello << std::endl; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index e8dcf535c..00e59e2a5 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -383,7 +383,8 @@ namespace MWDialogue || services & ESM::NPC::Misc) windowServices |= MWGui::DialogueWindow::Service_Trade; - if(mActor.getTypeName() == typeid(ESM::NPC).name() && !mActor.get()->mBase->mTransport.empty()) + 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) diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 6a45e6026..4da1ab33a 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -111,20 +111,26 @@ namespace MWGui mPtr = actor; clearDestinations(); - for(unsigned int i = 0;i()->mBase->mTransport.size();i++) + std::vector transport; + if (mPtr.getClass().isNpc()) + transport = mPtr.get()->mBase->getTransport(); + else if (mPtr.getTypeName() == typeid(ESM::Creature).name()) + transport = mPtr.get()->mBase->getTransport(); + + for(unsigned int i = 0;i()->mBase->mTransport[i].mCellName; + std::string cellname = transport[i].mCellName; bool interior = true; int x,y; - MWBase::Environment::get().getWorld()->positionToIndex(mPtr.get()->mBase->mTransport[i].mPos.pos[0], - mPtr.get()->mBase->mTransport[i].mPos.pos[1],x,y); + MWBase::Environment::get().getWorld()->positionToIndex(transport[i].mPos.pos[0], + transport[i].mPos.pos[1],x,y); if (cellname == "") { MWWorld::CellStore* cell = MWBase::Environment::get().getWorld()->getExterior(x,y); cellname = MWBase::Environment::get().getWorld()->getCellName(cell); interior = false; } - addDestination(cellname,mPtr.get()->mBase->mTransport[i].mPos,interior); + addDestination(cellname,transport[i].mPos,interior); } updateLabels(); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a49e54dd3..971897619 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -62,7 +62,7 @@ add_component_dir (esm loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap inventorystate containerstate npcstate creaturestate dialoguestate statstate npcstats creaturestats weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate debugprofile - aisequence magiceffects util custommarkerstate stolenitems + aisequence magiceffects util custommarkerstate stolenitems transport ) add_component_dir (esmterrain diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index 86eede34e..50c47349c 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -15,6 +15,7 @@ namespace ESM { mAiPackage.mList.clear(); mInventory.mList.clear(); mSpells.mList.clear(); + mTransport.mList.clear(); mScale = 1.f; mHasAI = false; @@ -59,6 +60,10 @@ namespace ESM { esm.getHExact(&mAiData, sizeof(mAiData)); mHasAI = true; break; + case ESM::FourCC<'D','O','D','T'>::value: + case ESM::FourCC<'D','N','A','M'>::value: + mTransport.add(esm); + break; case AI_Wander: case AI_Activate: case AI_Escort: @@ -94,6 +99,7 @@ namespace ESM { if (mHasAI) { esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); } + mTransport.save(esm); mAiPackage.save(esm); } @@ -120,5 +126,11 @@ namespace ESM { mAiData.blank(); mAiData.mServices = 0; mAiPackage.mList.clear(); + mTransport.mList.clear(); + } + + const std::vector& Creature::getTransport() const + { + return mTransport.mList; } } diff --git a/components/esm/loadcrea.hpp b/components/esm/loadcrea.hpp index e459dded7..1b02aa0ab 100644 --- a/components/esm/loadcrea.hpp +++ b/components/esm/loadcrea.hpp @@ -6,6 +6,7 @@ #include "loadcont.hpp" #include "spelllist.hpp" #include "aipackage.hpp" +#include "transport.hpp" namespace ESM { @@ -92,6 +93,9 @@ struct Creature bool mHasAI; AIData mAiData; AIPackageList mAiPackage; + Transport mTransport; + + const std::vector& getTransport() const; void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index 98cedbe42..751c7f252 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -14,7 +14,7 @@ namespace ESM mSpells.mList.clear(); mInventory.mList.clear(); - mTransport.clear(); + mTransport.mList.clear(); mAiPackage.mList.clear(); bool hasNpdt = false; @@ -81,14 +81,8 @@ namespace ESM mHasAI= true; break; case ESM::FourCC<'D','O','D','T'>::value: - { - Dest dodt; - esm.getHExact(&dodt.mPos, 24); - mTransport.push_back(dodt); - break; - } case ESM::FourCC<'D','N','A','M'>::value: - mTransport.back().mCellName = esm.getHString(); + mTransport.add(esm); break; case AI_Wander: case AI_Activate: @@ -131,11 +125,8 @@ namespace ESM esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); } - typedef std::vector::const_iterator DestIter; - for (DestIter it = mTransport.begin(); it != mTransport.end(); ++it) { - esm.writeHNT("DODT", it->mPos, sizeof(it->mPos)); - esm.writeHNOCString("DNAM", it->mCellName); - } + mTransport.save(esm); + mAiPackage.save(esm); } @@ -177,7 +168,7 @@ namespace ESM mSpells.mList.clear(); mAiData.blank(); mHasAI = false; - mTransport.clear(); + mTransport.mList.clear(); mAiPackage.mList.clear(); mName.clear(); mModel.clear(); @@ -198,4 +189,9 @@ namespace ESM else // NPC_DEFAULT return mNpdt52.mRank; } + + const std::vector& NPC::getTransport() const + { + return mTransport.mList; + } } diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index 9dc3be513..b535b91b0 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -9,6 +9,7 @@ #include "aipackage.hpp" #include "spelllist.hpp" #include "loadskil.hpp" +#include "transport.hpp" namespace ESM { @@ -98,12 +99,6 @@ struct NPC char mUnknown1, mUnknown2, mUnknown3; int mGold; }; // 12 bytes - - struct Dest - { - Position mPos; - std::string mCellName; - }; #pragma pack(pop) unsigned char mNpdtType; @@ -122,7 +117,10 @@ struct NPC AIData mAiData; bool mHasAI; - std::vector mTransport; + Transport mTransport; + + const std::vector& getTransport() const; + AIPackageList mAiPackage; std::string mId, mName, mModel, mRace, mClass, mFaction, mScript; diff --git a/components/esm/transport.cpp b/components/esm/transport.cpp new file mode 100644 index 000000000..da0a5f767 --- /dev/null +++ b/components/esm/transport.cpp @@ -0,0 +1,33 @@ +#include "transport.hpp" + +#include +#include + +namespace ESM +{ + + void Transport::add(ESMReader &esm) + { + if (esm.retSubName().val == ESM::FourCC<'D','O','D','T'>::value) + { + Dest dodt; + esm.getHExact(&dodt.mPos, 24); + mList.push_back(dodt); + } + else if (esm.retSubName().val == ESM::FourCC<'D','N','A','M'>::value) + { + mList.back().mCellName = esm.getHString(); + } + } + + void Transport::save(ESMWriter &esm) const + { + typedef std::vector::const_iterator DestIter; + for (DestIter it = mList.begin(); it != mList.end(); ++it) + { + esm.writeHNT("DODT", it->mPos, sizeof(it->mPos)); + esm.writeHNOCString("DNAM", it->mCellName); + } + } + +} diff --git a/components/esm/transport.hpp b/components/esm/transport.hpp new file mode 100644 index 000000000..10d4013f7 --- /dev/null +++ b/components/esm/transport.hpp @@ -0,0 +1,36 @@ +#ifndef OPENMW_COMPONENTS_ESM_TRANSPORT_H +#define OPENMW_COMPONENTS_ESM_TRANSPORT_H + +#include +#include + +#include "defs.hpp" + +namespace ESM +{ + + class ESMReader; + class ESMWriter; + + /// List of travel service destination. Shared by CREA and NPC_ records. + struct Transport + { + + struct Dest + { + Position mPos; + std::string mCellName; + }; + + std::vector mList; + + /// Load one destination, assumes the subrecord name was already read + void add(ESMReader &esm); + + void save(ESMWriter &esm) const; + + }; + +} + +#endif From ef34d8b3fb5e00caec7aaa0e6ea2dfe6b499d713 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Mar 2015 22:17:02 +0100 Subject: [PATCH 588/740] Markdown syntax fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 63a313896..f3f562925 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Getting Started * [Testing the game](https://wiki.openmw.org/index.php?title=Testing) * [How to contribute](https://wiki.openmw.org/index.php?title=Contribution_Wanted) * [Report a bug](http://bugs.openmw.org/projects/openmw) - read the [guidelines](https://wiki.openmw.org/index.php?title=Bug_Reporting_Guidelines) before submitting your first bug! -* [Known issues] (http://bugs.openmw.org/projects/openmw/issues?utf8=%E2%9C%93&set_filter=1&f%5B%5D=status_id&op%5Bstatus_id%5D=%3D&v%5Bstatus_id%5D%5B%5D=7&f%5B%5D=tracker_id&op%5Btracker_id%5D=%3D&v%5Btracker_id%5D%5B%5D=1&f%5B%5D=&c%5B%5D=project&c%5B%5D=tracker&c%5B%5D=status&c%5B%5D=priority&c%5B%5D=subject&c%5B%5D=assigned_to&c%5B%5D=updated_on&group_by=tracker) +* [Known issues](http://bugs.openmw.org/projects/openmw/issues?utf8=%E2%9C%93&set_filter=1&f%5B%5D=status_id&op%5Bstatus_id%5D=%3D&v%5Bstatus_id%5D%5B%5D=7&f%5B%5D=tracker_id&op%5Btracker_id%5D=%3D&v%5Btracker_id%5D%5B%5D=1&f%5B%5D=&c%5B%5D=project&c%5B%5D=tracker&c%5B%5D=status&c%5B%5D=priority&c%5B%5D=subject&c%5B%5D=assigned_to&c%5B%5D=updated_on&group_by=tracker) The data path ------------- From 6087a18c94e418c43b681accfb72efdef7cb2242 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 9 Mar 2015 14:58:07 +1100 Subject: [PATCH 589/740] Implement clone() using a new Record constructor. --- apps/opencs/model/world/record.hpp | 20 +++++++++++++++++--- apps/opencs/model/world/refidcollection.cpp | 1 - 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp index 2b556636f..1f97ece93 100644 --- a/apps/opencs/model/world/record.hpp +++ b/apps/opencs/model/world/record.hpp @@ -38,6 +38,10 @@ namespace CSMWorld ESXRecordT mBase; ESXRecordT mModified; + Record() {} + Record(State state, + const ESXRecordT *base = 0, const ESXRecordT *modified = 0); + virtual RecordBase *clone() const; virtual void assign (const RecordBase& record); @@ -58,12 +62,22 @@ namespace CSMWorld ///< Merge modified into base. }; + template + Record::Record(State state, const ESXRecordT *base = 0, const ESXRecordT *modified = 0) + { + if(base) + mBase = *base; + + if(modified) + mModified = *modified; + + this->mState = state; + } + template RecordBase *Record::clone() const { - Record *copy = new Record (*this); - copy->mModified = (*this).get(); - return copy; + return new Record (State_ModifiedOnly, 0, &(this->get())); } template diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 779d5a40c..011b5cc0e 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -471,7 +471,6 @@ void CSMWorld::RefIdCollection::cloneRecord(const std::string& origin, const CSMWorld::UniversalId::Type type) { std::auto_ptr newRecord(mData.getRecord(mData.searchId(origin)).clone()); - newRecord->mState = RecordBase::State_ModifiedOnly; mAdapters.find(type)->second->setId(*newRecord, destination); mData.insertRecord(*newRecord, type, destination); } From f90cdec53b122b220a20fadda1e82122b93eb2fb Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 9 Mar 2015 16:24:35 +1100 Subject: [PATCH 590/740] Remove default parameters from the implementation. --- apps/opencs/model/world/record.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp index 1f97ece93..5f935e30d 100644 --- a/apps/opencs/model/world/record.hpp +++ b/apps/opencs/model/world/record.hpp @@ -63,7 +63,7 @@ namespace CSMWorld }; template - Record::Record(State state, const ESXRecordT *base = 0, const ESXRecordT *modified = 0) + Record::Record(State state, const ESXRecordT *base, const ESXRecordT *modified) { if(base) mBase = *base; From 8b3adec3ec5e8009c3266b72a660fe4c2f3712a5 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 9 Mar 2015 21:25:41 +1100 Subject: [PATCH 591/740] Added a missing copy constructor. --- apps/opencs/model/world/record.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp index 5f935e30d..814e116dd 100644 --- a/apps/opencs/model/world/record.hpp +++ b/apps/opencs/model/world/record.hpp @@ -38,7 +38,8 @@ namespace CSMWorld ESXRecordT mBase; ESXRecordT mModified; - Record() {} + Record() = default; + Record(const Record&) = default; Record(State state, const ESXRecordT *base = 0, const ESXRecordT *modified = 0); From bef0bd13f39d74425917633cc61a563f0e8f9929 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 9 Mar 2015 16:46:09 +0100 Subject: [PATCH 592/740] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 90c543ada..0cd961c61 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -39,6 +39,7 @@ Programmers Eli2 Emanuel Guével (potatoesmaster) eroen + escondida Evgeniy Mineev (sandstranger) Fil Krynicki (filkry) Gašper Sedej From 88f746574def3a815c63a9e80c03235d60ed323f Mon Sep 17 00:00:00 2001 From: Scott Howard Date: Mon, 9 Mar 2015 14:37:43 -0400 Subject: [PATCH 593/740] fix compiler detection and adding build flags in CMakeLists.txt --- CMakeLists.txt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 91f12d6da..30710f532 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -349,22 +349,22 @@ if (NOT WIN32 AND NOT APPLE) "${OpenMW_BINARY_DIR}/openmw-cs.desktop") endif() -# Compiler settings -if (CMAKE_COMPILER_IS_GNUCC) - set_property(GLOBAL APPEND_STRING PROPERTY COMPILE_FLAGS "-Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++98 -pedantic -Wno-long-long") +# CXX Compiler settings +if (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++98 -pedantic -Wno-long-long") execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) - if ("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6) - set_property(GLOBAL APPEND_STRING PROPERTY COMPILE_FLAGS "-Wno-unused-but-set-parameter") - endif("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6) + if (CMAKE_CXX_COMPILER_ID STREQUAL GNU AND "${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-but-set-parameter") + endif(CMAKE_CXX_COMPILER_ID STREQUAL GNU AND "${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6) elseif (MSVC) # Enable link-time code generation globally for all linking set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL") set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG") set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG") set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "${CMAKE_STATIC_LINKER_FLAGS_RELEASE} /LTCG") -endif (CMAKE_COMPILER_IS_GNUCC) +endif (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang) IF(NOT WIN32 AND NOT APPLE) # Linux building @@ -673,7 +673,7 @@ if (WIN32) set(WARNINGS "${WARNINGS} /wd${d}") endforeach(d) - set_property(GLOBAL APPEND_STRING PROPERTY COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNINGS} ${MT_BUILD}") # boost::wave has a few issues with signed / unsigned conversions, so we suppress those here set(SHINY_WARNINGS "${WARNINGS} /wd4245") From 8ac7b77d36477eacae7a2d81009d122390cbb142 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 10 Mar 2015 06:51:54 +1100 Subject: [PATCH 594/740] For RefId's, modify a copy of the base record rather than modifying the record directly. --- apps/opencs/model/world/refidadapterimp.hpp | 70 ++++++++++++++++----- 1 file changed, 53 insertions(+), 17 deletions(-) diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 034905781..202b7781c 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -156,10 +156,16 @@ namespace CSMWorld Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter::getType()))); + RecordT record2 = record.get(); if (column==mModel.mModel) - record.get().mModel = value.toString().toUtf8().constData(); + record2.mModel = value.toString().toUtf8().constData(); else + { BaseRefIdAdapter::setData (column, data, index, value); + return; + } + + record.setModified(record2); } struct NameColumns : public ModelColumns @@ -216,12 +222,18 @@ namespace CSMWorld Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter::getType()))); + RecordT record2 = record.get(); if (column==mName.mName) - record.get().mName = value.toString().toUtf8().constData(); + record2.mName = value.toString().toUtf8().constData(); else if (column==mName.mScript) - record.get().mScript = value.toString().toUtf8().constData(); + record2.mScript = value.toString().toUtf8().constData(); else + { ModelRefIdAdapter::setData (column, data, index, value); + return; + } + + record.setModified(record2); } struct InventoryColumns : public NameColumns @@ -283,14 +295,20 @@ namespace CSMWorld Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter::getType()))); + RecordT record2 = record.get(); if (column==mInventory.mIcon) - record.get().mIcon = value.toString().toUtf8().constData(); + record2.mIcon = value.toString().toUtf8().constData(); else if (column==mInventory.mWeight) - record.get().mData.mWeight = value.toFloat(); + record2.mData.mWeight = value.toFloat(); else if (column==mInventory.mValue) - record.get().mData.mValue = value.toInt(); + record2.mData.mValue = value.toInt(); else + { NameRefIdAdapter::setData (column, data, index, value); + return; + } + + record.setModified(record2); } class PotionRefIdAdapter : public InventoryRefIdAdapter @@ -364,12 +382,18 @@ namespace CSMWorld Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter::getType()))); + RecordT record2 = record.get(); if (column==mEnchantable.mEnchantment) - record.get().mEnchant = value.toString().toUtf8().constData(); + record2.mEnchant = value.toString().toUtf8().constData(); else if (column==mEnchantable.mEnchantmentPoints) - record.get().mData.mEnchant = value.toInt(); + record2.mData.mEnchant = value.toInt(); else + { InventoryRefIdAdapter::setData (column, data, index, value); + return; + } + + record.setModified(record2); } struct ToolColumns : public InventoryColumns @@ -426,12 +450,18 @@ namespace CSMWorld Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter::getType()))); + RecordT record2 = record.get(); if (column==mTools.mQuality) - record.get().mData.mQuality = value.toFloat(); + record2.mData.mQuality = value.toFloat(); else if (column==mTools.mUses) - record.get().mData.mUses = value.toInt(); + record2.mData.mUses = value.toInt(); else + { InventoryRefIdAdapter::setData (column, data, index, value); + return; + } + + record.setModified(record2); } struct ActorColumns : public NameColumns @@ -508,16 +538,17 @@ namespace CSMWorld Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter::getType()))); + RecordT record2 = record.get(); if (column==mActors.mHasAi) - record.get().mHasAI = value.toInt(); + record2.mHasAI = value.toInt(); else if (column==mActors.mHello) - record.get().mAiData.mHello = value.toInt(); + record2.mAiData.mHello = value.toInt(); else if (column==mActors.mFlee) - record.get().mAiData.mFlee = value.toInt(); + record2.mAiData.mFlee = value.toInt(); else if (column==mActors.mFight) - record.get().mAiData.mFight = value.toInt(); + record2.mAiData.mFight = value.toInt(); else if (column==mActors.mAlarm) - record.get().mAiData.mAlarm = value.toInt(); + record2.mAiData.mAlarm = value.toInt(); else { typename std::map::const_iterator iter = @@ -525,13 +556,18 @@ namespace CSMWorld if (iter!=mActors.mServices.end()) { if (value.toInt()!=0) - record.get().mAiData.mServices |= iter->second; + record2.mAiData.mServices |= iter->second; else - record.get().mAiData.mServices &= ~iter->second; + record2.mAiData.mServices &= ~iter->second; } else + { NameRefIdAdapter::setData (column, data, index, value); + return; + } } + + record.setModified(record2); } class ApparatusRefIdAdapter : public InventoryRefIdAdapter From d7baf923536a01f1f77713c4869480cfb8403ac6 Mon Sep 17 00:00:00 2001 From: Scott Howard Date: Mon, 9 Mar 2015 16:49:40 -0400 Subject: [PATCH 595/740] tell include_directories which libraries are system libs --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 30710f532..b5377ee00 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -229,7 +229,8 @@ endif () endif(WIN32) endif(OGRE_STATIC) -include_directories("." +include_directories("." ${LIBS_DIR} + SYSTEM ${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE ${OGRE_INCLUDE_DIRS} ${OGRE_PLUGIN_INCLUDE_DIRS} ${OGRE_INCLUDE_DIR}/Overlay ${OGRE_Overlay_INCLUDE_DIR} ${SDL2_INCLUDE_DIR} @@ -239,7 +240,6 @@ include_directories("." ${MYGUI_PLATFORM_INCLUDE_DIRS} ${OPENAL_INCLUDE_DIR} ${BULLET_INCLUDE_DIRS} - ${LIBS_DIR} ) link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR} ${MYGUI_LIB_DIR}) From 43ec933b7ba44186de8b2fd0ffa4f4d89a7cfcec Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 10 Mar 2015 09:45:35 +1100 Subject: [PATCH 596/740] Revert to the original clone() method. Create a new copy method for modified records. --- apps/opencs/model/world/record.hpp | 25 +++++++++------------ apps/opencs/model/world/refidcollection.cpp | 2 +- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp index 814e116dd..a0ddd8bc8 100644 --- a/apps/opencs/model/world/record.hpp +++ b/apps/opencs/model/world/record.hpp @@ -22,6 +22,8 @@ namespace CSMWorld virtual RecordBase *clone() const = 0; + virtual RecordBase *modifiedCopy() const = 0; + virtual void assign (const RecordBase& record) = 0; ///< Will throw an exception if the types don't match. @@ -38,13 +40,10 @@ namespace CSMWorld ESXRecordT mBase; ESXRecordT mModified; - Record() = default; - Record(const Record&) = default; - Record(State state, - const ESXRecordT *base = 0, const ESXRecordT *modified = 0); - virtual RecordBase *clone() const; + virtual RecordBase *modifiedCopy() const; + virtual void assign (const RecordBase& record); const ESXRecordT& get() const; @@ -64,21 +63,19 @@ namespace CSMWorld }; template - Record::Record(State state, const ESXRecordT *base, const ESXRecordT *modified) + RecordBase *Record::modifiedCopy() const { - if(base) - mBase = *base; - - if(modified) - mModified = *modified; - - this->mState = state; + Record *record = new Record (*this); + record->mModified = record->mBase; + record->mBase = ESXRecordT(); + record->mState = RecordBase::State_ModifiedOnly; + return record; } template RecordBase *Record::clone() const { - return new Record (State_ModifiedOnly, 0, &(this->get())); + return new Record (*this); } template diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 011b5cc0e..14a8890ad 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -470,7 +470,7 @@ void CSMWorld::RefIdCollection::cloneRecord(const std::string& origin, const std::string& destination, const CSMWorld::UniversalId::Type type) { - std::auto_ptr newRecord(mData.getRecord(mData.searchId(origin)).clone()); + std::auto_ptr newRecord(mData.getRecord(mData.searchId(origin)).modifiedCopy()); mAdapters.find(type)->second->setId(*newRecord, destination); mData.insertRecord(*newRecord, type, destination); } From 28259f914c06100ea58ed31680d7b5deb80ead5f Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 11 Mar 2015 10:49:21 +1100 Subject: [PATCH 597/740] Remove potential memory leak. --- apps/opencs/model/world/record.hpp | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp index a0ddd8bc8..1cf14a8f9 100644 --- a/apps/opencs/model/world/record.hpp +++ b/apps/opencs/model/world/record.hpp @@ -40,6 +40,13 @@ namespace CSMWorld ESXRecordT mBase; ESXRecordT mModified; + Record() = default; + Record(const Record&) = default; + Record& operator= (const Record&) = default; + + Record(State state, + const ESXRecordT *base = 0, const ESXRecordT *modified = 0); + virtual RecordBase *clone() const; virtual RecordBase *modifiedCopy() const; @@ -62,14 +69,22 @@ namespace CSMWorld ///< Merge modified into base. }; + template + Record::Record(State state, const ESXRecordT *base, const ESXRecordT *modified) + { + if(base) + mBase = *base; + + if(modified) + mModified = *modified; + + this->mState = state; + } + template RecordBase *Record::modifiedCopy() const { - Record *record = new Record (*this); - record->mModified = record->mBase; - record->mBase = ESXRecordT(); - record->mState = RecordBase::State_ModifiedOnly; - return record; + return new Record (State_ModifiedOnly, 0, &(this->get())); } template From e2ef8c402233d84f670c82d6cc6e848075c07a03 Mon Sep 17 00:00:00 2001 From: Scott Howard Date: Wed, 11 Mar 2015 10:54:45 -0400 Subject: [PATCH 598/740] fix -Wnewline-eof warnings --- apps/mwiniimporter/importer.cpp | 2 +- apps/opencs/model/doc/blacklist.cpp | 2 +- apps/opencs/model/doc/documentmanager.cpp | 2 +- apps/opencs/model/doc/documentmanager.hpp | 2 +- apps/opencs/model/doc/messages.cpp | 2 +- apps/opencs/model/doc/operation.hpp | 2 +- apps/opencs/model/doc/saving.cpp | 2 +- apps/opencs/model/doc/stage.cpp | 2 +- apps/opencs/model/filter/booleannode.cpp | 2 +- apps/opencs/model/filter/booleannode.hpp | 2 +- apps/opencs/model/filter/node.cpp | 2 +- apps/opencs/model/filter/notnode.cpp | 2 +- apps/opencs/model/filter/textnode.cpp | 2 +- apps/opencs/model/filter/unarynode.cpp | 2 +- apps/opencs/model/filter/valuenode.cpp | 2 +- apps/opencs/model/tools/birthsigncheck.cpp | 2 +- apps/opencs/model/tools/bodypartcheck.hpp | 2 +- apps/opencs/model/tools/classcheck.cpp | 2 +- apps/opencs/model/tools/mandatoryid.cpp | 2 +- apps/opencs/model/tools/racecheck.cpp | 2 +- apps/opencs/model/tools/referencecheck.hpp | 2 +- apps/opencs/model/tools/regioncheck.cpp | 2 +- apps/opencs/model/tools/reportmodel.cpp | 2 +- apps/opencs/model/tools/scriptcheck.cpp | 2 +- apps/opencs/model/tools/skillcheck.cpp | 2 +- apps/opencs/model/tools/soundcheck.cpp | 2 +- apps/opencs/model/tools/spellcheck.cpp | 2 +- apps/opencs/model/world/cell.hpp | 2 +- apps/opencs/model/world/collectionbase.cpp | 2 +- apps/opencs/model/world/collectionbase.hpp | 2 +- apps/opencs/model/world/columnbase.cpp | 2 +- apps/opencs/model/world/commanddispatcher.cpp | 2 +- apps/opencs/model/world/commands.cpp | 2 +- apps/opencs/model/world/commands.hpp | 2 +- apps/opencs/model/world/idtablebase.cpp | 2 +- apps/opencs/model/world/infocollection.hpp | 2 +- apps/opencs/model/world/pathgrid.hpp | 2 +- apps/opencs/model/world/record.cpp | 2 +- apps/opencs/model/world/ref.cpp | 2 +- apps/opencs/model/world/refidadapter.cpp | 2 +- apps/opencs/model/world/refidadapter.hpp | 2 +- apps/opencs/model/world/regionmap.cpp | 2 +- apps/opencs/model/world/resources.cpp | 2 +- apps/opencs/model/world/resourcesmanager.cpp | 2 +- apps/opencs/model/world/resourcesmanager.hpp | 2 +- apps/opencs/model/world/resourcetable.cpp | 2 +- apps/opencs/model/world/scope.cpp | 2 +- apps/opencs/model/world/scriptcontext.cpp | 2 +- apps/opencs/view/doc/globaldebugprofilemenu.cpp | 2 +- apps/opencs/view/doc/runlogsubview.cpp | 2 +- apps/opencs/view/doc/subviewfactory.cpp | 2 +- apps/opencs/view/doc/subviewfactoryimp.hpp | 2 +- apps/opencs/view/filter/editwidget.cpp | 2 +- apps/opencs/view/filter/recordfilterbox.hpp | 2 +- apps/opencs/view/render/editmode.cpp | 2 +- apps/opencs/view/render/lighting.cpp | 2 +- apps/opencs/view/render/lightingbright.cpp | 2 +- apps/opencs/view/render/lightingday.cpp | 2 +- apps/opencs/view/render/lightingnight.cpp | 2 +- apps/opencs/view/render/navigationorbit.cpp | 2 +- apps/opencs/view/tools/reporttable.cpp | 2 +- apps/opencs/view/tools/subviews.cpp | 2 +- apps/opencs/view/widget/pushbutton.cpp | 2 +- apps/opencs/view/widget/scenetoolmode.cpp | 2 +- apps/opencs/view/widget/scenetoolrun.cpp | 2 +- apps/opencs/view/world/creator.cpp | 2 +- apps/opencs/view/world/creator.hpp | 2 +- apps/opencs/view/world/dialoguecreator.cpp | 2 +- apps/opencs/view/world/dialoguesubview.hpp | 2 +- apps/opencs/view/world/genericcreator.cpp | 2 +- apps/opencs/view/world/genericcreator.hpp | 2 +- apps/opencs/view/world/idvalidator.cpp | 2 +- apps/opencs/view/world/infocreator.cpp | 2 +- apps/opencs/view/world/previewsubview.cpp | 2 +- apps/opencs/view/world/regionmapsubview.cpp | 2 +- apps/opencs/view/world/scriptedit.cpp | 2 +- apps/opencs/view/world/scriptedit.hpp | 2 +- apps/opencs/view/world/scripthighlighter.cpp | 2 +- apps/opencs/view/world/scriptsubview.hpp | 2 +- apps/opencs/view/world/subviews.cpp | 2 +- apps/openmw/mwmechanics/stat.cpp | 2 +- apps/openmw/mwscript/transformationextensions.hpp | 2 +- apps/openmw/mwworld/failedaction.hpp | 2 +- apps/openmw/mwworld/manualref.cpp | 2 +- components/bsa/resources.cpp | 2 +- components/compiler/extensions0.hpp | 2 +- components/compiler/nullerrorhandler.cpp | 2 +- components/compiler/opcodes.cpp | 2 +- components/compiler/quickfileparser.cpp | 2 +- components/esm/cellid.hpp | 2 +- components/esm/containerstate.cpp | 2 +- components/esm/globalscript.cpp | 2 +- components/esm/queststate.cpp | 2 +- extern/oics/ICSChannelListener.h | 2 +- extern/oics/ICSControlListener.h | 2 +- 95 files changed, 95 insertions(+), 95 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index efebe5a4d..479f8cba2 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -903,4 +903,4 @@ std::time_t MwIniImporter::lastWriteTime(const boost::filesystem::path& filename std::cout << "content file: " << filename << " not found" << std::endl; } return writeTime; -} \ No newline at end of file +} diff --git a/apps/opencs/model/doc/blacklist.cpp b/apps/opencs/model/doc/blacklist.cpp index 9b37a4302..083726412 100644 --- a/apps/opencs/model/doc/blacklist.cpp +++ b/apps/opencs/model/doc/blacklist.cpp @@ -28,4 +28,4 @@ void CSMDoc::Blacklist::add (CSMWorld::UniversalId::Type type, std::transform (ids.begin(), ids.end(), list.begin()+size, Misc::StringUtils::lowerCase); std::sort (list.begin(), list.end()); -} \ No newline at end of file +} diff --git a/apps/opencs/model/doc/documentmanager.cpp b/apps/opencs/model/doc/documentmanager.cpp index 9b807225c..7a1a86153 100644 --- a/apps/opencs/model/doc/documentmanager.cpp +++ b/apps/opencs/model/doc/documentmanager.cpp @@ -107,4 +107,4 @@ void CSMDoc::DocumentManager::documentNotLoaded (Document *document, const std:: if (error.empty()) // do not remove the document yet, if we have an error removeDocument (document); -} \ No newline at end of file +} diff --git a/apps/opencs/model/doc/documentmanager.hpp b/apps/opencs/model/doc/documentmanager.hpp index c545b9a9f..3202c4fe1 100644 --- a/apps/opencs/model/doc/documentmanager.hpp +++ b/apps/opencs/model/doc/documentmanager.hpp @@ -99,4 +99,4 @@ namespace CSMDoc }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/doc/messages.cpp b/apps/opencs/model/doc/messages.cpp index 1fb423145..9b295fb28 100644 --- a/apps/opencs/model/doc/messages.cpp +++ b/apps/opencs/model/doc/messages.cpp @@ -25,4 +25,4 @@ CSMDoc::Messages::Iterator CSMDoc::Messages::begin() const CSMDoc::Messages::Iterator CSMDoc::Messages::end() const { return mMessages.end(); -} \ No newline at end of file +} diff --git a/apps/opencs/model/doc/operation.hpp b/apps/opencs/model/doc/operation.hpp index 3c9467754..a4ee88a07 100644 --- a/apps/opencs/model/doc/operation.hpp +++ b/apps/opencs/model/doc/operation.hpp @@ -68,4 +68,4 @@ namespace CSMDoc }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/doc/saving.cpp b/apps/opencs/model/doc/saving.cpp index b52186a47..04d61ed1b 100644 --- a/apps/opencs/model/doc/saving.cpp +++ b/apps/opencs/model/doc/saving.cpp @@ -97,4 +97,4 @@ CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& proje appendStage (new CloseSaveStage (mState)); appendStage (new FinalSavingStage (mDocument, mState)); -} \ No newline at end of file +} diff --git a/apps/opencs/model/doc/stage.cpp b/apps/opencs/model/doc/stage.cpp index 99b765770..1a2c5c721 100644 --- a/apps/opencs/model/doc/stage.cpp +++ b/apps/opencs/model/doc/stage.cpp @@ -1,4 +1,4 @@ #include "stage.hpp" -CSMDoc::Stage::~Stage() {} \ No newline at end of file +CSMDoc::Stage::~Stage() {} diff --git a/apps/opencs/model/filter/booleannode.cpp b/apps/opencs/model/filter/booleannode.cpp index 2daa1b6d8..35fc98e08 100644 --- a/apps/opencs/model/filter/booleannode.cpp +++ b/apps/opencs/model/filter/booleannode.cpp @@ -12,4 +12,4 @@ bool CSMFilter::BooleanNode::test (const CSMWorld::IdTableBase& table, int row, std::string CSMFilter::BooleanNode::toString (bool numericColumns) const { return mTrue ? "true" : "false"; -} \ No newline at end of file +} diff --git a/apps/opencs/model/filter/booleannode.hpp b/apps/opencs/model/filter/booleannode.hpp index d9635746c..32206b575 100644 --- a/apps/opencs/model/filter/booleannode.hpp +++ b/apps/opencs/model/filter/booleannode.hpp @@ -26,4 +26,4 @@ namespace CSMFilter }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/filter/node.cpp b/apps/opencs/model/filter/node.cpp index 276861cdc..091dc4698 100644 --- a/apps/opencs/model/filter/node.cpp +++ b/apps/opencs/model/filter/node.cpp @@ -3,4 +3,4 @@ CSMFilter::Node::Node() {} -CSMFilter::Node::~Node() {} \ No newline at end of file +CSMFilter::Node::~Node() {} diff --git a/apps/opencs/model/filter/notnode.cpp b/apps/opencs/model/filter/notnode.cpp index 231773075..b5d9da7b7 100644 --- a/apps/opencs/model/filter/notnode.cpp +++ b/apps/opencs/model/filter/notnode.cpp @@ -7,4 +7,4 @@ bool CSMFilter::NotNode::test (const CSMWorld::IdTableBase& table, int row, const std::map& columns) const { return !getChild().test (table, row, columns); -} \ No newline at end of file +} diff --git a/apps/opencs/model/filter/textnode.cpp b/apps/opencs/model/filter/textnode.cpp index 24cdce4f5..73c378f11 100644 --- a/apps/opencs/model/filter/textnode.cpp +++ b/apps/opencs/model/filter/textnode.cpp @@ -82,4 +82,4 @@ std::string CSMFilter::TextNode::toString (bool numericColumns) const stream << ", \"" << mText << "\")"; return stream.str(); -} \ No newline at end of file +} diff --git a/apps/opencs/model/filter/unarynode.cpp b/apps/opencs/model/filter/unarynode.cpp index 43a24b76a..c40d191b6 100644 --- a/apps/opencs/model/filter/unarynode.cpp +++ b/apps/opencs/model/filter/unarynode.cpp @@ -23,4 +23,4 @@ std::vector CSMFilter::UnaryNode::getReferencedColumns() const std::string CSMFilter::UnaryNode::toString (bool numericColumns) const { return mName + " " + mChild->toString (numericColumns); -} \ No newline at end of file +} diff --git a/apps/opencs/model/filter/valuenode.cpp b/apps/opencs/model/filter/valuenode.cpp index 26b982441..72cf5896b 100644 --- a/apps/opencs/model/filter/valuenode.cpp +++ b/apps/opencs/model/filter/valuenode.cpp @@ -94,4 +94,4 @@ std::string CSMFilter::ValueNode::toString (bool numericColumns) const stream << ")"; return stream.str(); -} \ No newline at end of file +} diff --git a/apps/opencs/model/tools/birthsigncheck.cpp b/apps/opencs/model/tools/birthsigncheck.cpp index 1d72e24b8..4e6da4631 100644 --- a/apps/opencs/model/tools/birthsigncheck.cpp +++ b/apps/opencs/model/tools/birthsigncheck.cpp @@ -41,4 +41,4 @@ void CSMTools::BirthsignCheckStage::perform (int stage, CSMDoc::Messages& messag /// \todo test if the texture exists /// \todo check data members that can't be edited in the table view -} \ No newline at end of file +} diff --git a/apps/opencs/model/tools/bodypartcheck.hpp b/apps/opencs/model/tools/bodypartcheck.hpp index 0a6ca959a..dbab5f5c6 100644 --- a/apps/opencs/model/tools/bodypartcheck.hpp +++ b/apps/opencs/model/tools/bodypartcheck.hpp @@ -32,4 +32,4 @@ namespace CSMTools }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/tools/classcheck.cpp b/apps/opencs/model/tools/classcheck.cpp index 5b872a266..be57a3729 100644 --- a/apps/opencs/model/tools/classcheck.cpp +++ b/apps/opencs/model/tools/classcheck.cpp @@ -65,4 +65,4 @@ void CSMTools::ClassCheckStage::perform (int stage, CSMDoc::Messages& messages) messages.push_back (std::make_pair (id, ESM::Skill::indexToId (iter->first) + " is listed more than once")); } -} \ No newline at end of file +} diff --git a/apps/opencs/model/tools/mandatoryid.cpp b/apps/opencs/model/tools/mandatoryid.cpp index 87d19401b..4c97d2266 100644 --- a/apps/opencs/model/tools/mandatoryid.cpp +++ b/apps/opencs/model/tools/mandatoryid.cpp @@ -20,4 +20,4 @@ void CSMTools::MandatoryIdStage::perform (int stage, CSMDoc::Messages& messages) if (mIdCollection.searchId (mIds.at (stage))==-1 || mIdCollection.getRecord (mIds.at (stage)).isDeleted()) messages.add (mCollectionId, "Missing mandatory record: " + mIds.at (stage)); -} \ No newline at end of file +} diff --git a/apps/opencs/model/tools/racecheck.cpp b/apps/opencs/model/tools/racecheck.cpp index 143d61772..3b2c8d290 100644 --- a/apps/opencs/model/tools/racecheck.cpp +++ b/apps/opencs/model/tools/racecheck.cpp @@ -70,4 +70,4 @@ void CSMTools::RaceCheckStage::perform (int stage, CSMDoc::Messages& messages) performFinal (messages); else performPerRecord (stage, messages); -} \ No newline at end of file +} diff --git a/apps/opencs/model/tools/referencecheck.hpp b/apps/opencs/model/tools/referencecheck.hpp index 9cf685b3a..70ef02916 100644 --- a/apps/opencs/model/tools/referencecheck.hpp +++ b/apps/opencs/model/tools/referencecheck.hpp @@ -26,4 +26,4 @@ namespace CSMTools }; } -#endif // CSM_TOOLS_REFERENCECHECK_H \ No newline at end of file +#endif // CSM_TOOLS_REFERENCECHECK_H diff --git a/apps/opencs/model/tools/regioncheck.cpp b/apps/opencs/model/tools/regioncheck.cpp index 091836d0d..42abc35c9 100644 --- a/apps/opencs/model/tools/regioncheck.cpp +++ b/apps/opencs/model/tools/regioncheck.cpp @@ -35,4 +35,4 @@ void CSMTools::RegionCheckStage::perform (int stage, CSMDoc::Messages& messages) /// \todo test that the ID in mSleeplist exists /// \todo check data members that can't be edited in the table view -} \ No newline at end of file +} diff --git a/apps/opencs/model/tools/reportmodel.cpp b/apps/opencs/model/tools/reportmodel.cpp index 135420612..ac9dabb25 100644 --- a/apps/opencs/model/tools/reportmodel.cpp +++ b/apps/opencs/model/tools/reportmodel.cpp @@ -78,4 +78,4 @@ const CSMWorld::UniversalId& CSMTools::ReportModel::getUniversalId (int row) con std::string CSMTools::ReportModel::getHint (int row) const { return mRows.at (row).second.second; -} \ No newline at end of file +} diff --git a/apps/opencs/model/tools/scriptcheck.cpp b/apps/opencs/model/tools/scriptcheck.cpp index d9dea7f43..a70ee2ae4 100644 --- a/apps/opencs/model/tools/scriptcheck.cpp +++ b/apps/opencs/model/tools/scriptcheck.cpp @@ -98,4 +98,4 @@ void CSMTools::ScriptCheckStage::perform (int stage, CSMDoc::Messages& messages) } mMessages = 0; -} \ No newline at end of file +} diff --git a/apps/opencs/model/tools/skillcheck.cpp b/apps/opencs/model/tools/skillcheck.cpp index e061e042c..2b55526e0 100644 --- a/apps/opencs/model/tools/skillcheck.cpp +++ b/apps/opencs/model/tools/skillcheck.cpp @@ -39,4 +39,4 @@ void CSMTools::SkillCheckStage::perform (int stage, CSMDoc::Messages& messages) if (skill.mDescription.empty()) messages.push_back (std::make_pair (id, skill.mId + " has an empty description")); -} \ No newline at end of file +} diff --git a/apps/opencs/model/tools/soundcheck.cpp b/apps/opencs/model/tools/soundcheck.cpp index e122ced91..f78932a32 100644 --- a/apps/opencs/model/tools/soundcheck.cpp +++ b/apps/opencs/model/tools/soundcheck.cpp @@ -31,4 +31,4 @@ void CSMTools::SoundCheckStage::perform (int stage, CSMDoc::Messages& messages) messages.push_back (std::make_pair (id, "Maximum range larger than minimum range")); /// \todo check, if the sound file exists -} \ No newline at end of file +} diff --git a/apps/opencs/model/tools/spellcheck.cpp b/apps/opencs/model/tools/spellcheck.cpp index 0b59dc862..bd076d2a5 100644 --- a/apps/opencs/model/tools/spellcheck.cpp +++ b/apps/opencs/model/tools/spellcheck.cpp @@ -37,4 +37,4 @@ void CSMTools::SpellCheckStage::perform (int stage, CSMDoc::Messages& messages) messages.push_back (std::make_pair (id, spell.mId + " has a negative spell costs")); /// \todo check data members that can't be edited in the table view -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/cell.hpp b/apps/opencs/model/world/cell.hpp index a47dbf45d..f393e2cf9 100644 --- a/apps/opencs/model/world/cell.hpp +++ b/apps/opencs/model/world/cell.hpp @@ -21,4 +21,4 @@ namespace CSMWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/world/collectionbase.cpp b/apps/opencs/model/world/collectionbase.cpp index 241f198cb..b8eed4192 100644 --- a/apps/opencs/model/world/collectionbase.cpp +++ b/apps/opencs/model/world/collectionbase.cpp @@ -28,4 +28,4 @@ int CSMWorld::CollectionBase::findColumnIndex (Columns::ColumnId id) const throw std::logic_error ("invalid column index"); return index; -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/collectionbase.hpp b/apps/opencs/model/world/collectionbase.hpp index 442055d5f..ef826e31c 100644 --- a/apps/opencs/model/world/collectionbase.hpp +++ b/apps/opencs/model/world/collectionbase.hpp @@ -106,4 +106,4 @@ namespace CSMWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index f6363fe2e..665ab9354 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -22,4 +22,4 @@ std::string CSMWorld::ColumnBase::getTitle() const int CSMWorld::ColumnBase::getId() const { return mColumnId; -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/commanddispatcher.cpp b/apps/opencs/model/world/commanddispatcher.cpp index 4e146d87c..ca6faafbc 100644 --- a/apps/opencs/model/world/commanddispatcher.cpp +++ b/apps/opencs/model/world/commanddispatcher.cpp @@ -264,4 +264,4 @@ void CSMWorld::CommandDispatcher::executeExtendedRevert() if (mExtendedTypes.size()>1) mDocument.getUndoStack().endMacro(); -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index de0e9a4e5..1d86ba080 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -170,4 +170,4 @@ void CSMWorld::CloneCommand::redo() void CSMWorld::CloneCommand::undo() { mModel.removeRow (mModel.getModelIndex (mId, 0).row()); -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index a15c071a8..7267c9c8b 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -141,4 +141,4 @@ namespace CSMWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/world/idtablebase.cpp b/apps/opencs/model/world/idtablebase.cpp index 31d8d461e..389f5396e 100644 --- a/apps/opencs/model/world/idtablebase.cpp +++ b/apps/opencs/model/world/idtablebase.cpp @@ -6,4 +6,4 @@ CSMWorld::IdTableBase::IdTableBase (unsigned int features) : mFeatures (features unsigned int CSMWorld::IdTableBase::getFeatures() const { return mFeatures; -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/infocollection.hpp b/apps/opencs/model/world/infocollection.hpp index ae61f5d39..e953effa8 100644 --- a/apps/opencs/model/world/infocollection.hpp +++ b/apps/opencs/model/world/infocollection.hpp @@ -47,4 +47,4 @@ namespace CSMWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/world/pathgrid.hpp b/apps/opencs/model/world/pathgrid.hpp index d8cc89f24..7e7b7c3bb 100644 --- a/apps/opencs/model/world/pathgrid.hpp +++ b/apps/opencs/model/world/pathgrid.hpp @@ -26,4 +26,4 @@ namespace CSMWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/world/record.cpp b/apps/opencs/model/world/record.cpp index 14f63c155..ef2f4d320 100644 --- a/apps/opencs/model/world/record.cpp +++ b/apps/opencs/model/world/record.cpp @@ -18,4 +18,4 @@ bool CSMWorld::RecordBase::isErased() const bool CSMWorld::RecordBase::isModified() const { return mState==State_Modified || mState==State_ModifiedOnly; -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/ref.cpp b/apps/opencs/model/world/ref.cpp index f3c1b0b73..eee454a16 100644 --- a/apps/opencs/model/world/ref.cpp +++ b/apps/opencs/model/world/ref.cpp @@ -5,4 +5,4 @@ CSMWorld::CellRef::CellRef() { mRefNum.mIndex = 0; mRefNum.mContentFile = 0; -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/refidadapter.cpp b/apps/opencs/model/world/refidadapter.cpp index 94ae38c3c..8f74e6134 100644 --- a/apps/opencs/model/world/refidadapter.cpp +++ b/apps/opencs/model/world/refidadapter.cpp @@ -3,4 +3,4 @@ CSMWorld::RefIdAdapter::RefIdAdapter() {} -CSMWorld::RefIdAdapter::~RefIdAdapter() {} \ No newline at end of file +CSMWorld::RefIdAdapter::~RefIdAdapter() {} diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index 0870a2d3e..3320af190 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -35,4 +35,4 @@ namespace CSMWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/world/regionmap.cpp b/apps/opencs/model/world/regionmap.cpp index 5f030bb52..f63426c04 100644 --- a/apps/opencs/model/world/regionmap.cpp +++ b/apps/opencs/model/world/regionmap.cpp @@ -503,4 +503,4 @@ void CSMWorld::RegionMap::cellsChanged (const QModelIndex& topLeft, const QModel // columns we are interested in. If not we can exit the function here and avoid all updating. addCells (topLeft.row(), bottomRight.row()); -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/resources.cpp b/apps/opencs/model/world/resources.cpp index 13c8df84d..8c9439890 100644 --- a/apps/opencs/model/world/resources.cpp +++ b/apps/opencs/model/world/resources.cpp @@ -105,4 +105,4 @@ int CSMWorld::Resources::searchId (const std::string& id) const CSMWorld::UniversalId::Type CSMWorld::Resources::getType() const { return mType; -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/resourcesmanager.cpp b/apps/opencs/model/world/resourcesmanager.cpp index 50014f4b5..deddd83b5 100644 --- a/apps/opencs/model/world/resourcesmanager.cpp +++ b/apps/opencs/model/world/resourcesmanager.cpp @@ -30,4 +30,4 @@ const CSMWorld::Resources& CSMWorld::ResourcesManager::get (UniversalId::Type ty throw std::logic_error ("Unknown resource type"); return iter->second; -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/resourcesmanager.hpp b/apps/opencs/model/world/resourcesmanager.hpp index 77f210c47..18861a6a5 100644 --- a/apps/opencs/model/world/resourcesmanager.hpp +++ b/apps/opencs/model/world/resourcesmanager.hpp @@ -25,4 +25,4 @@ namespace CSMWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/world/resourcetable.cpp b/apps/opencs/model/world/resourcetable.cpp index a7180434a..9257b9d2a 100644 --- a/apps/opencs/model/world/resourcetable.cpp +++ b/apps/opencs/model/world/resourcetable.cpp @@ -143,4 +143,4 @@ std::pair CSMWorld::ResourceTable::view (int bool CSMWorld::ResourceTable::isDeleted (const std::string& id) const { return false; -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/scope.cpp b/apps/opencs/model/world/scope.cpp index e3ebf5ebd..6e4ce4c02 100644 --- a/apps/opencs/model/world/scope.cpp +++ b/apps/opencs/model/world/scope.cpp @@ -22,4 +22,4 @@ CSMWorld::Scope CSMWorld::getScopeFromId (const std::string& id) return Scope_Session; return Scope_Content; -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/scriptcontext.cpp b/apps/opencs/model/world/scriptcontext.cpp index 0d2b9984e..a8c2c9452 100644 --- a/apps/opencs/model/world/scriptcontext.cpp +++ b/apps/opencs/model/world/scriptcontext.cpp @@ -120,4 +120,4 @@ void CSMWorld::ScriptContext::clear() mIds.clear(); mIdsUpdated = false; mLocals.clear(); -} \ No newline at end of file +} diff --git a/apps/opencs/view/doc/globaldebugprofilemenu.cpp b/apps/opencs/view/doc/globaldebugprofilemenu.cpp index 82bd96326..b88381385 100644 --- a/apps/opencs/view/doc/globaldebugprofilemenu.cpp +++ b/apps/opencs/view/doc/globaldebugprofilemenu.cpp @@ -90,4 +90,4 @@ void CSVDoc::GlobalDebugProfileMenu::profileChanged (const QModelIndex& topLeft, void CSVDoc::GlobalDebugProfileMenu::actionTriggered (QAction *action) { emit triggered (std::string (action->text().toUtf8().constData())); -} \ No newline at end of file +} diff --git a/apps/opencs/view/doc/runlogsubview.cpp b/apps/opencs/view/doc/runlogsubview.cpp index 68e888e8d..129396999 100644 --- a/apps/opencs/view/doc/runlogsubview.cpp +++ b/apps/opencs/view/doc/runlogsubview.cpp @@ -17,4 +17,4 @@ CSVDoc::RunLogSubView::RunLogSubView (const CSMWorld::UniversalId& id, void CSVDoc::RunLogSubView::setEditLock (bool locked) { // ignored since this SubView does not have editing -} \ No newline at end of file +} diff --git a/apps/opencs/view/doc/subviewfactory.cpp b/apps/opencs/view/doc/subviewfactory.cpp index 8576f6b1d..3137f7e32 100644 --- a/apps/opencs/view/doc/subviewfactory.cpp +++ b/apps/opencs/view/doc/subviewfactory.cpp @@ -35,4 +35,4 @@ CSVDoc::SubView *CSVDoc::SubViewFactoryManager::makeSubView (const CSMWorld::Uni throw std::runtime_error ("Failed to create a sub view for: " + id.toString()); return iter->second->makeSubView (id, document); -} \ No newline at end of file +} diff --git a/apps/opencs/view/doc/subviewfactoryimp.hpp b/apps/opencs/view/doc/subviewfactoryimp.hpp index 059b24fd0..670137985 100644 --- a/apps/opencs/view/doc/subviewfactoryimp.hpp +++ b/apps/opencs/view/doc/subviewfactoryimp.hpp @@ -48,4 +48,4 @@ namespace CSVDoc } } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/filter/editwidget.cpp b/apps/opencs/view/filter/editwidget.cpp index 68e99e0de..bc7f9b5a1 100644 --- a/apps/opencs/view/filter/editwidget.cpp +++ b/apps/opencs/view/filter/editwidget.cpp @@ -193,4 +193,4 @@ std::string CSVFilter::EditWidget::generateFilter (std::pair< std::string, std:: } return ss.str(); -} \ No newline at end of file +} diff --git a/apps/opencs/view/filter/recordfilterbox.hpp b/apps/opencs/view/filter/recordfilterbox.hpp index f4d17510b..29d12529a 100644 --- a/apps/opencs/view/filter/recordfilterbox.hpp +++ b/apps/opencs/view/filter/recordfilterbox.hpp @@ -43,4 +43,4 @@ namespace CSVFilter } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp index 51a137d3b..9361030a3 100644 --- a/apps/opencs/view/render/editmode.cpp +++ b/apps/opencs/view/render/editmode.cpp @@ -16,4 +16,4 @@ unsigned int CSVRender::EditMode::getInteractionMask() const void CSVRender::EditMode::activate (CSVWidget::SceneToolbar *toolbar) { mWorldspaceWidget->setInteractionMask (mMask); -} \ No newline at end of file +} diff --git a/apps/opencs/view/render/lighting.cpp b/apps/opencs/view/render/lighting.cpp index d57570d69..3553ef58c 100644 --- a/apps/opencs/view/render/lighting.cpp +++ b/apps/opencs/view/render/lighting.cpp @@ -1,4 +1,4 @@ #include "lighting.hpp" -CSVRender::Lighting::~Lighting() {} \ No newline at end of file +CSVRender::Lighting::~Lighting() {} diff --git a/apps/opencs/view/render/lightingbright.cpp b/apps/opencs/view/render/lightingbright.cpp index ab845b924..a342ab093 100644 --- a/apps/opencs/view/render/lightingbright.cpp +++ b/apps/opencs/view/render/lightingbright.cpp @@ -27,4 +27,4 @@ void CSVRender::LightingBright::deactivate() } } -void CSVRender::LightingBright::setDefaultAmbient (const Ogre::ColourValue& colour) {} \ No newline at end of file +void CSVRender::LightingBright::setDefaultAmbient (const Ogre::ColourValue& colour) {} diff --git a/apps/opencs/view/render/lightingday.cpp b/apps/opencs/view/render/lightingday.cpp index ab0257c0c..c5189ccfd 100644 --- a/apps/opencs/view/render/lightingday.cpp +++ b/apps/opencs/view/render/lightingday.cpp @@ -33,4 +33,4 @@ void CSVRender::LightingDay::deactivate() void CSVRender::LightingDay::setDefaultAmbient (const Ogre::ColourValue& colour) { mSceneManager->setAmbientLight (colour); -} \ No newline at end of file +} diff --git a/apps/opencs/view/render/lightingnight.cpp b/apps/opencs/view/render/lightingnight.cpp index 516bb3f40..7d94dc964 100644 --- a/apps/opencs/view/render/lightingnight.cpp +++ b/apps/opencs/view/render/lightingnight.cpp @@ -33,4 +33,4 @@ void CSVRender::LightingNight::deactivate() void CSVRender::LightingNight::setDefaultAmbient (const Ogre::ColourValue& colour) { mSceneManager->setAmbientLight (colour); -} \ No newline at end of file +} diff --git a/apps/opencs/view/render/navigationorbit.cpp b/apps/opencs/view/render/navigationorbit.cpp index c6e729e96..c5f3eda96 100644 --- a/apps/opencs/view/render/navigationorbit.cpp +++ b/apps/opencs/view/render/navigationorbit.cpp @@ -97,4 +97,4 @@ bool CSVRender::NavigationOrbit::handleRollKeys (int delta) { mCamera->roll (Ogre::Degree (getFactor (false) * delta)); return true; -} \ No newline at end of file +} diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index 4cd11925e..da15b4acc 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -133,4 +133,4 @@ void CSVTools::ReportTable::removeSelection() mModel->removeRows (iter->row(), 1); selectionModel()->clear(); -} \ No newline at end of file +} diff --git a/apps/opencs/view/tools/subviews.cpp b/apps/opencs/view/tools/subviews.cpp index 8b04aca50..a50b5724a 100644 --- a/apps/opencs/view/tools/subviews.cpp +++ b/apps/opencs/view/tools/subviews.cpp @@ -11,4 +11,4 @@ void CSVTools::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) new CSVDoc::SubViewFactory); manager.add (CSMWorld::UniversalId::Type_LoadErrorLog, new CSVDoc::SubViewFactory); -} \ No newline at end of file +} diff --git a/apps/opencs/view/widget/pushbutton.cpp b/apps/opencs/view/widget/pushbutton.cpp index d4e600794..1baeb7ca2 100644 --- a/apps/opencs/view/widget/pushbutton.cpp +++ b/apps/opencs/view/widget/pushbutton.cpp @@ -106,4 +106,4 @@ CSVWidget::PushButton::Type CSVWidget::PushButton::getType() const void CSVWidget::PushButton::checkedStateChanged (bool checked) { setExtendedToolTip(); -} \ No newline at end of file +} diff --git a/apps/opencs/view/widget/scenetoolmode.cpp b/apps/opencs/view/widget/scenetoolmode.cpp index 8d871cc5f..39e051c48 100644 --- a/apps/opencs/view/widget/scenetoolmode.cpp +++ b/apps/opencs/view/widget/scenetoolmode.cpp @@ -100,4 +100,4 @@ void CSVWidget::SceneToolMode::selected() emit modeChanged (iter->second); } -} \ No newline at end of file +} diff --git a/apps/opencs/view/widget/scenetoolrun.cpp b/apps/opencs/view/widget/scenetoolrun.cpp index 0c7a4b9f0..8de334efe 100644 --- a/apps/opencs/view/widget/scenetoolrun.cpp +++ b/apps/opencs/view/widget/scenetoolrun.cpp @@ -148,4 +148,4 @@ void CSVWidget::SceneToolRun::clicked (const QModelIndex& index) removeProfile (*iter); updatePanel(); } -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/creator.cpp b/apps/opencs/view/world/creator.cpp index a24c58e54..2e7c7fe22 100644 --- a/apps/opencs/view/world/creator.cpp +++ b/apps/opencs/view/world/creator.cpp @@ -19,4 +19,4 @@ CSVWorld::Creator *CSVWorld::NullCreatorFactory::makeCreator (CSMWorld::Data& da QUndoStack& undoStack, const CSMWorld::UniversalId& id) const { return 0; -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/creator.hpp b/apps/opencs/view/world/creator.hpp index 8e50e8715..7c0422c88 100644 --- a/apps/opencs/view/world/creator.hpp +++ b/apps/opencs/view/world/creator.hpp @@ -101,4 +101,4 @@ namespace CSVWorld } } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/world/dialoguecreator.cpp b/apps/opencs/view/world/dialoguecreator.cpp index 3523d5e32..956cd26df 100644 --- a/apps/opencs/view/world/dialoguecreator.cpp +++ b/apps/opencs/view/world/dialoguecreator.cpp @@ -32,4 +32,4 @@ CSVWorld::Creator *CSVWorld::JournalCreatorFactory::makeCreator (CSMWorld::Data& QUndoStack& undoStack, const CSMWorld::UniversalId& id) const { return new DialogueCreator (data, undoStack, id, ESM::Dialogue::Journal); -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 4c260170f..5de2c3ad2 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -209,4 +209,4 @@ namespace CSVWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/world/genericcreator.cpp b/apps/opencs/view/world/genericcreator.cpp index afa59bc45..b4cf46040 100644 --- a/apps/opencs/view/world/genericcreator.cpp +++ b/apps/opencs/view/world/genericcreator.cpp @@ -276,4 +276,4 @@ void CSVWorld::GenericCreator::scopeChanged (int index) { update(); updateNamespace(); -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/genericcreator.hpp b/apps/opencs/view/world/genericcreator.hpp index 8c8c34bd8..678005082 100644 --- a/apps/opencs/view/world/genericcreator.hpp +++ b/apps/opencs/view/world/genericcreator.hpp @@ -111,4 +111,4 @@ namespace CSVWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/world/idvalidator.cpp b/apps/opencs/view/world/idvalidator.cpp index 7caa20f9b..13b05d2d1 100644 --- a/apps/opencs/view/world/idvalidator.cpp +++ b/apps/opencs/view/world/idvalidator.cpp @@ -120,4 +120,4 @@ void CSVWorld::IdValidator::setNamespace (const std::string& namespace_) std::string CSVWorld::IdValidator::getError() const { return mError; -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/infocreator.cpp b/apps/opencs/view/world/infocreator.cpp index 1d914716b..14034ea7f 100644 --- a/apps/opencs/view/world/infocreator.cpp +++ b/apps/opencs/view/world/infocreator.cpp @@ -94,4 +94,4 @@ std::string CSVWorld::InfoCreator::getErrors() const void CSVWorld::InfoCreator::topicChanged() { update(); -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/previewsubview.cpp b/apps/opencs/view/world/previewsubview.cpp index 1ae466f42..1c2d6b95c 100644 --- a/apps/opencs/view/world/previewsubview.cpp +++ b/apps/opencs/view/world/previewsubview.cpp @@ -67,4 +67,4 @@ void CSVWorld::PreviewSubView::referenceableIdChanged (const std::string& id) setWindowTitle (QString::fromUtf8 (mTitle.c_str())); emit updateTitle(); -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/regionmapsubview.cpp b/apps/opencs/view/world/regionmapsubview.cpp index a7675a4a6..411e24e75 100644 --- a/apps/opencs/view/world/regionmapsubview.cpp +++ b/apps/opencs/view/world/regionmapsubview.cpp @@ -24,4 +24,4 @@ void CSVWorld::RegionMapSubView::editRequest (const CSMWorld::UniversalId& id, const std::string& hint) { focusId (id, hint); -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/scriptedit.cpp b/apps/opencs/view/world/scriptedit.cpp index c2d94ab5d..271b0316d 100644 --- a/apps/opencs/view/world/scriptedit.cpp +++ b/apps/opencs/view/world/scriptedit.cpp @@ -156,4 +156,4 @@ void CSVWorld::ScriptEdit::updateHighlighting() ChangeLock lock (*this); mHighlighter->rehighlight(); -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/scriptedit.hpp b/apps/opencs/view/world/scriptedit.hpp index c67385816..0192bc550 100644 --- a/apps/opencs/view/world/scriptedit.hpp +++ b/apps/opencs/view/world/scriptedit.hpp @@ -76,4 +76,4 @@ namespace CSVWorld void updateHighlighting(); }; } -#endif // SCRIPTEDIT_H \ No newline at end of file +#endif // SCRIPTEDIT_H diff --git a/apps/opencs/view/world/scripthighlighter.cpp b/apps/opencs/view/world/scripthighlighter.cpp index 36cebcb76..6dda8d4fa 100644 --- a/apps/opencs/view/world/scripthighlighter.cpp +++ b/apps/opencs/view/world/scripthighlighter.cpp @@ -142,4 +142,4 @@ void CSVWorld::ScriptHighlighter::highlightBlock (const QString& text) void CSVWorld::ScriptHighlighter::invalidateIds() { mContext.invalidateIds(); -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 16ffc7b80..561476577 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -46,4 +46,4 @@ namespace CSVWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 5e01ef283..cd9b37a64 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -172,4 +172,4 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) //preview manager.add (CSMWorld::UniversalId::Type_Preview, new CSVDoc::SubViewFactory); -} \ No newline at end of file +} diff --git a/apps/openmw/mwmechanics/stat.cpp b/apps/openmw/mwmechanics/stat.cpp index 3216a46e6..e067e354e 100644 --- a/apps/openmw/mwmechanics/stat.cpp +++ b/apps/openmw/mwmechanics/stat.cpp @@ -31,4 +31,4 @@ void MWMechanics::SkillValue::readState (const ESM::StatState& state) { AttributeValue::readState (state); mProgress = state.mProgress; -} \ No newline at end of file +} diff --git a/apps/openmw/mwscript/transformationextensions.hpp b/apps/openmw/mwscript/transformationextensions.hpp index a25cc0c3d..7a4d29e06 100644 --- a/apps/openmw/mwscript/transformationextensions.hpp +++ b/apps/openmw/mwscript/transformationextensions.hpp @@ -20,4 +20,4 @@ namespace MWScript } } -#endif \ No newline at end of file +#endif diff --git a/apps/openmw/mwworld/failedaction.hpp b/apps/openmw/mwworld/failedaction.hpp index c69d62023..f248ee3bd 100644 --- a/apps/openmw/mwworld/failedaction.hpp +++ b/apps/openmw/mwworld/failedaction.hpp @@ -17,4 +17,4 @@ namespace MWWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/openmw/mwworld/manualref.cpp b/apps/openmw/mwworld/manualref.cpp index 30b4fe353..b926c5799 100644 --- a/apps/openmw/mwworld/manualref.cpp +++ b/apps/openmw/mwworld/manualref.cpp @@ -64,4 +64,4 @@ MWWorld::ManualRef::ManualRef(const MWWorld::ESMStore& store, const std::string& } mPtr.getRefData().setCount(count); -} \ No newline at end of file +} diff --git a/components/bsa/resources.cpp b/components/bsa/resources.cpp index d06b3b485..b66da1a76 100644 --- a/components/bsa/resources.cpp +++ b/components/bsa/resources.cpp @@ -50,4 +50,4 @@ void Bsa::registerResources (const Files::Collections& collections, throw std::runtime_error(message.str()); } } -} \ No newline at end of file +} diff --git a/components/compiler/extensions0.hpp b/components/compiler/extensions0.hpp index d51507711..83f3a44fa 100644 --- a/components/compiler/extensions0.hpp +++ b/components/compiler/extensions0.hpp @@ -78,4 +78,4 @@ namespace Compiler } } -#endif \ No newline at end of file +#endif diff --git a/components/compiler/nullerrorhandler.cpp b/components/compiler/nullerrorhandler.cpp index 3071701e8..ee2884705 100644 --- a/components/compiler/nullerrorhandler.cpp +++ b/components/compiler/nullerrorhandler.cpp @@ -3,4 +3,4 @@ void Compiler::NullErrorHandler::report (const std::string& message, const TokenLoc& loc, Type type) {} -void Compiler::NullErrorHandler::report (const std::string& message, Type type) {} \ No newline at end of file +void Compiler::NullErrorHandler::report (const std::string& message, Type type) {} diff --git a/components/compiler/opcodes.cpp b/components/compiler/opcodes.cpp index 8617062d6..03081dff9 100644 --- a/components/compiler/opcodes.cpp +++ b/components/compiler/opcodes.cpp @@ -10,4 +10,4 @@ namespace Compiler "playerviewswitch", "vanitymode" }; } -} \ No newline at end of file +} diff --git a/components/compiler/quickfileparser.cpp b/components/compiler/quickfileparser.cpp index f3d8063b2..4e9f76e13 100644 --- a/components/compiler/quickfileparser.cpp +++ b/components/compiler/quickfileparser.cpp @@ -49,4 +49,4 @@ bool Compiler::QuickFileParser::parseSpecial (int code, const TokenLoc& loc, Sca void Compiler::QuickFileParser::parseEOF (Scanner& scanner) { -} \ No newline at end of file +} diff --git a/components/esm/cellid.hpp b/components/esm/cellid.hpp index 40bc552e0..44a1b387a 100644 --- a/components/esm/cellid.hpp +++ b/components/esm/cellid.hpp @@ -28,4 +28,4 @@ namespace ESM bool operator!= (const CellId& left, const CellId& right); } -#endif \ No newline at end of file +#endif diff --git a/components/esm/containerstate.cpp b/components/esm/containerstate.cpp index 5dcf17733..80ad5cbdc 100644 --- a/components/esm/containerstate.cpp +++ b/components/esm/containerstate.cpp @@ -13,4 +13,4 @@ void ESM::ContainerState::save (ESMWriter &esm, bool inInventory) const ObjectState::save (esm, inInventory); mInventory.save (esm); -} \ No newline at end of file +} diff --git a/components/esm/globalscript.cpp b/components/esm/globalscript.cpp index 467fe54a1..0129f8eb7 100644 --- a/components/esm/globalscript.cpp +++ b/components/esm/globalscript.cpp @@ -26,4 +26,4 @@ void ESM::GlobalScript::save (ESMWriter &esm) const esm.writeHNT ("RUN_", mRunning); esm.writeHNOString ("TARG", mTargetId); -} \ No newline at end of file +} diff --git a/components/esm/queststate.cpp b/components/esm/queststate.cpp index e93826725..c8cff7adc 100644 --- a/components/esm/queststate.cpp +++ b/components/esm/queststate.cpp @@ -16,4 +16,4 @@ void ESM::QuestState::save (ESMWriter &esm) const esm.writeHNString ("YETO", mTopic); esm.writeHNT ("QSTA", mState); esm.writeHNT ("QFIN", mFinished); -} \ No newline at end of file +} diff --git a/extern/oics/ICSChannelListener.h b/extern/oics/ICSChannelListener.h index d520b3bce..a202e7e22 100644 --- a/extern/oics/ICSChannelListener.h +++ b/extern/oics/ICSChannelListener.h @@ -43,4 +43,4 @@ namespace ICS } -#endif \ No newline at end of file +#endif diff --git a/extern/oics/ICSControlListener.h b/extern/oics/ICSControlListener.h index 067b2d6f2..97b3940be 100644 --- a/extern/oics/ICSControlListener.h +++ b/extern/oics/ICSControlListener.h @@ -43,4 +43,4 @@ namespace ICS } -#endif \ No newline at end of file +#endif From 37a6d7da761edb862d9a6af8fd0f11e1a9c9e846 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Mar 2015 20:04:25 +0100 Subject: [PATCH 599/740] WindowManager refactoring --- apps/openmw/mwbase/windowmanager.hpp | 24 +++---- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 3 - apps/openmw/mwgui/dialogue.cpp | 43 ++----------- apps/openmw/mwgui/hud.cpp | 3 +- apps/openmw/mwgui/inventorywindow.cpp | 10 +-- apps/openmw/mwgui/windowmanagerimp.cpp | 64 +++++++++++++------ apps/openmw/mwgui/windowmanagerimp.hpp | 20 +++--- apps/openmw/mwinput/inputmanagerimp.cpp | 6 +- apps/openmw/mwworld/actionopen.cpp | 5 +- apps/openmw/mwworld/actionrepair.cpp | 1 - 10 files changed, 77 insertions(+), 102 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 2c4cb360d..b43dde4dd 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -149,17 +149,16 @@ namespace MWBase /// \todo investigate, if we really need to expose every single lousy UI element to the outside world virtual MWGui::DialogueWindow* getDialogueWindow() = 0; - virtual MWGui::ContainerWindow* getContainerWindow() = 0; virtual MWGui::InventoryWindow* getInventoryWindow() = 0; virtual MWGui::BookWindow* getBookWindow() = 0; virtual MWGui::ScrollWindow* getScrollWindow() = 0; virtual MWGui::CountDialog* getCountDialog() = 0; virtual MWGui::ConfirmationDialog* getConfirmationDialog() = 0; virtual MWGui::TradeWindow* getTradeWindow() = 0; - virtual MWGui::SpellBuyingWindow* getSpellBuyingWindow() = 0; - virtual MWGui::TravelWindow* getTravelWindow() = 0; - virtual MWGui::SpellWindow* getSpellWindow() = 0; - virtual MWGui::Console* getConsole() = 0; + + virtual void updateSpellWindow() = 0; + + virtual void setConsoleSelectedObject(const MWWorld::Ptr& object) = 0; virtual void wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount) = 0; @@ -181,12 +180,6 @@ namespace MWBase virtual void configureSkills (const SkillList& major, const SkillList& minor) = 0; ///< configure skill groups, each set contains the skill ID for that group. - virtual void setReputation (int reputation) = 0; - ///< set the current reputation value - - virtual void setBounty (int bounty) = 0; - ///< set the current bounty value - virtual void updateSkillArea() = 0; ///< update display of skills, factions, birth sign, reputation and bounty @@ -303,6 +296,10 @@ namespace MWBase 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 showSoulgemDialog (MWWorld::Ptr item) = 0; @@ -332,9 +329,8 @@ namespace MWBase /// Does the current stack of GUI-windows permit saving? virtual bool isSavingAllowed() const = 0; - /// Returns the current Modal - /** Used to send exit command to active Modal when Esc is pressed **/ - virtual MWGui::WindowModal* getCurrentModal() const = 0; + /// Send exit command to active Modal window + virtual void exitCurrentModal() = 0; /// Sets the current Modal /** Used to send exit command to active Modal when Esc is pressed **/ diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 00e59e2a5..b928738dd 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -179,10 +179,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()->pushGuiMode(MWGui::GM_Companion); MWBase::Environment::get().getWindowManager()->showCompanionWindow(mActor); - } } bool DialogueManager::compile (const std::string& cmd,std::vector& code) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 3bc4292e3..1b07522f3 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -7,12 +7,14 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" +#include "../mwbase/dialoguemanager.hpp" #include "../mwmechanics/npcstats.hpp" @@ -20,12 +22,7 @@ #include "../mwworld/containerstore.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwdialogue/dialoguemanagerimp.hpp" - #include "widgets.hpp" -#include "tradewindow.hpp" -#include "spellbuyingwindow.hpp" -#include "travelwindow.hpp" #include "bookpage.hpp" #include "journalbooks.hpp" // to_utf8_span @@ -337,51 +334,25 @@ namespace MWGui MWBase::Environment::get().getWorld()->getStore().get(); if (topic == gmst.find("sPersuasion")->getString()) - { mPersuasionDialog.setVisible(true); - } else if (topic == gmst.find("sCompanionShare")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Companion); MWBase::Environment::get().getWindowManager()->showCompanionWindow(mPtr); - } else if (!MWBase::Environment::get().getDialogueManager()->checkServiceRefused()) { if (topic == gmst.find("sBarter")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Barter); - MWBase::Environment::get().getWindowManager()->getTradeWindow()->startTrade(mPtr); - } + MWBase::Environment::get().getWindowManager()->startTrade(mPtr); else if (topic == gmst.find("sSpells")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellBuying); - MWBase::Environment::get().getWindowManager()->getSpellBuyingWindow()->startSpellBuying(mPtr); - } + MWBase::Environment::get().getWindowManager()->startSpellBuying(mPtr); else if (topic == gmst.find("sTravel")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Travel); - MWBase::Environment::get().getWindowManager()->getTravelWindow()->startTravel(mPtr); - } + MWBase::Environment::get().getWindowManager()->startTravel(mPtr); else if (topic == gmst.find("sSpellMakingMenuTitle")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellCreation); MWBase::Environment::get().getWindowManager()->startSpellMaking (mPtr); - } else if (topic == gmst.find("sEnchanting")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Enchanting); MWBase::Environment::get().getWindowManager()->startEnchanting (mPtr); - } else if (topic == gmst.find("sServiceTrainingTitle")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Training); MWBase::Environment::get().getWindowManager()->startTraining (mPtr); - } else if (topic == gmst.find("sRepair")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_MerchantRepair); MWBase::Environment::get().getWindowManager()->startRepair (mPtr); - } } } } @@ -440,8 +411,6 @@ namespace MWGui bool isCompanion = !mPtr.getClass().getScript(mPtr).empty() && mPtr.getRefData().getLocals().getIntVar(mPtr.getClass().getScript(mPtr), "companion"); - bool anyService = mServices > 0 || isCompanion || mPtr.getTypeName() == typeid(ESM::NPC).name(); - const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); @@ -472,7 +441,7 @@ namespace MWGui if (isCompanion) mTopicsList->addItem(gmst.find("sCompanionShare")->getString()); - if (anyService) + if (mTopicsList->getItemCount() > 0) mTopicsList->addSeparator(); diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 97a113527..eb458be50 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -24,7 +24,6 @@ #include "../mwmechanics/npcstats.hpp" #include "inventorywindow.hpp" -#include "console.hpp" #include "spellicons.hpp" #include "itemmodel.hpp" #include "draganddrop.hpp" @@ -309,7 +308,7 @@ namespace MWGui MWWorld::Ptr object = MWBase::Environment::get().getWorld()->getFacedObject(); if (mode == GM_Console) - MWBase::Environment::get().getWindowManager()->getConsole()->setSelectedObject(object); + MWBase::Environment::get().getWindowManager()->setConsoleSelectedObject(object); else if ((mode == GM_Container) || (mode == GM_Inventory)) { // pick up object diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 919228195..a94df0b01 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -25,7 +25,6 @@ #include "bookwindow.hpp" #include "scrollwindow.hpp" -#include "spellwindow.hpp" #include "itemview.hpp" #include "inventoryitemmodel.hpp" #include "sortfilteritemmodel.hpp" @@ -317,8 +316,7 @@ namespace MWGui void InventoryWindow::updateItemView() { - if (MWBase::Environment::get().getWindowManager()->getSpellWindow()) - MWBase::Environment::get().getWindowManager()->getSpellWindow()->updateSpells(); + MWBase::Environment::get().getWindowManager()->updateSpellWindow(); mItemView->update(); mPreviewDirty = true; @@ -568,8 +566,7 @@ namespace MWGui void InventoryWindow::notifyContentChanged() { // update the spell window just in case new enchanted items were added to inventory - if (MWBase::Environment::get().getWindowManager()->getSpellWindow()) - MWBase::Environment::get().getWindowManager()->getSpellWindow()->updateSpells(); + MWBase::Environment::get().getWindowManager()->updateSpellWindow(); MWBase::Environment::get().getMechanicsManager()->updateMagicEffects( MWBase::Environment::get().getWorld()->getPlayerPtr()); @@ -626,8 +623,7 @@ namespace MWGui MWBase::Environment::get().getMechanicsManager()->itemTaken(player, newObject, MWWorld::Ptr(), count); - if (MWBase::Environment::get().getWindowManager()->getSpellWindow()) - MWBase::Environment::get().getWindowManager()->getSpellWindow()->updateSpells(); + MWBase::Environment::get().getWindowManager()->updateSpellWindow(); } void InventoryWindow::cycle(bool next) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 815f342a4..fddc92dc1 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -715,16 +715,6 @@ namespace MWGui mPlayerMinorSkills = minor; } - void WindowManager::setReputation (int reputation) - { - mStatsWindow->setReputation (reputation); - } - - void WindowManager::setBounty (int bounty) - { - mStatsWindow->setBounty (bounty); - } - void WindowManager::updateSkillArea() { mStatsWindow->updateSkillArea(); @@ -1287,17 +1277,12 @@ namespace MWGui } MWGui::DialogueWindow* WindowManager::getDialogueWindow() { return mDialogueWindow; } - MWGui::ContainerWindow* WindowManager::getContainerWindow() { return mContainerWindow; } MWGui::InventoryWindow* WindowManager::getInventoryWindow() { return mInventoryWindow; } MWGui::BookWindow* WindowManager::getBookWindow() { return mBookWindow; } MWGui::ScrollWindow* WindowManager::getScrollWindow() { return mScrollWindow; } MWGui::CountDialog* WindowManager::getCountDialog() { return mCountDialog; } MWGui::ConfirmationDialog* WindowManager::getConfirmationDialog() { return mConfirmationDialog; } MWGui::TradeWindow* WindowManager::getTradeWindow() { return mTradeWindow; } - MWGui::SpellBuyingWindow* WindowManager::getSpellBuyingWindow() { return mSpellBuyingWindow; } - MWGui::TravelWindow* WindowManager::getTravelWindow() { return mTravelWindow; } - MWGui::SpellWindow* WindowManager::getSpellWindow() { return mSpellWindow; } - MWGui::Console* WindowManager::getConsole() { return mConsole; } bool WindowManager::isAllowed (GuiWindow wnd) const { @@ -1459,11 +1444,13 @@ namespace MWGui void WindowManager::startSpellMaking(MWWorld::Ptr actor) { + pushGuiMode(GM_SpellCreation); mSpellCreationDialog->startSpellMaking (actor); } void WindowManager::startEnchanting (MWWorld::Ptr actor) { + pushGuiMode(GM_Enchanting); mEnchantingDialog->startEnchanting (actor); } @@ -1474,16 +1461,19 @@ namespace MWGui 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); } @@ -1494,6 +1484,7 @@ namespace MWGui void WindowManager::showCompanionWindow(MWWorld::Ptr actor) { + pushGuiMode(MWGui::GM_Companion); mCompanionWindow->open(actor); } @@ -1744,12 +1735,10 @@ namespace MWGui mVideoWidget->autoResize(stretch); } - WindowModal* WindowManager::getCurrentModal() const + void WindowManager::exitCurrentModal() { - if(!mCurrentModals.empty()) - return mCurrentModals.top(); - else - return NULL; + if (!mCurrentModals.empty()) + mCurrentModals.top()->exit(); } void WindowManager::removeCurrentModal(WindowModal* input) @@ -1874,4 +1863,39 @@ namespace MWGui mInventoryWindow->cycle(next); } + 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); + } + + 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->open(container, loot); + } + } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index fbbc295b3..66125d4d0 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -154,17 +154,16 @@ namespace MWGui /// \todo investigate, if we really need to expose every single lousy UI element to the outside world virtual MWGui::DialogueWindow* getDialogueWindow(); - virtual MWGui::ContainerWindow* getContainerWindow(); virtual MWGui::InventoryWindow* getInventoryWindow(); virtual MWGui::BookWindow* getBookWindow(); virtual MWGui::ScrollWindow* getScrollWindow(); virtual MWGui::CountDialog* getCountDialog(); virtual MWGui::ConfirmationDialog* getConfirmationDialog(); virtual MWGui::TradeWindow* getTradeWindow(); - virtual MWGui::SpellBuyingWindow* getSpellBuyingWindow(); - virtual MWGui::TravelWindow* getTravelWindow(); - virtual MWGui::SpellWindow* getSpellWindow(); - virtual MWGui::Console* getConsole(); + + virtual void updateSpellWindow(); + + virtual void setConsoleSelectedObject(const MWWorld::Ptr& object); virtual void wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount); @@ -182,8 +181,6 @@ namespace MWGui virtual void setPlayerClass (const ESM::Class &class_); ///< set current class of player virtual void configureSkills (const SkillList& major, const SkillList& minor); ///< configure skill groups, each set contains the skill ID for that group. - virtual void setReputation (int reputation); ///< set the current reputation value - virtual void setBounty (int bounty); ///< set the current bounty value virtual void updateSkillArea(); ///< update display of skills, factions, birth sign, reputation and bounty virtual void changeCell(MWWorld::CellStore* cell); ///< change the active cell @@ -292,6 +289,10 @@ namespace MWGui 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 frameStarted(float dt); @@ -317,9 +318,8 @@ namespace MWGui /// Does the current stack of GUI-windows permit saving? virtual bool isSavingAllowed() const; - /// Returns the current Modal - /** Used to send exit command to active Modal when Esc is pressed **/ - virtual WindowModal* getCurrentModal() const; + /// Send exit command to active Modal window **/ + virtual void exitCurrentModal(); /// Sets the current Modal /** Used to send exit command to active Modal when Esc is pressed **/ diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 21576785c..355594204 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -33,8 +33,6 @@ #include "../mwdialogue/dialoguemanagerimp.hpp" -#include "../mwgui/windowbase.hpp" - #include using namespace ICS; @@ -887,7 +885,7 @@ namespace MWInput void InputManager::toggleMainMenu() { if (MyGUI::InputManager::getInstance().isModalAny()) { - MWBase::Environment::get().getWindowManager()->getCurrentModal()->exit(); + MWBase::Environment::get().getWindowManager()->exitCurrentModal(); return; } @@ -1061,7 +1059,7 @@ namespace MWInput } else if (MWBase::Environment::get().getWindowManager()->getMode () == MWGui::GM_QuickKeysMenu) { while(MyGUI::InputManager::getInstance().isModalAny()) { //Handle any open Modal windows - MWBase::Environment::get().getWindowManager()->getCurrentModal()->exit(); + MWBase::Environment::get().getWindowManager()->exitCurrentModal(); } MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); //And handle the actual main window } diff --git a/apps/openmw/mwworld/actionopen.cpp b/apps/openmw/mwworld/actionopen.cpp index e9d8b4716..0df451b18 100644 --- a/apps/openmw/mwworld/actionopen.cpp +++ b/apps/openmw/mwworld/actionopen.cpp @@ -3,8 +3,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwgui/container.hpp" - #include "../mwmechanics/disease.hpp" #include "class.hpp" @@ -25,7 +23,6 @@ namespace MWWorld MWMechanics::diseaseContact(actor, getTarget()); - MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Container); - MWBase::Environment::get().getWindowManager()->getContainerWindow()->open(getTarget(), mLoot); + MWBase::Environment::get().getWindowManager()->openContainer(getTarget(), mLoot); } } diff --git a/apps/openmw/mwworld/actionrepair.cpp b/apps/openmw/mwworld/actionrepair.cpp index a86dc38b1..699440a01 100644 --- a/apps/openmw/mwworld/actionrepair.cpp +++ b/apps/openmw/mwworld/actionrepair.cpp @@ -19,7 +19,6 @@ namespace MWWorld return; } - MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Repair); MWBase::Environment::get().getWindowManager()->startRepairItem(getTarget()); } } From 48ea6286fd7b5ba08f3235d594a9f8ff5b5423ed Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Mar 2015 20:33:55 +0100 Subject: [PATCH 600/740] Book/scroll window refactoring --- apps/openmw/mwbase/windowmanager.hpp | 4 ++-- apps/openmw/mwgui/bookwindow.cpp | 4 ++-- apps/openmw/mwgui/bookwindow.hpp | 9 +++++---- apps/openmw/mwgui/inventorywindow.cpp | 9 --------- apps/openmw/mwgui/scrollwindow.cpp | 4 ++-- apps/openmw/mwgui/scrollwindow.hpp | 4 ++-- apps/openmw/mwgui/windowmanagerimp.cpp | 14 ++++++++++++-- apps/openmw/mwgui/windowmanagerimp.hpp | 4 ++-- apps/openmw/mwworld/actionread.cpp | 22 ++++++---------------- 9 files changed, 33 insertions(+), 41 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index b43dde4dd..fdd51ef44 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -150,8 +150,6 @@ namespace MWBase /// \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::BookWindow* getBookWindow() = 0; - virtual MWGui::ScrollWindow* getScrollWindow() = 0; virtual MWGui::CountDialog* getCountDialog() = 0; virtual MWGui::ConfirmationDialog* getConfirmationDialog() = 0; virtual MWGui::TradeWindow* getTradeWindow() = 0; @@ -300,6 +298,8 @@ namespace MWBase 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; diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index da0d1950e..55a9b6191 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -73,7 +73,7 @@ namespace MWGui mPages.clear(); } - void BookWindow::open (MWWorld::Ptr book) + void BookWindow::open (MWWorld::Ptr book, bool showTakeButton) { mBook = book; @@ -90,7 +90,7 @@ namespace MWGui updatePages(); - setTakeButtonShow(true); + setTakeButtonShow(showTakeButton); } void BookWindow::exit() diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index ea3057a6f..8ad4f6830 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -16,10 +16,7 @@ namespace MWGui virtual void exit(); - void open(MWWorld::Ptr book); - void setTakeButtonShow(bool show); - void nextPage(); - void prevPage(); + void open(MWWorld::Ptr book, bool showTakeButton); void setInventoryAllowed(bool allowed); protected: @@ -28,6 +25,10 @@ namespace MWGui void onCloseButtonClicked (MyGUI::Widget* sender); void onTakeButtonClicked (MyGUI::Widget* sender); void onMouseWheel(MyGUI::Widget* _sender, int _rel); + void setTakeButtonShow(bool show); + + void nextPage(); + void prevPage(); void updatePages(); void clearPages(); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index a94df0b01..80b246e84 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -23,8 +23,6 @@ #include "../mwbase/scriptmanager.hpp" #include "../mwrender/characterpreview.hpp" -#include "bookwindow.hpp" -#include "scrollwindow.hpp" #include "itemview.hpp" #include "inventoryitemmodel.hpp" #include "sortfilteritemmodel.hpp" @@ -430,13 +428,6 @@ namespace MWGui action->execute (MWBase::Environment::get().getWorld()->getPlayerPtr()); - // this is necessary for books/scrolls: if they are already in the player's inventory, - // the "Take" button should not be visible. - // NOTE: the take button is "reset" when the window opens, so we can safely do the following - // without screwing up future book windows - MWBase::Environment::get().getWindowManager()->getBookWindow()->setTakeButtonShow(false); - MWBase::Environment::get().getWindowManager()->getScrollWindow()->setTakeButtonShow(false); - mSkippedToEquip = MWWorld::Ptr(); } else diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index d61693d39..85d1c8c4e 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -48,7 +48,7 @@ namespace MWGui center(); } - void ScrollWindow::open (MWWorld::Ptr scroll) + void ScrollWindow::open (MWWorld::Ptr scroll, bool showTakeButton) { // no 3d sounds because the object could be in a container. MWBase::Environment::get().getSoundManager()->playSound ("scroll", 1.0, 1.0); @@ -71,7 +71,7 @@ namespace MWGui mTextView->setViewOffset(MyGUI::IntPoint(0,0)); - setTakeButtonShow(true); + setTakeButtonShow(showTakeButton); } void ScrollWindow::exit() diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index e1f86529a..3c9e718b6 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -17,14 +17,14 @@ namespace MWGui public: ScrollWindow (); - void open (MWWorld::Ptr scroll); + void open (MWWorld::Ptr scroll, bool showTakeButton); virtual void exit(); - void setTakeButtonShow(bool show); void setInventoryAllowed(bool allowed); protected: void onCloseButtonClicked (MyGUI::Widget* _sender); void onTakeButtonClicked (MyGUI::Widget* _sender); + void setTakeButtonShow(bool show); private: Gui::ImageButton* mCloseButton; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index fddc92dc1..279c2f22e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1278,8 +1278,6 @@ namespace MWGui MWGui::DialogueWindow* WindowManager::getDialogueWindow() { return mDialogueWindow; } MWGui::InventoryWindow* WindowManager::getInventoryWindow() { return mInventoryWindow; } - MWGui::BookWindow* WindowManager::getBookWindow() { return mBookWindow; } - MWGui::ScrollWindow* WindowManager::getScrollWindow() { return mScrollWindow; } MWGui::CountDialog* WindowManager::getCountDialog() { return mCountDialog; } MWGui::ConfirmationDialog* WindowManager::getConfirmationDialog() { return mConfirmationDialog; } MWGui::TradeWindow* WindowManager::getTradeWindow() { return mTradeWindow; } @@ -1898,4 +1896,16 @@ namespace MWGui mContainerWindow->open(container, loot); } + void WindowManager::showBook(const MWWorld::Ptr &item, bool showTakeButton) + { + pushGuiMode(GM_Book); + mBookWindow->open(item, showTakeButton); + } + + void WindowManager::showScroll(const MWWorld::Ptr &item, bool showTakeButton) + { + pushGuiMode(GM_Scroll); + mScrollWindow->open(item, showTakeButton); + } + } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 66125d4d0..297480d20 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -155,8 +155,6 @@ namespace MWGui /// \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::BookWindow* getBookWindow(); - virtual MWGui::ScrollWindow* getScrollWindow(); virtual MWGui::CountDialog* getCountDialog(); virtual MWGui::ConfirmationDialog* getConfirmationDialog(); virtual MWGui::TradeWindow* getTradeWindow(); @@ -293,6 +291,8 @@ namespace MWGui 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 frameStarted(float dt); diff --git a/apps/openmw/mwworld/actionread.cpp b/apps/openmw/mwworld/actionread.cpp index 0a4e2d6c9..cd0471a0e 100644 --- a/apps/openmw/mwworld/actionread.cpp +++ b/apps/openmw/mwworld/actionread.cpp @@ -4,13 +4,8 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" -#include "../mwworld/player.hpp" - #include "../mwmechanics/npcstats.hpp" -#include "../mwgui/bookwindow.hpp" -#include "../mwgui/scrollwindow.hpp" - #include "player.hpp" #include "class.hpp" #include "esmstore.hpp" @@ -33,27 +28,22 @@ namespace MWWorld return; } + bool showTakeButton = (getTarget().getContainerStore() != &actor.getClass().getContainerStore(actor)); + LiveCellRef *ref = getTarget().get(); if (ref->mBase->mData.mIsScroll) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Scroll); - MWBase::Environment::get().getWindowManager()->getScrollWindow()->open(getTarget()); - } + MWBase::Environment::get().getWindowManager()->showScroll(getTarget(), showTakeButton); else - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Book); - MWBase::Environment::get().getWindowManager()->getBookWindow()->open(getTarget()); - } + MWBase::Environment::get().getWindowManager()->showBook(getTarget(), showTakeButton); - MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr(); - MWMechanics::NpcStats& npcStats = player.getClass().getNpcStats (player); + MWMechanics::NpcStats& npcStats = actor.getClass().getNpcStats (actor); // Skill gain from books if (ref->mBase->mData.mSkillID >= 0 && ref->mBase->mData.mSkillID < ESM::Skill::Length && !npcStats.hasBeenUsed (ref->mBase->mId)) { - MWWorld::LiveCellRef *playerRef = player.get(); + MWWorld::LiveCellRef *playerRef = actor.get(); const ESM::Class *class_ = MWBase::Environment::get().getWorld()->getStore().get().find ( From 68de87605126fccb4dd816f960c2efc8d4738d96 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Mar 2015 21:12:08 +0100 Subject: [PATCH 601/740] Switch to weapon drawstate when creating a bound weapon (Fixes #2387) --- apps/openmw/mwmechanics/actors.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index ca4105bc6..23bd1ea6a 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -54,9 +54,17 @@ void adjustBoundItem (const std::string& item, bool bound, const MWWorld::Ptr& a { if (actor.getClass().getContainerStore(actor).count(item) == 0) { - MWWorld::Ptr newPtr = *actor.getClass().getContainerStore(actor).add(item, 1, actor); + MWWorld::InventoryStore& store = actor.getClass().getInventoryStore(actor); + MWWorld::Ptr newPtr = *store.MWWorld::ContainerStore::add(item, 1, actor); MWWorld::ActionEquip action(newPtr); action.execute(actor); + MWWorld::ContainerStoreIterator rightHand = store.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); + // change draw state only if the item is in player's right hand + if (actor == MWBase::Environment::get().getWorld()->getPlayerPtr() + && rightHand != store.end() && newPtr == *rightHand) + { + MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Weapon); + } } } else From dc9af19dcfbb075cfbafcb741adbd4fb6964c2b7 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 12 Mar 2015 08:28:26 +1100 Subject: [PATCH 602/740] Don't use C++11 features. --- apps/opencs/model/world/record.hpp | 31 +++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp index 1cf14a8f9..6ff33f0c2 100644 --- a/apps/opencs/model/world/record.hpp +++ b/apps/opencs/model/world/record.hpp @@ -40,9 +40,9 @@ namespace CSMWorld ESXRecordT mBase; ESXRecordT mModified; - Record() = default; - Record(const Record&) = default; - Record& operator= (const Record&) = default; + Record(); + Record(const Record& record); + Record& operator= (const Record& record); Record(State state, const ESXRecordT *base = 0, const ESXRecordT *modified = 0); @@ -69,6 +69,31 @@ namespace CSMWorld ///< Merge modified into base. }; + template + Record::Record() + : mBase(), mModified() + { } + + template + Record::Record(const Record& record) + : mBase(record.mBase), mModified(record.mModified) + { + mState = record.mState; + } + + template + Record& Record::operator= (const Record& record) + { + if(this != &record) + { + mBase = record.mBase; + mModified = record.mModified; + mState = record.mState; + } + + return *this; + } + template Record::Record(State state, const ESXRecordT *base, const ESXRecordT *modified) { From 3879ce6ac168b942bfd6e894983c9baadd48b288 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Mar 2015 23:07:39 +0100 Subject: [PATCH 603/740] Get rid of "player" string checks (Fixes #2216) --- apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/npc.cpp | 14 +++++------ apps/openmw/mwmechanics/actors.cpp | 15 ++++++------ apps/openmw/mwmechanics/character.cpp | 16 ++++++------- apps/openmw/mwmechanics/combat.cpp | 8 +++---- apps/openmw/mwmechanics/spellcasting.cpp | 24 +++++++++---------- apps/openmw/mwrender/renderingmanager.cpp | 4 ++-- apps/openmw/mwscript/containerextensions.cpp | 2 +- .../mwscript/transformationextensions.cpp | 8 +++---- apps/openmw/mwsound/soundmanagerimp.cpp | 2 +- apps/openmw/mwworld/action.cpp | 2 +- apps/openmw/mwworld/containerstore.cpp | 2 +- apps/openmw/mwworld/failedaction.cpp | 2 +- apps/openmw/mwworld/inventorystore.cpp | 6 ++--- apps/openmw/mwworld/worldimp.cpp | 10 ++++---- 15 files changed, 59 insertions(+), 58 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index ace4949ed..9a3c6c218 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -355,7 +355,7 @@ namespace MWClass if(!object.isEmpty()) getCreatureStats(ptr).setLastHitObject(object.getClass().getId(object)); - if(setOnPcHitMe && !attacker.isEmpty() && attacker.getRefData().getHandle() == "player") + if(setOnPcHitMe && !attacker.isEmpty() && attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) { const std::string &script = ptr.get()->mBase->mScript; /* Set the OnPCHitMe script variable. The script is responsible for clearing it. */ diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index c62257572..deb4b90cd 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -507,7 +507,7 @@ namespace MWClass if(otherstats.isDead()) // Can't hit dead actors return; - if(ptr.getRefData().getHandle() == "player") + if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->setEnemy(victim); int weapskill = ESM::Skill::HandToHand; @@ -549,7 +549,7 @@ namespace MWClass { MWMechanics::getHandToHandDamage(ptr, victim, damage, healthdmg); } - if(ptr.getRefData().getHandle() == "player") + if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) { skillUsageSucceeded(ptr, weapskill, 0); @@ -625,7 +625,7 @@ namespace MWClass if(!object.isEmpty()) getCreatureStats(ptr).setLastHitObject(object.getClass().getId(object)); - if(setOnPcHitMe && !attacker.isEmpty() && attacker.getRefData().getHandle() == "player") + if(setOnPcHitMe && !attacker.isEmpty() && attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) { const std::string &script = ptr.getClass().getScript(ptr); /* Set the OnPCHitMe script variable. The script is responsible for clearing it. */ @@ -708,7 +708,7 @@ namespace MWClass if (armorhealth == 0) armor = *inv.unequipItem(armor, ptr); - if (ptr.getRefData().getHandle() == "player") + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) skillUsageSucceeded(ptr, armor.getClass().getEquipmentSkill(armor), 0); switch(armor.getClass().getEquipmentSkill(armor)) @@ -724,7 +724,7 @@ namespace MWClass break; } } - else if(ptr.getRefData().getHandle() == "player") + else if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) skillUsageSucceeded(ptr, ESM::Skill::Unarmored, 0); } } @@ -737,7 +737,7 @@ namespace MWClass if(damage > 0.0f) { sndMgr->playSound3D(ptr, "Health Damage", 1.0f, 1.0f); - if (ptr.getRefData().getHandle() == "player") + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->activateHitOverlay(); } float health = getCreatureStats(ptr).getHealth().getCurrent() - damage; @@ -815,7 +815,7 @@ namespace MWClass const MWWorld::Ptr& actor) const { // player got activated by another NPC - if(ptr.getRefData().getHandle() == "player") + if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) return boost::shared_ptr(new MWWorld::ActionTalk(actor)); // Werewolfs can't activate NPCs diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 23bd1ea6a..c25e207c6 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -99,7 +99,7 @@ bool disintegrateSlot (MWWorld::Ptr ptr, int slot, float disintegrate) if (charge == 0) { // Will unequip the broken item and try to find a replacement - if (ptr.getRefData().getHandle() != "player") + if (ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) inv.autoEquip(ptr); else inv.unequipItem(*item, ptr); @@ -154,6 +154,7 @@ void adjustCommandedActor (const MWWorld::Ptr& actor) if (check.mCommanded && !hasCommandPackage) { + // FIXME: don't use refid string MWMechanics::AiFollow package("player", true); stats.getAiSequence().stack(package, actor); } @@ -244,7 +245,7 @@ namespace MWMechanics gem->getContainerStore()->unstack(*gem, caster); gem->getCellRef().setSoul(mCreature.getCellRef().getRefId()); - if (caster.getRefData().getHandle() == "player") + if (caster == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sSoultrapSuccess}"); const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get() @@ -433,7 +434,7 @@ namespace MWMechanics int intelligence = creatureStats.getAttribute(ESM::Attribute::Intelligence).getModified(); float base = 1.f; - if (ptr.getCellRef().getRefId() == "player") + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) base = MWBase::Environment::get().getWorld()->getStore().get().find("fPCbaseMagickaMult")->getFloat(); else base = MWBase::Environment::get().getWorld()->getStore().get().find("fNPCbaseMagickaMult")->getFloat(); @@ -543,7 +544,7 @@ namespace MWMechanics { spells.worsenCorprus(it->first); - if (ptr.getRefData().getHandle() == "player") + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicCorprusWorsens}"); } } @@ -665,7 +666,7 @@ namespace MWMechanics } } - if (receivedMagicDamage && ptr.getRefData().getHandle() == "player") + if (receivedMagicDamage && ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->activateHitOverlay(false); creatureStats.setHealth(health); @@ -848,7 +849,7 @@ namespace MWMechanics void Actors::updateEquippedLight (const MWWorld::Ptr& ptr, float duration) { - bool isPlayer = ptr.getRefData().getHandle()=="player"; + bool isPlayer = (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()); MWWorld::InventoryStore &inventoryStore = ptr.getClass().getInventoryStore(ptr); MWWorld::ContainerStoreIterator heldIter = @@ -1157,7 +1158,7 @@ namespace MWMechanics // Handle player last, in case a cell transition occurs by casting a teleportation spell // (would invalidate the iterator) - if (iter->first.getCellRef().getRefId() == "player") + if (iter->first == MWBase::Environment::get().getWorld()->getPlayerPtr()) { playerCharacter = iter->second->getCharacterController(); continue; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index c8834e095..28028500a 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1010,7 +1010,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.getRefData().getHandle() == "player") + if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) { std::string selectedSpell = MWBase::Environment::get().getWindowManager()->getSelectedSpell(); stats.getSpells().setSelectedSpell(selectedSpell); @@ -1094,7 +1094,7 @@ bool CharacterController::updateWeaponState() mAttackType = "shoot"; else { - if(isWeapon && mPtr.getRefData().getHandle() == "player" && + if(isWeapon && mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr() && Settings::Manager::getBool("best attack", "Game")) { MWWorld::ContainerStoreIterator weapon = mPtr.getClass().getInventoryStore(mPtr).getSlot(MWWorld::InventoryStore::Slot_CarriedRight); @@ -1421,7 +1421,7 @@ void CharacterController::update(float duration) // advance athletics - if(mHasMovedInXY && mPtr.getRefData().getHandle() == "player") + if(mHasMovedInXY && mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) { if(inwater) { @@ -1521,7 +1521,7 @@ void CharacterController::update(float duration) } // advance acrobatics - if (mPtr.getRefData().getHandle() == "player") + if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 0); // decrease fatigue @@ -1564,7 +1564,7 @@ void CharacterController::update(float duration) else { // report acrobatics progression - if (mPtr.getRefData().getHandle() == "player") + if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 1); } } @@ -1797,7 +1797,7 @@ bool CharacterController::kill() { if( isDead() ) { - if( mPtr.getRefData().getHandle()=="player" && !isAnimPlaying(mCurrentDeath) ) + if( mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr() && !isAnimPlaying(mCurrentDeath) ) { //player's death animation is over MWBase::Environment::get().getStateManager()->askLoadRecent(); @@ -1813,7 +1813,7 @@ bool CharacterController::kill() mCurrentIdle.clear(); // Play Death Music if it was the player dying - if(mPtr.getRefData().getHandle()=="player") + if(mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getSoundManager()->streamMusic("Special/MW_Death.mp3"); return true; @@ -1854,7 +1854,7 @@ void CharacterController::updateMagicEffects() float alpha = 1.f; if (mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Invisibility).getMagnitude()) { - if (mPtr.getRefData().getHandle() == "player") + if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) alpha = 0.4f; else alpha = 0.f; diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 42380664b..b8ffa63e2 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -133,7 +133,7 @@ namespace MWMechanics blockerStats.setBlock(true); - if (blocker.getCellRef().getRefId() == "player") + if (blocker == MWBase::Environment::get().getWorld()->getPlayerPtr()) blocker.getClass().skillUsageSucceeded(blocker, ESM::Skill::Block, 0); return true; @@ -157,7 +157,7 @@ namespace MWMechanics && actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf()) damage *= MWBase::Environment::get().getWorld()->getStore().get().find("fWereWolfSilverWeaponDamageMult")->getFloat(); - if (damage == 0 && attacker.getRefData().getHandle() == "player") + if (damage == 0 && attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResistsWeapons}"); } @@ -176,7 +176,7 @@ namespace MWMechanics return; } - if(attacker.getRefData().getHandle() == "player") + if(attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->setEnemy(victim); int weapskill = ESM::Skill::Marksman; @@ -211,7 +211,7 @@ namespace MWMechanics adjustWeaponDamage(damage, weapon); reduceWeaponCondition(damage, true, weapon, attacker); - if(attacker.getRefData().getHandle() == "player") + if(attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) attacker.getClass().skillUsageSucceeded(attacker, weapskill, 0); if (victim.getClass().getCreatureStats(victim).getKnockedDown()) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 3ca30977b..590c8fe83 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -180,7 +180,7 @@ namespace MWMechanics int actorLuck = stats.getAttribute(ESM::Attribute::Luck).getModified(); float castChance = (lowestSkill - spell->mData.mCost + castBonus + 0.2f * actorWillpower + 0.1f * actorLuck) * stats.getFatigueTerm(); - if (MWBase::Environment::get().getWorld()->getGodModeState() && actor.getRefData().getHandle() == "player") + if (MWBase::Environment::get().getWorld()->getGodModeState() && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) castChance = 100; if (!cap) @@ -387,7 +387,7 @@ namespace MWMechanics if (roll <= x) { // Fully resisted, show message - if (target.getRefData().getHandle() == "player") + if (target == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicPCResisted}"); return; } @@ -405,7 +405,7 @@ namespace MWMechanics if (target.getClass().isActor()) targetEffects += target.getClass().getCreatureStats(target).getMagicEffects(); - bool castByPlayer = (!caster.isEmpty() && caster.getRefData().getHandle() == "player"); + bool castByPlayer = (!caster.isEmpty() && caster == MWBase::Environment::get().getWorld()->getPlayerPtr()); // Try absorbing if it's a spell // NOTE: Vanilla does this once per effect source instead of adding the % from all sources together, not sure @@ -482,7 +482,7 @@ namespace MWMechanics if (magnitudeMult == 0) { // Fully resisted, show message - if (target.getRefData().getHandle() == "player") + if (target == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicPCResisted}"); else if (castByPlayer) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResisted}"); @@ -611,7 +611,7 @@ namespace MWMechanics { if (target.getCellRef().getLockLevel() < magnitude) //If the door is not already locked to a higher value, lock it to spell magnitude { - if (caster.getRefData().getHandle() == "player") + if (caster == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicLockSuccess}"); target.getCellRef().setLockLevel(static_cast(magnitude)); } @@ -626,7 +626,7 @@ namespace MWMechanics if (!caster.isEmpty() && caster.getClass().isActor()) MWBase::Environment::get().getMechanicsManager()->objectOpened(caster, target); - if (caster.getRefData().getHandle() == "player") + if (caster == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicOpenSuccess}"); } target.getCellRef().setLockLevel(-abs(target.getCellRef().getLockLevel())); @@ -652,7 +652,7 @@ namespace MWMechanics else if (effectId == ESM::MagicEffect::RemoveCurse) target.getClass().getCreatureStats(target).getSpells().purgeCurses(); - if (target.getRefData().getHandle() != "player") + if (target != MWBase::Environment::get().getWorld()->getPlayerPtr()) return; if (!MWBase::Environment::get().getWorld()->isTeleportingEnabled()) return; @@ -728,7 +728,7 @@ namespace MWMechanics if (item.getCellRef().getEnchantmentCharge() < castCost) { - if (mCaster.getRefData().getHandle() == "player") + if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicInsufficientCharge}"); // Failure sound @@ -752,14 +752,14 @@ namespace MWMechanics if (enchantment->mData.mType == ESM::Enchantment::WhenUsed) { - if (mCaster.getRefData().getHandle() == "player") + if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr()) mCaster.getClass().skillUsageSucceeded (mCaster, ESM::Skill::Enchant, 1); } if (enchantment->mData.mType == ESM::Enchantment::CastOnce) item.getContainerStore()->remove(item, 1, mCaster); else if (enchantment->mData.mType != ESM::Enchantment::WhenStrikes) { - if (mCaster.getRefData().getHandle() == "player") + if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr()) { mCaster.getClass().skillUsageSucceeded (mCaster, ESM::Skill::Enchant, 3); } @@ -827,7 +827,7 @@ namespace MWMechanics int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] if (!fail && roll >= successChance) { - if (mCaster.getRefData().getHandle() == "player") + if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicSkillFail}"); fail = true; } @@ -845,7 +845,7 @@ namespace MWMechanics } } - if (mCaster.getRefData().getHandle() == "player" && spellIncreasesSkill(spell)) + if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr() && spellIncreasesSkill(spell)) mCaster.getClass().skillUsageSucceeded(mCaster, spellSchoolToSkill(school), 0); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 78ab45881..8fb1ee53c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -321,7 +321,7 @@ void RenderingManager::updatePlayerPtr(const MWWorld::Ptr &ptr) void RenderingManager::rebuildPtr(const MWWorld::Ptr &ptr) { NpcAnimation *anim = NULL; - if(ptr.getRefData().getHandle() == "player") + if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) anim = mPlayerAnimation; else if(ptr.getClass().isActor()) anim = dynamic_cast(mActors->getAnimation(ptr)); @@ -955,7 +955,7 @@ Animation* RenderingManager::getAnimation(const MWWorld::Ptr &ptr) { Animation *anim = mActors->getAnimation(ptr); - if(!anim && ptr.getRefData().getHandle() == "player") + if(!anim && ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) anim = mPlayerAnimation; if (!anim) diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 86329191e..70475d8e2 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -175,7 +175,7 @@ namespace MWScript MWWorld::ActionEquip action (*it); action.execute(ptr); - if (ptr.getRefData().getHandle() == "player" && !ptr.getClass().getScript(ptr).empty()) + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr() && !ptr.getClass().getScript(ptr).empty()) ptr.getRefData().getLocals().setVarByInt(ptr.getClass().getScript(ptr), "onpcequip", 1); } }; diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 1ed5f0c30..f87983ce8 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -212,7 +212,7 @@ namespace MWScript if (!ptr.isInCell()) return; - if (ptr.getRefData().getHandle() == "player") + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) { MWBase::Environment::get().getWorld()->getPlayer().setTeleported(true); } @@ -287,7 +287,7 @@ namespace MWScript if (ptr.getContainerStore()) return; - if (ptr.getRefData().getHandle() == "player") + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) { MWBase::Environment::get().getWorld()->getPlayer().setTeleported(true); } @@ -352,7 +352,7 @@ namespace MWScript if (!ptr.isInCell()) return; - if (ptr.getRefData().getHandle() == "player") + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) { MWBase::Environment::get().getWorld()->getPlayer().setTeleported(true); } @@ -371,7 +371,7 @@ namespace MWScript // another morrowind oddity: player will be moved to the exterior cell at this location, // non-player actors will move within the cell they are in. MWWorld::Ptr updated; - if (ptr.getRefData().getHandle() == "player") + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) { MWWorld::CellStore* cell = MWBase::Environment::get().getWorld()->getExterior(cx,cy); MWBase::Environment::get().getWorld()->moveObject(ptr,cell,x,y,z); diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index b3978f9d5..998cc460b 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -477,7 +477,7 @@ namespace MWSound while(snditer != mActiveSounds.end()) { if(snditer->second.first != MWWorld::Ptr() && - snditer->second.first.getCellRef().getRefId() != "player" && + snditer->second.first != MWBase::Environment::get().getWorld()->getPlayerPtr() && snditer->second.first.getCell() == cell) { snditer->first->stop(); diff --git a/apps/openmw/mwworld/action.cpp b/apps/openmw/mwworld/action.cpp index 0fe061e5c..1c360fd4d 100644 --- a/apps/openmw/mwworld/action.cpp +++ b/apps/openmw/mwworld/action.cpp @@ -20,7 +20,7 @@ void MWWorld::Action::execute (const Ptr& actor) { if (!mSoundId.empty()) { - if (mKeepSound && actor.getRefData().getHandle()=="player") + if (mKeepSound && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getSoundManager()->playSound(mSoundId, 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Normal,mSoundOffset); else diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 8ef6799ba..d4aadc6c7 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -210,7 +210,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add(const std::string & { MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), id, count); // a bit pointless to set owner for the player - if (actorPtr.getRefData().getHandle() != "player") + if (actorPtr != MWBase::Environment::get().getWorld()->getPlayerPtr()) return add(ref.getPtr(), count, actorPtr, true); else return add(ref.getPtr(), count, actorPtr, false); diff --git a/apps/openmw/mwworld/failedaction.cpp b/apps/openmw/mwworld/failedaction.cpp index 7c8ef8c7b..cf5a2a5c2 100644 --- a/apps/openmw/mwworld/failedaction.cpp +++ b/apps/openmw/mwworld/failedaction.cpp @@ -13,7 +13,7 @@ namespace MWWorld void FailedAction::executeImp(const Ptr &actor) { - if(actor.getRefData().getHandle() == "player" && !mMessage.empty()) + if(actor == MWBase::Environment::get().getWorld()->getPlayerPtr() && !mMessage.empty()) MWBase::Environment::get().getWindowManager()->messageBox(mMessage); } } diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 9ad490d69..da43df513 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -133,7 +133,7 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::add(const Ptr& itemPtr, const MWWorld::ContainerStoreIterator& retVal = MWWorld::ContainerStore::add(itemPtr, count, actorPtr, setOwner); // Auto-equip items if an armor/clothing or weapon item is added, but not for the player nor werewolves - if (actorPtr.getRefData().getHandle() != "player" + if (actorPtr != MWBase::Environment::get().getWorld()->getPlayerPtr() && !(actorPtr.getClass().isNpc() && actorPtr.getClass().getNpcStats(actorPtr).isWerewolf())) { std::string type = itemPtr.getTypeName(); @@ -503,7 +503,7 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor // If an armor/clothing item is removed, try to find a replacement, // but not for the player nor werewolves. - if ((actor.getRefData().getHandle() != "player") + if ((actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) && !(actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf())) { std::string type = item.getTypeName(); @@ -535,7 +535,7 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipSlot(int slot, c { retval = restack(*it); - if (actor.getRefData().getHandle() == "player") + if (actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) { // Unset OnPCEquip Variable on item's script, if it has a script with that variable declared const std::string& script = it->getClass().getScript(*it); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 97b2cd204..518c88ead 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1406,7 +1406,7 @@ namespace MWWorld PtrVelocityList::const_iterator player(results.end()); for(PtrVelocityList::const_iterator iter(results.begin());iter != results.end();++iter) { - if(iter->first.getRefData().getHandle() == "player") + if(iter->first == getPlayerPtr()) { /* Handle player last, in case a cell transition occurs */ player = iter; @@ -2228,7 +2228,7 @@ namespace MWWorld if (healthPerSecond > 0.0f) { - if (actor.getRefData().getHandle() == "player") + if (actor == getPlayerPtr()) MWBase::Environment::get().getWindowManager()->activateHitOverlay(false); if (!MWBase::Environment::get().getSoundManager()->getSoundPlaying(actor, "Health Damage")) @@ -2259,7 +2259,7 @@ namespace MWWorld if (healthPerSecond > 0.0f) { - if (actor.getRefData().getHandle() == "player") + if (actor == getPlayerPtr()) MWBase::Environment::get().getWindowManager()->activateHitOverlay(false); if (!MWBase::Environment::get().getSoundManager()->getSoundPlaying(actor, "Health Damage")) @@ -2516,7 +2516,7 @@ namespace MWWorld // the following is just for reattaching the camera properly. mRendering->rebuildPtr(actor); - if(actor.getRefData().getHandle() == "player") + if(actor == getPlayerPtr()) { // Update the GUI only when called on the player MWBase::WindowManager* windowManager = MWBase::Environment::get().getWindowManager(); @@ -3167,7 +3167,7 @@ namespace MWWorld void World::spawnBloodEffect(const Ptr &ptr, const Vector3 &worldPosition) { - if (ptr.getRefData().getHandle() == "player" && Settings::Manager::getBool("hit fader", "GUI")) + if (ptr == getPlayerPtr() && Settings::Manager::getBool("hit fader", "GUI")) return; int type = ptr.getClass().getBloodTexture(ptr); From 304277429f07659cd8fcf5b1ffc91657bcc0ed21 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Mar 2015 00:21:46 +0100 Subject: [PATCH 604/740] Rename variable to not show up in search for "TODO" comments. --- components/fontloader/fontloader.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/components/fontloader/fontloader.cpp b/components/fontloader/fontloader.cpp index 0ca37ad11..eb7dd901d 100644 --- a/components/fontloader/fontloader.cpp +++ b/components/fontloader/fontloader.cpp @@ -20,12 +20,12 @@ namespace { size_t i = 0; unsigned long unicode; - size_t todo; + size_t numbytes; unsigned char ch = utf8[i++]; if (ch <= 0x7F) { unicode = ch; - todo = 0; + numbytes = 0; } else if (ch <= 0xBF) { @@ -34,23 +34,23 @@ namespace else if (ch <= 0xDF) { unicode = ch&0x1F; - todo = 1; + numbytes = 1; } else if (ch <= 0xEF) { unicode = ch&0x0F; - todo = 2; + numbytes = 2; } else if (ch <= 0xF7) { unicode = ch&0x07; - todo = 3; + numbytes = 3; } else { throw std::logic_error("not a UTF-8 string"); } - for (size_t j = 0; j < todo; ++j) + for (size_t j = 0; j < numbytes; ++j) { unsigned char ch = utf8[i++]; if (ch < 0x80 || ch > 0xBF) From 16ddfbca14fca5bdd86af78075e7c9154198aee3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Mar 2015 00:27:01 +0100 Subject: [PATCH 605/740] Remove some outdated todo comments --- components/to_utf8/to_utf8.cpp | 8 ++++---- libs/openengine/bullet/physic.hpp | 3 +-- libs/openengine/gui/manager.cpp | 1 - 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/components/to_utf8/to_utf8.cpp b/components/to_utf8/to_utf8.cpp index cb9680441..d7f9c3a38 100644 --- a/components/to_utf8/to_utf8.cpp +++ b/components/to_utf8/to_utf8.cpp @@ -84,11 +84,11 @@ std::string Utf8Encoder::getUtf8(const char* input, size_t size) // is also ok.) assert(input[size] == 0); - // TODO: The rest of this function is designed for single-character + // Note: The rest of this function is designed for single-character // input encodings only. It also assumes that the input the input - // encoding shares its first 128 values (0-127) with ASCII. These - // conditions must be checked again if you add more input encodings - // later. + // encoding shares its first 128 values (0-127) with ASCII. There are + // no plans to add more encodings to this module (we are using utf8 + // for new content files), so that shouldn't be an issue. // Compute output length, and check for pure ascii input at the same // time. diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 1a16ff4e8..7784e8941 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -258,13 +258,12 @@ namespace Physic const Ogre::Vector3 &position, float scale, const Ogre::Quaternion &rotation); /** - * Remove a character from the scene. TODO:delete it! for now, a small memory leak^^ done? + * Remove a character from the scene. */ void removeCharacter(const std::string &name); /** * Return a pointer to a character - * TODO:check if the actor exist... */ PhysicActor* getCharacter(const std::string &name); diff --git a/libs/openengine/gui/manager.cpp b/libs/openengine/gui/manager.cpp index 512c7f069..349647892 100644 --- a/libs/openengine/gui/manager.cpp +++ b/libs/openengine/gui/manager.cpp @@ -451,7 +451,6 @@ public: mRenderSystem->_setSceneBlending(Ogre::SBF_SOURCE_ALPHA, Ogre::SBF_ONE_MINUS_SOURCE_ALPHA); // always use wireframe - // TODO: add option to enable wireframe mode in platform mRenderSystem->_setPolygonMode(Ogre::PM_SOLID); } From 5f051b5bf2dda8e2e48827505218b2351ffe9b2b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Mar 2015 00:32:57 +0100 Subject: [PATCH 606/740] Remove comment about GMST cleaning which was removed. --- components/esm/loadgmst.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/loadgmst.hpp b/components/esm/loadgmst.hpp index 6b66ac832..398b8047f 100644 --- a/components/esm/loadgmst.hpp +++ b/components/esm/loadgmst.hpp @@ -12,7 +12,7 @@ class ESMReader; class ESMWriter; /* - * Game setting, with automatic cleaning of "dirty" entries. + * Game setting * */ From d00c75d428489819fa9d7229a719a27c5831ff1d Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Mar 2015 00:37:28 +0100 Subject: [PATCH 607/740] Remove more outdated TODO comments. --- apps/openmw/mwbase/world.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 56f575d3a..9e6c6d9bf 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -205,10 +205,8 @@ namespace MWBase ///< Return a pointer to a liveCellRef which contains \a ptr. /// \note Search is limited to the active cells. - /// \todo enable reference in the OGRE scene virtual void enable (const MWWorld::Ptr& ptr) = 0; - /// \todo disable reference in the OGRE scene virtual void disable (const MWWorld::Ptr& ptr) = 0; virtual void advanceTime (double hours) = 0; From 7fd1c2c2e27426dd735e64879b0a4bc34aa3c477 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Mar 2015 00:43:28 +0100 Subject: [PATCH 608/740] CharacterCreation refactoring --- apps/openmw/mwgui/charactercreation.cpp | 97 ++++++------------------- apps/openmw/mwgui/charactercreation.hpp | 2 + 2 files changed, 24 insertions(+), 75 deletions(-) diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index ab412f63b..fb00d6a98 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -330,20 +330,7 @@ namespace MWGui updatePlayerHealth(); - //TODO This bit gets repeated a few times; wrap it in a function - MWBase::Environment::get().getWindowManager()->popGuiMode(); - if (mCreationStage == CSE_ReviewNext) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else if (mCreationStage >= CSE_ClassChosen) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); - } - else - { - mCreationStage = CSE_ClassChosen; - } + handleDialogDone(CSE_ClassChosen, GM_Birth); } void CharacterCreation::onPickClassDialogBack() @@ -397,19 +384,7 @@ namespace MWGui mNameDialog = 0; } - MWBase::Environment::get().getWindowManager()->popGuiMode(); - if (mCreationStage == CSE_ReviewNext) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else if (mCreationStage >= CSE_NameChosen) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Race); - } - else - { - mCreationStage = CSE_NameChosen; - } + handleDialogDone(CSE_NameChosen, GM_Race); } void CharacterCreation::onRaceDialogBack() @@ -456,19 +431,7 @@ namespace MWGui updatePlayerHealth(); - MWBase::Environment::get().getWindowManager()->popGuiMode(); - if (mCreationStage == CSE_ReviewNext) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else if (mCreationStage >= CSE_RaceChosen) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); - } - else - { - mCreationStage = CSE_RaceChosen; - } + handleDialogDone(CSE_RaceChosen, GM_Class); } void CharacterCreation::onBirthSignDialogDone(WindowBase* parWindow) @@ -484,15 +447,7 @@ namespace MWGui updatePlayerHealth(); - MWBase::Environment::get().getWindowManager()->popGuiMode(); - if (mCreationStage >= CSE_BirthSignChosen) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else - { - mCreationStage = CSE_BirthSignChosen; - } + handleDialogDone(CSE_BirthSignChosen, GM_Review); } void CharacterCreation::onBirthSignDialogBack() @@ -543,19 +498,7 @@ namespace MWGui updatePlayerHealth(); - MWBase::Environment::get().getWindowManager()->popGuiMode(); - if (mCreationStage == CSE_ReviewNext) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else if (mCreationStage >= CSE_ClassChosen) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); - } - else - { - mCreationStage = CSE_ClassChosen; - } + handleDialogDone(CSE_ClassChosen, GM_Birth); } void CharacterCreation::onCreateClassDialogBack() @@ -711,19 +654,7 @@ namespace MWGui updatePlayerHealth(); - MWBase::Environment::get().getWindowManager()->popGuiMode(); - if (mCreationStage == CSE_ReviewNext) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else if (mCreationStage >= CSE_ClassChosen) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); - } - else - { - mCreationStage = CSE_ClassChosen; - } + handleDialogDone(CSE_ClassChosen, GM_Birth); } CharacterCreation::~CharacterCreation() @@ -739,4 +670,20 @@ namespace MWGui delete mReviewDialog; } + void CharacterCreation::handleDialogDone(CSE currentStage, int nextMode) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + if (mCreationStage == CSE_ReviewNext) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); + } + else if (mCreationStage >= currentStage) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode((GuiMode)nextMode); + } + else + { + mCreationStage = currentStage; + } + } } diff --git a/apps/openmw/mwgui/charactercreation.hpp b/apps/openmw/mwgui/charactercreation.hpp index c2486c7f0..a4515569d 100644 --- a/apps/openmw/mwgui/charactercreation.hpp +++ b/apps/openmw/mwgui/charactercreation.hpp @@ -104,6 +104,8 @@ namespace MWGui }; CSE mCreationStage; // Which state the character creating is in, controls back/next/ok buttons + + void handleDialogDone(CSE currentStage, int nextMode); }; } From f603a681445c653960adb76d1722b9af44a0db98 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Mar 2015 02:23:46 +0100 Subject: [PATCH 609/740] Allow binding Hand To Hand in quick keys menu (Fixes #2024) --- apps/openmw/mwgui/quickkeysmenu.cpp | 29 ++++++++++++++++++++++++----- apps/openmw/mwgui/quickkeysmenu.hpp | 5 +++-- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index a102de1e5..8f595df80 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -94,12 +94,24 @@ namespace MWGui while (key->getChildCount()) // Destroy number label MyGUI::Gui::getInstance().destroyWidget(key->getChildAt(0)); - mAssigned[index] = Type_Unassigned; + if (index == 9) + { + mAssigned[index] = Type_HandToHand; + + MyGUI::ImageBox* image = key->createWidget("ImageBox", + MyGUI::IntCoord(14, 13, 32, 32), MyGUI::Align::Default); + image->setImageTexture("icons\\k\\stealth_handtohand.dds"); + image->setNeedMouseFocus(false); + } + else + { + mAssigned[index] = Type_Unassigned; - MyGUI::TextBox* textBox = key->createWidgetReal("SandText", MyGUI::FloatCoord(0,0,1,1), MyGUI::Align::Default); - textBox->setTextAlign (MyGUI::Align::Center); - textBox->setCaption (MyGUI::utility::toString(index+1)); - textBox->setNeedMouseFocus (false); + MyGUI::TextBox* textBox = key->createWidgetReal("SandText", MyGUI::FloatCoord(0,0,1,1), MyGUI::Align::Default); + textBox->setTextAlign (MyGUI::Align::Center); + textBox->setCaption (MyGUI::utility::toString(index+1)); + textBox->setNeedMouseFocus (false); + } } void QuickKeysMenu::onQuickKeyButtonClicked(MyGUI::Widget* sender) @@ -338,6 +350,11 @@ namespace MWGui store.setSelectedEnchantItem(it); MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Spell); } + else if (type == Type_HandToHand) + { + store.unequipSlot(MWWorld::InventoryStore::Slot_CarriedRight, player); + MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Weapon); + } } // --------------------------------------------------------------------------------------------------------- @@ -409,6 +426,7 @@ namespace MWGui switch (type) { case Type_Unassigned: + case Type_HandToHand: break; case Type_Item: case Type_MagicItem: @@ -489,6 +507,7 @@ namespace MWGui break; } case Type_Unassigned: + case Type_HandToHand: unassign(button, i); break; } diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index 00afa4561..afbcff001 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -37,15 +37,16 @@ namespace MWGui void activateQuickKey(int index); + /// @note This enum is serialized, so don't move the items around! enum QuickKeyType { Type_Item, Type_Magic, Type_MagicItem, - Type_Unassigned + Type_Unassigned, + Type_HandToHand }; - void write (ESM::ESMWriter& writer); void readRecord (ESM::ESMReader& reader, uint32_t type); void clear(); From a846bb1aa3430c57dd3488df16f2a0dfb69bcb74 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Mar 2015 02:44:41 +0100 Subject: [PATCH 610/740] Update hit chance according to wiki and implement fCombatInvisoMult --- apps/openmw/mwmechanics/combat.cpp | 35 +++++++++++++++++++---- apps/openmw/mwmechanics/creaturestats.cpp | 2 +- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index b8ffa63e2..9d61b2eac 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -241,14 +241,39 @@ namespace MWMechanics { MWMechanics::CreatureStats &stats = attacker.getClass().getCreatureStats(attacker); const MWMechanics::MagicEffects &mageffects = stats.getMagicEffects(); - float hitchance = skillValue + + + MWBase::World *world = MWBase::Environment::get().getWorld(); + const MWWorld::Store &gmst = world->getStore().get(); + + float defenseTerm = 0; + if (victim.getClass().getCreatureStats(victim).getFatigue().getCurrent() >= 0) + { + MWMechanics::CreatureStats& victimStats = victim.getClass().getCreatureStats(victim); + // Maybe we should keep an aware state for actors updated every so often instead of testing every time + bool unaware = (!victimStats.getAiSequence().isInCombat()) + && (attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) + && (!MWBase::Environment::get().getMechanicsManager()->awarenessCheck(attacker, victim)); + if (!(victimStats.getKnockedDown() || + victimStats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0 + || unaware )) + { + defenseTerm = victimStats.getEvasion(); + } + defenseTerm += std::min(100.f, + gmst.find("fCombatInvisoMult")->getFloat() * + victimStats.getMagicEffects().get(ESM::MagicEffect::Chameleon).getMagnitude()); + defenseTerm += std::min(100.f, + gmst.find("fCombatInvisoMult")->getFloat() * + victimStats.getMagicEffects().get(ESM::MagicEffect::Invisibility).getMagnitude()); + } + float attackTerm = skillValue + (stats.getAttribute(ESM::Attribute::Agility).getModified() / 5.0f) + (stats.getAttribute(ESM::Attribute::Luck).getModified() / 10.0f); - hitchance *= stats.getFatigueTerm(); - hitchance += mageffects.get(ESM::MagicEffect::FortifyAttack).getMagnitude() - + attackTerm *= stats.getFatigueTerm(); + attackTerm += mageffects.get(ESM::MagicEffect::FortifyAttack).getMagnitude() - mageffects.get(ESM::MagicEffect::Blind).getMagnitude(); - hitchance -= victim.getClass().getCreatureStats(victim).getEvasion(); - return hitchance; + + return static_cast((attackTerm - defenseTerm) + 0.5f); } void applyElementalShields(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim) diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 931c2f14e..4c338e23f 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -336,7 +336,7 @@ namespace MWMechanics float evasion = (getAttribute(ESM::Attribute::Agility).getModified() / 5.0f) + (getAttribute(ESM::Attribute::Luck).getModified() / 10.0f); evasion *= getFatigueTerm(); - evasion += mMagicEffects.get(ESM::MagicEffect::Sanctuary).getMagnitude(); + evasion += std::min(100.f, mMagicEffects.get(ESM::MagicEffect::Sanctuary).getMagnitude()); return evasion; } From 767624f518108463b64816411da1f287b0489e09 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Mar 2015 03:08:58 +0100 Subject: [PATCH 611/740] Combat mechanic fixes --- apps/openmw/mwclass/creature.cpp | 6 ++---- apps/openmw/mwclass/npc.cpp | 8 ++------ apps/openmw/mwclass/npc.hpp | 2 -- apps/openmw/mwmechanics/combat.cpp | 27 ++++++++++++++------------- apps/openmw/mwmechanics/combat.hpp | 2 +- 5 files changed, 19 insertions(+), 26 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 9a3c6c218..908de02d8 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -249,7 +249,7 @@ namespace MWClass float hitchance = MWMechanics::getHitChance(ptr, victim, ref->mBase->mData.mCombat); - if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f) + if((::rand()/(RAND_MAX+1.0)) >= hitchance/100.0f) { victim.getClass().onHit(victim, 0.0f, false, MWWorld::Ptr(), ptr, false); MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr); @@ -288,9 +288,7 @@ namespace MWClass if(attack) { damage = attack[0] + ((attack[1]-attack[0])*stats.getAttackStrength()); - damage *= gmst.find("fDamageStrengthBase")->getFloat() + - (stats.getAttribute(ESM::Attribute::Strength).getModified() * gmst.find("fDamageStrengthMult")->getFloat() * 0.1f); - MWMechanics::adjustWeaponDamage(damage, weapon); + MWMechanics::adjustWeaponDamage(damage, weapon, ptr); MWMechanics::reduceWeaponCondition(damage, true, weapon, ptr); } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index deb4b90cd..ea506ff9e 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -279,8 +279,6 @@ namespace MWClass gmst.fKnockDownMult = store.find("fKnockDownMult"); gmst.iKnockDownOddsMult = store.find("iKnockDownOddsMult"); gmst.iKnockDownOddsBase = store.find("iKnockDownOddsBase"); - gmst.fDamageStrengthBase = store.find("fDamageStrengthBase"); - gmst.fDamageStrengthMult = store.find("fDamageStrengthMult"); gmst.fCombatArmorMinMult = store.find("fCombatArmorMinMult"); inited = true; @@ -516,7 +514,7 @@ namespace MWClass float hitchance = MWMechanics::getHitChance(ptr, victim, ptr.getClass().getSkill(ptr, weapskill)); - if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f) + if((::rand()/(RAND_MAX+1.0)) >= hitchance/100.0f) { othercls.onHit(victim, 0.0f, false, weapon, ptr, false); MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr); @@ -538,10 +536,8 @@ namespace MWClass if(attack) { damage = attack[0] + ((attack[1]-attack[0])*stats.getAttackStrength()); - damage *= gmst.fDamageStrengthBase->getFloat() + - (stats.getAttribute(ESM::Attribute::Strength).getModified() * gmst.fDamageStrengthMult->getFloat() * 0.1f); } - MWMechanics::adjustWeaponDamage(damage, weapon); + MWMechanics::adjustWeaponDamage(damage, weapon, ptr); MWMechanics::reduceWeaponCondition(damage, true, weapon, ptr); healthdmg = true; } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index c00665eb3..27beeb626 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -38,8 +38,6 @@ namespace MWClass const ESM::GameSetting *fKnockDownMult; const ESM::GameSetting *iKnockDownOddsMult; const ESM::GameSetting *iKnockDownOddsBase; - const ESM::GameSetting *fDamageStrengthBase; - const ESM::GameSetting *fDamageStrengthMult; const ESM::GameSetting *fCombatArmorMinMult; }; diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 9d61b2eac..fdb375846 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -186,29 +186,23 @@ namespace MWMechanics int skillValue = attacker.getClass().getSkill(attacker, weapon.getClass().getEquipmentSkill(weapon)); - if((::rand()/(RAND_MAX+1.0)) > getHitChance(attacker, victim, skillValue)/100.0f) + if((::rand()/(RAND_MAX+1.0)) >= getHitChance(attacker, victim, skillValue)/100.0f) { victim.getClass().onHit(victim, 0.0f, false, projectile, attacker, false); MWMechanics::reduceWeaponCondition(0.f, false, weapon, attacker); return; } - float fDamageStrengthBase = gmst.find("fDamageStrengthBase")->getFloat(); - float fDamageStrengthMult = gmst.find("fDamageStrengthMult")->getFloat(); const unsigned char* attack = weapon.get()->mBase->mData.mChop; float damage = attack[0] + ((attack[1]-attack[0])*attackerStats.getAttackStrength()); // Bow/crossbow damage - if (weapon != projectile) - { - // Arrow/bolt damage - attack = projectile.get()->mBase->mData.mChop; - damage += attack[0] + ((attack[1]-attack[0])*attackerStats.getAttackStrength()); - } - damage *= fDamageStrengthBase + - (attackerStats.getAttribute(ESM::Attribute::Strength).getModified() * fDamageStrengthMult * 0.1f); + // Arrow/bolt damage + // NB in case of thrown weapons, we are applying the damage twice since projectile == weapon + attack = projectile.get()->mBase->mData.mChop; + damage += attack[0] + ((attack[1]-attack[0])*attackerStats.getAttackStrength()); - adjustWeaponDamage(damage, weapon); + adjustWeaponDamage(damage, weapon, attacker); reduceWeaponCondition(damage, true, weapon, attacker); if(attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) @@ -347,7 +341,7 @@ namespace MWMechanics } } - void adjustWeaponDamage(float &damage, const MWWorld::Ptr &weapon) + void adjustWeaponDamage(float &damage, const MWWorld::Ptr &weapon, const MWWorld::Ptr& attacker) { if (weapon.isEmpty()) return; @@ -359,6 +353,13 @@ namespace MWMechanics int weapmaxhealth = weapon.getClass().getItemMaxHealth(weapon); damage *= (float(weaphealth) / weapmaxhealth); } + + static const float fDamageStrengthBase = MWBase::Environment::get().getWorld()->getStore().get() + .find("fDamageStrengthBase")->getFloat(); + static const float fDamageStrengthMult = MWBase::Environment::get().getWorld()->getStore().get() + .find("fDamageStrengthMult")->getFloat(); + damage *= fDamageStrengthBase + + (attacker.getClass().getCreatureStats(attacker).getAttribute(ESM::Attribute::Strength).getModified() * fDamageStrengthMult * 0.1f); } void getHandToHandDamage(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim, float &damage, bool &healthdmg) diff --git a/apps/openmw/mwmechanics/combat.hpp b/apps/openmw/mwmechanics/combat.hpp index a48dcf72a..a2fd8b006 100644 --- a/apps/openmw/mwmechanics/combat.hpp +++ b/apps/openmw/mwmechanics/combat.hpp @@ -30,7 +30,7 @@ void applyElementalShields(const MWWorld::Ptr& attacker, const MWWorld::Ptr& vic void reduceWeaponCondition (float damage, bool hit, MWWorld::Ptr& weapon, const MWWorld::Ptr& attacker); /// Adjust weapon damage based on its condition. A used weapon will be less effective. -void adjustWeaponDamage (float& damage, const MWWorld::Ptr& weapon); +void adjustWeaponDamage (float& damage, const MWWorld::Ptr& weapon, const MWWorld::Ptr& attacker); void getHandToHandDamage (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, float& damage, bool& healthdmg); From 418025e0a29394c87501ae64e6993d03c114b05b Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 12 Mar 2015 13:10:25 +1100 Subject: [PATCH 612/740] Add missing editor type to the dialogue. Should resolve Bug #2437. --- apps/opencs/view/world/dialoguesubview.cpp | 7 ++++++- apps/opencs/view/world/util.cpp | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 8790601ea..48009da8d 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -266,6 +267,8 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: editor = delegateIt->second->createEditor(qobject_cast(mParent), QStyleOptionViewItem(), index, display); DialogueDelegateDispatcherProxy* proxy = new DialogueDelegateDispatcherProxy(editor, display); + // NOTE: For each entry in CSVWorld::CommandDelegate::createEditor() a corresponding entry + // is required here if (qobject_cast(editor)) { connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited())); @@ -286,10 +289,12 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: { connect(editor, SIGNAL(currentIndexChanged (int)), proxy, SLOT(editorDataCommited())); } - else if (qobject_cast(editor)) + else if (qobject_cast(editor) || qobject_cast(editor)) { connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited())); } + else // throw an exception because this is a coding error + throw std::logic_error ("Dialogue editor type missing"); connect(proxy, SIGNAL(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display)), this, SLOT(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display))); mProxys.push_back(proxy); //deleted in the destructor diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index c65e12c60..91460c3df 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -152,6 +152,8 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO } } + // NOTE: for each editor type (e.g. QLineEdit) there needs to be a corresponding + // entry in CSVWorld::DialogueDelegateDispatcher::makeEditor() switch (display) { case CSMWorld::ColumnBase::Display_Colour: From 8e37e9a14af3cc03176d53f662c47741345b0a52 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 12 Mar 2015 10:51:50 +0100 Subject: [PATCH 613/740] removed redundant functions --- apps/opencs/model/world/record.hpp | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp index 6ff33f0c2..3362f9f96 100644 --- a/apps/opencs/model/world/record.hpp +++ b/apps/opencs/model/world/record.hpp @@ -41,8 +41,6 @@ namespace CSMWorld ESXRecordT mModified; Record(); - Record(const Record& record); - Record& operator= (const Record& record); Record(State state, const ESXRecordT *base = 0, const ESXRecordT *modified = 0); @@ -74,26 +72,6 @@ namespace CSMWorld : mBase(), mModified() { } - template - Record::Record(const Record& record) - : mBase(record.mBase), mModified(record.mModified) - { - mState = record.mState; - } - - template - Record& Record::operator= (const Record& record) - { - if(this != &record) - { - mBase = record.mBase; - mModified = record.mModified; - mState = record.mState; - } - - return *this; - } - template Record::Record(State state, const ESXRecordT *base, const ESXRecordT *modified) { From d10f073bf8f51973b8ff914e9022397820da78f3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 12 Mar 2015 12:05:36 +0100 Subject: [PATCH 614/740] updated changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bbee6fe0..1766aa21d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ Bug #2334: Drag-and-drop on a content file in the launcher creates duplicate items Bug #2338: Arrows reclaimed from corpses do not stack sometimes Bug #2344: Launcher - Settings importer running correctly? + Bug #2346: Launcher - Importing plugins into content list screws up the load order Bug #2348: Mod: H.E.L.L.U.V.A. Handy Holdables does not appear in the content list Bug #2353: Detect Animal detects dead creatures Bug #2354: Cmake does not respect LIB_SUFFIX From 589b0b91713888ab0364841d6d0e712e080d2785 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 13 Mar 2015 08:01:48 +1100 Subject: [PATCH 615/740] Add saving land and land textures. Should resolve Bug #2447. --- apps/opencs/model/doc/saving.cpp | 4 ++ apps/opencs/model/doc/savingstages.cpp | 66 ++++++++++++++++++++++++++ apps/opencs/model/doc/savingstages.hpp | 34 +++++++++++++ 3 files changed, 104 insertions(+) diff --git a/apps/opencs/model/doc/saving.cpp b/apps/opencs/model/doc/saving.cpp index 04d61ed1b..9f6e469b8 100644 --- a/apps/opencs/model/doc/saving.cpp +++ b/apps/opencs/model/doc/saving.cpp @@ -93,6 +93,10 @@ CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& proje appendStage (new WritePathgridCollectionStage (mDocument, mState)); + appendStage (new WriteLandCollectionStage (mDocument, mState)); + + appendStage (new WriteLandTextureCollectionStage (mDocument, mState)); + // close file and clean up appendStage (new CloseSaveStage (mState)); diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index 08f8c9eaa..11aa8a7d1 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -353,6 +353,72 @@ void CSMDoc::WritePathgridCollectionStage::perform (int stage, Messages& message } +CSMDoc::WriteLandCollectionStage::WriteLandCollectionStage (Document& document, + SavingState& state) +: mDocument (document), mState (state) +{} + +int CSMDoc::WriteLandCollectionStage::setup() +{ + return mDocument.getData().getLand().getSize(); +} + +void CSMDoc::WriteLandCollectionStage::perform (int stage, Messages& messages) +{ + const CSMWorld::Record& land = + mDocument.getData().getLand().getRecord (stage); + + if (land.mState==CSMWorld::RecordBase::State_Modified || + land.mState==CSMWorld::RecordBase::State_ModifiedOnly) + { + CSMWorld::Land record = land.get(); + + mState.getWriter().startRecord (record.mLand->sRecordId); + + record.mLand->save (mState.getWriter()); + + mState.getWriter().endRecord (record.mLand->sRecordId); + } + else if (land.mState==CSMWorld::RecordBase::State_Deleted) + { + /// \todo write record with delete flag + } +} + + +CSMDoc::WriteLandTextureCollectionStage::WriteLandTextureCollectionStage (Document& document, + SavingState& state) +: mDocument (document), mState (state) +{} + +int CSMDoc::WriteLandTextureCollectionStage::setup() +{ + return mDocument.getData().getLandTextures().getSize(); +} + +void CSMDoc::WriteLandTextureCollectionStage::perform (int stage, Messages& messages) +{ + const CSMWorld::Record& landTexture = + mDocument.getData().getLandTextures().getRecord (stage); + + if (landTexture.mState==CSMWorld::RecordBase::State_Modified || + landTexture.mState==CSMWorld::RecordBase::State_ModifiedOnly) + { + CSMWorld::LandTexture record = landTexture.get(); + + mState.getWriter().startRecord (record.sRecordId); + + record.save (mState.getWriter()); + + mState.getWriter().endRecord (record.sRecordId); + } + else if (landTexture.mState==CSMWorld::RecordBase::State_Deleted) + { + /// \todo write record with delete flag + } +} + + CSMDoc::CloseSaveStage::CloseSaveStage (SavingState& state) : mState (state) {} diff --git a/apps/opencs/model/doc/savingstages.hpp b/apps/opencs/model/doc/savingstages.hpp index 907041114..4b16581dc 100644 --- a/apps/opencs/model/doc/savingstages.hpp +++ b/apps/opencs/model/doc/savingstages.hpp @@ -209,6 +209,40 @@ namespace CSMDoc ///< Messages resulting from this stage will be appended to \a messages. }; + + class WriteLandCollectionStage : public Stage + { + Document& mDocument; + SavingState& mState; + + public: + + WriteLandCollectionStage (Document& document, SavingState& state); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; + + + class WriteLandTextureCollectionStage : public Stage + { + Document& mDocument; + SavingState& mState; + + public: + + WriteLandTextureCollectionStage (Document& document, SavingState& state); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; + class CloseSaveStage : public Stage { SavingState& mState; From 488bc76da5b33f8ac935a946134d7c24f77e8841 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 13 Mar 2015 22:06:55 +1100 Subject: [PATCH 616/740] Fix saving land data. --- apps/opencs/model/doc/savingstages.cpp | 2 ++ apps/opencs/model/world/data.cpp | 2 +- components/esm/loadland.cpp | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index 11aa8a7d1..485ad094b 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -376,6 +376,8 @@ void CSMDoc::WriteLandCollectionStage::perform (int stage, Messages& messages) mState.getWriter().startRecord (record.mLand->sRecordId); record.mLand->save (mState.getWriter()); + if(record.mLand->mLandData) + record.mLand->mLandData->save (mState.getWriter()); mState.getWriter().endRecord (record.mLand->sRecordId); } diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 313518091..39cff3db6 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -745,7 +745,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) if (index!=-1 && !mBase) mLand.getRecord (index).mModified.mLand->loadData ( ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR | - ESM::Land::DATA_VTEX); + ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM); break; } diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index ae73eee52..b1c01fcba 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -11,7 +11,7 @@ namespace ESM void Land::LandData::save(ESMWriter &esm) { if (mDataTypes & Land::DATA_VNML) { - esm.writeHNT("VNML", mNormals, sizeof(VNML)); + esm.writeHNT("VNML", mNormals, sizeof(mNormals)); } if (mDataTypes & Land::DATA_VHGT) { VHGT offsets; From 4d46d7ba72b261d3eb5aab6762702e44543bbe73 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 14 Mar 2015 06:07:12 +1100 Subject: [PATCH 617/740] Fix some compiler warnings. --- apps/openmw/mwworld/store.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index a887272c5..56f16377b 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -29,7 +29,7 @@ namespace MWWorld virtual bool eraseStatic(const std::string &id) {return false;} virtual void clearDynamic() {} - virtual void write (ESM::ESMWriter& writer) const {} + virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const {} virtual void read (ESM::ESMReader& reader, const std::string& id) {} ///< Read into dynamic storage @@ -234,7 +234,7 @@ namespace MWWorld int getDynamicSize() const { - return mDynamic.size(); + return static_cast (mDynamic.size()); // truncated from unsigned __int64 if _MSC_VER && _WIN64 } void listIdentifier(std::vector &list) const { From 4f6c772437228dda02de2ef62d8f36aa4ff707b4 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 14 Mar 2015 06:36:35 +1100 Subject: [PATCH 618/740] Fix more warnings. --- apps/opencs/model/world/refcollection.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/refcollection.hpp b/apps/opencs/model/world/refcollection.hpp index 4ecc32b2f..46572752e 100644 --- a/apps/opencs/model/world/refcollection.hpp +++ b/apps/opencs/model/world/refcollection.hpp @@ -12,7 +12,7 @@ namespace CSMWorld { struct Cell; - struct UniversalId; + class UniversalId; /// \brief References in cells class RefCollection : public Collection From fd86076db3608ca6d7d3533bf2ab51ec651d308f Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 14 Mar 2015 08:09:19 +1100 Subject: [PATCH 619/740] More warning fixes. --- apps/opencs/model/doc/document.hpp | 2 +- apps/opencs/model/doc/documentmanager.hpp | 6 +++--- apps/opencs/model/doc/savingstages.cpp | 2 +- apps/opencs/model/doc/savingstages.hpp | 1 - apps/opencs/model/world/infocollection.cpp | 6 +++--- apps/opencs/model/world/infocollection.hpp | 4 ++-- apps/opencs/model/world/ref.hpp | 2 -- 7 files changed, 10 insertions(+), 13 deletions(-) diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index f3aef6db6..19866c18d 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -32,7 +32,7 @@ namespace ESM namespace Files { - class ConfigurationManager; + struct ConfigurationManager; } namespace CSMWorld diff --git a/apps/opencs/model/doc/documentmanager.hpp b/apps/opencs/model/doc/documentmanager.hpp index 3202c4fe1..0ae73e70c 100644 --- a/apps/opencs/model/doc/documentmanager.hpp +++ b/apps/opencs/model/doc/documentmanager.hpp @@ -17,7 +17,7 @@ namespace Files { - class ConfigurationManager; + struct ConfigurationManager; } namespace CSMDoc @@ -50,7 +50,7 @@ namespace CSMDoc ///< \param new_ Do not load the last content file in \a files and instead create in an /// appropriate way. - void setResourceDir (const boost::filesystem::path& parResDir); + void setResourceDir (const boost::filesystem::path& parResDir); void setEncoding (ToUTF8::FromType encoding); @@ -61,7 +61,7 @@ namespace CSMDoc private: - boost::filesystem::path mResDir; + boost::filesystem::path mResDir; private slots: diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index 485ad094b..ef7d1d3af 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -90,7 +90,7 @@ void CSMDoc::WriteHeaderStage::perform (int stage, Messages& messages) CSMDoc::WriteDialogueCollectionStage::WriteDialogueCollectionStage (Document& document, SavingState& state, bool journal) -: mDocument (document), mState (state), +: mState (state), mTopics (journal ? document.getData().getJournals() : document.getData().getTopics()), mInfos (journal ? document.getData().getJournalInfos() : document.getData().getTopicInfos()) {} diff --git a/apps/opencs/model/doc/savingstages.hpp b/apps/opencs/model/doc/savingstages.hpp index 4b16581dc..188f22f96 100644 --- a/apps/opencs/model/doc/savingstages.hpp +++ b/apps/opencs/model/doc/savingstages.hpp @@ -126,7 +126,6 @@ namespace CSMDoc class WriteDialogueCollectionStage : public Stage { - Document& mDocument; SavingState& mState; const CSMWorld::IdCollection& mTopics; CSMWorld::InfoCollection& mInfos; diff --git a/apps/opencs/model/world/infocollection.cpp b/apps/opencs/model/world/infocollection.cpp index 50d09f313..f2d81823c 100644 --- a/apps/opencs/model/world/infocollection.cpp +++ b/apps/opencs/model/world/infocollection.cpp @@ -26,7 +26,7 @@ void CSMWorld::InfoCollection::load (const Info& record, bool base) if (!record2.get().mPrev.empty()) { - index = getIndex (record2.get().mPrev, topic); + index = getInfoIndex (record2.get().mPrev, topic); if (index!=-1) ++index; @@ -34,7 +34,7 @@ void CSMWorld::InfoCollection::load (const Info& record, bool base) if (index==-1 && !record2.get().mNext.empty()) { - index = getIndex (record2.get().mNext, topic); + index = getInfoIndex (record2.get().mNext, topic); } if (index==-1) @@ -60,7 +60,7 @@ void CSMWorld::InfoCollection::load (const Info& record, bool base) } } -int CSMWorld::InfoCollection::getIndex (const std::string& id, const std::string& topic) const +int CSMWorld::InfoCollection::getInfoIndex (const std::string& id, const std::string& topic) const { std::string fullId = Misc::StringUtils::lowerCase (topic) + "#" + id; diff --git a/apps/opencs/model/world/infocollection.hpp b/apps/opencs/model/world/infocollection.hpp index e953effa8..6db47373d 100644 --- a/apps/opencs/model/world/infocollection.hpp +++ b/apps/opencs/model/world/infocollection.hpp @@ -6,7 +6,7 @@ namespace ESM { - class Dialogue; + struct Dialogue; } namespace CSMWorld @@ -22,7 +22,7 @@ namespace CSMWorld void load (const Info& record, bool base); - int getIndex (const std::string& id, const std::string& topic) const; + int getInfoIndex (const std::string& id, const std::string& topic) const; ///< Return index for record \a id or -1 (if not present; deleted records are considered) /// /// \param id info ID without topic prefix diff --git a/apps/opencs/model/world/ref.hpp b/apps/opencs/model/world/ref.hpp index eb62434cf..8ab901a6f 100644 --- a/apps/opencs/model/world/ref.hpp +++ b/apps/opencs/model/world/ref.hpp @@ -5,8 +5,6 @@ namespace CSMWorld { - class Cell; - /// \brief Wrapper for CellRef sub record struct CellRef : public ESM::CellRef { From 2540a901d5387d1fbef7fbc6bb19692b7a45b987 Mon Sep 17 00:00:00 2001 From: Rohit Nirmal Date: Fri, 13 Mar 2015 20:04:47 -0500 Subject: [PATCH 620/740] Remove unused variable. --- apps/openmw/mwclass/npc.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index ea506ff9e..d5055fcb2 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -473,7 +473,6 @@ namespace MWClass void Npc::hit(const MWWorld::Ptr& ptr, int type) const { MWBase::World *world = MWBase::Environment::get().getWorld(); - const GMST& gmst = getGmst(); const MWWorld::Store &store = world->getStore().get(); From 17e6244bd6ac594346b0cb23dd6fea62bc9ff7a2 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 14 Mar 2015 12:42:46 +1100 Subject: [PATCH 621/740] Yet more warnings suppressed. --- apps/opencs/model/world/commands.hpp | 2 +- apps/opencs/model/world/idtable.hpp | 2 +- apps/opencs/model/world/refidadapter.hpp | 2 +- apps/opencs/view/render/object.hpp | 2 +- apps/opencs/view/tools/reporttable.cpp | 2 +- apps/opencs/view/world/dialoguesubview.cpp | 25 +++++++++++++++------- apps/opencs/view/world/dialoguesubview.hpp | 9 ++++---- apps/opencs/view/world/dragrecordtable.cpp | 2 +- apps/opencs/view/world/dragrecordtable.hpp | 2 +- apps/opencs/view/world/enumdelegate.cpp | 1 - apps/opencs/view/world/regionmap.cpp | 4 ++-- apps/opencs/view/world/table.cpp | 2 +- apps/opencs/view/world/util.cpp | 11 ++++++++++ apps/opencs/view/world/util.hpp | 9 ++++++-- 14 files changed, 50 insertions(+), 25 deletions(-) diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index 7267c9c8b..3c24b64a5 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -20,7 +20,7 @@ namespace CSMWorld { class IdTable; class IdTable; - class RecordBase; + struct RecordBase; class ModifyCommand : public QUndoCommand { diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index 707d7133b..ea8ab80f9 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -10,7 +10,7 @@ namespace CSMWorld { class CollectionBase; - class RecordBase; + struct RecordBase; class IdTable : public IdTableBase { diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index 3320af190..74c5dfe58 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -9,7 +9,7 @@ namespace CSMWorld { class RefIdColumn; class RefIdData; - class RecordBase; + struct RecordBase; class RefIdAdapter { diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index 3ed4fa793..c5a2b73c2 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -17,7 +17,7 @@ namespace Ogre namespace CSMWorld { class Data; - class CellRef; + struct CellRef; } namespace CSVWorld diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index da15b4acc..da39c1983 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -30,7 +30,7 @@ void CSVTools::ReportTable::contextMenuEvent (QContextMenuEvent *event) void CSVTools::ReportTable::mouseMoveEvent (QMouseEvent *event) { if (event->buttons() & Qt::LeftButton) - startDrag (*this); + startDragToTable (*this); } void CSVTools::ReportTable::mouseDoubleClickEvent (QMouseEvent *event) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 48009da8d..e383f5e9a 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -40,8 +40,12 @@ QAbstractItemDelegate(parent), mTable(table) {} -void CSVWorld::NotEditableSubDelegate::setEditorData (QLabel* editor, const QModelIndex& index) const +void CSVWorld::NotEditableSubDelegate::setEditorData (QWidget* editor, const QModelIndex& index) const { + QLabel* label = qobject_cast(editor); + if(!label) + return; + QVariant v = index.data(Qt::EditRole); if (!v.isValid()) { @@ -54,16 +58,17 @@ void CSVWorld::NotEditableSubDelegate::setEditorData (QLabel* editor, const QMod if (QVariant::String == v.type()) { - editor->setText(v.toString()); - } else //else we are facing enums + label->setText(v.toString()); + } + else //else we are facing enums { int data = v.toInt(); std::vector enumNames (CSMWorld::Columns::getEnums (static_cast (mTable->getColumnId (index.column())))); - editor->setText(QString::fromUtf8(enumNames.at(data).c_str())); + label->setText(QString::fromUtf8(enumNames.at(data).c_str())); } } -void CSVWorld::NotEditableSubDelegate::setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const +void CSVWorld::NotEditableSubDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const { //not editable widgets will not save model data } @@ -80,8 +85,7 @@ QSize CSVWorld::NotEditableSubDelegate::sizeHint (const QStyleOptionViewItem& op QWidget* CSVWorld::NotEditableSubDelegate::createEditor (QWidget *parent, const QStyleOptionViewItem& option, - const QModelIndex& index, - CSMWorld::ColumnBase::Display display) const + const QModelIndex& index) const { return new QLabel(parent); } @@ -224,6 +228,11 @@ void CSVWorld::DialogueDelegateDispatcher::setEditorData (QWidget* editor, const } } +void CSVWorld::DialogueDelegateDispatcher::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const +{ + setModelData(editor, model, index, CSMWorld::ColumnBase::Display_None); +} + void CSVWorld::DialogueDelegateDispatcher::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const { std::map::const_iterator delegateIt(mDelegates.find(display)); @@ -258,7 +267,7 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: QWidget* editor = NULL; if (! (mTable->flags (index) & Qt::ItemIsEditable)) { - return mNotEditableDelegate.createEditor(qobject_cast(mParent), QStyleOptionViewItem(), index, display); + return mNotEditableDelegate.createEditor(qobject_cast(mParent), QStyleOptionViewItem(), index); } std::map::iterator delegateIt(mDelegates.find(display)); diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 5de2c3ad2..5bd226960 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -40,9 +40,9 @@ namespace CSVWorld public: NotEditableSubDelegate(const CSMWorld::IdTable* table, QObject * parent = 0); - virtual void setEditorData (QLabel* editor, const QModelIndex& index) const; + virtual void setEditorData (QWidget* editor, const QModelIndex& index) const; - virtual void setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const; + virtual void setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const; virtual void paint (QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; ///< does nothing @@ -52,8 +52,7 @@ namespace CSVWorld virtual QWidget *createEditor (QWidget *parent, const QStyleOptionViewItem& option, - const QModelIndex& index, - CSMWorld::ColumnBase::Display display = CSMWorld::ColumnBase::Display_None) const; + const QModelIndex& index) const; }; //this can't be nested into the DialogueDelegateDispatcher, because it needs to emit signals @@ -119,6 +118,8 @@ namespace CSVWorld virtual void setEditorData (QWidget* editor, const QModelIndex& index) const; + virtual void setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const; + virtual void setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const; virtual void paint (QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; diff --git a/apps/opencs/view/world/dragrecordtable.cpp b/apps/opencs/view/world/dragrecordtable.cpp index c33fa58ad..f9cc4b530 100644 --- a/apps/opencs/view/world/dragrecordtable.cpp +++ b/apps/opencs/view/world/dragrecordtable.cpp @@ -3,7 +3,7 @@ #include "../../model/world/tablemimedata.hpp" #include "dragrecordtable.hpp" -void CSVWorld::DragRecordTable::startDrag (const CSVWorld::DragRecordTable& table) +void CSVWorld::DragRecordTable::startDragToTable (const CSVWorld::DragRecordTable& table) { CSMWorld::TableMimeData* mime = new CSMWorld::TableMimeData (table.getDraggedRecords(), mDocument); diff --git a/apps/opencs/view/world/dragrecordtable.hpp b/apps/opencs/view/world/dragrecordtable.hpp index 8c5f1b841..5b7e68490 100644 --- a/apps/opencs/view/world/dragrecordtable.hpp +++ b/apps/opencs/view/world/dragrecordtable.hpp @@ -33,7 +33,7 @@ namespace CSVWorld void setEditLock(bool locked); protected: - void startDrag(const DragRecordTable& table); + void startDragToTable(const DragRecordTable& table); void dragEnterEvent(QDragEnterEvent *event); diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp index 168e5cb0a..7c305b1b6 100644 --- a/apps/opencs/view/world/enumdelegate.cpp +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -46,7 +46,6 @@ QWidget *CSVWorld::EnumDelegate::createEditor(QWidget *parent, const QModelIndex& index) const { return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_None); - //overloading virtual functions is HARD } QWidget *CSVWorld::EnumDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem& option, diff --git a/apps/opencs/view/world/regionmap.cpp b/apps/opencs/view/world/regionmap.cpp index 9497e4054..316c61a88 100644 --- a/apps/opencs/view/world/regionmap.cpp +++ b/apps/opencs/view/world/regionmap.cpp @@ -345,7 +345,7 @@ void CSVWorld::RegionMap::viewInTable() void CSVWorld::RegionMap::mouseMoveEvent (QMouseEvent* event) { - startDrag(*this); + startDragToTable(*this); } std::vector< CSMWorld::UniversalId > CSVWorld::RegionMap::getDraggedRecords() const @@ -400,7 +400,7 @@ void CSVWorld::RegionMap::dropEvent (QDropEvent* event) QModelIndex index2(cellsModel->getModelIndex (cellId, cellsModel->findColumnIndex (CSMWorld::Columns::ColumnId_Region))); - mDocument.getUndoStack().push(new CSMWorld::ModifyCommand + mDocument.getUndoStack().push(new CSMWorld::ModifyCommand (*cellsModel, index2, QString::fromUtf8(record.getId().c_str()))); mRegionId = record.getId(); diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index e864e4ed2..7b8b97bc8 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -635,7 +635,7 @@ void CSVWorld::Table::mouseMoveEvent (QMouseEvent* event) { if (event->buttons() & Qt::LeftButton) { - startDrag(*this); + startDragToTable(*this); } } diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index 91460c3df..b0f8a035a 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -139,6 +139,12 @@ void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemMode ///< \todo provide some kind of feedback to the user, indicating that editing is currently not possible. } +QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleOptionViewItem& option, + const QModelIndex& index) const +{ + return createEditor (parent, option, index, CSMWorld::ColumnBase::Display_None); +} + QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleOptionViewItem& option, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const { @@ -230,6 +236,11 @@ bool CSVWorld::CommandDelegate::isEditLocked() const return mEditLock; } +void CSVWorld::CommandDelegate::setEditorData (QWidget *editor, const QModelIndex& index) const +{ + setEditorData (editor, index, false); +} + void CSVWorld::CommandDelegate::setEditorData (QWidget *editor, const QModelIndex& index, bool tryDisplay) const { QVariant v = index.data(Qt::EditRole); diff --git a/apps/opencs/view/world/util.hpp b/apps/opencs/view/world/util.hpp index b4d972bf3..10011798d 100644 --- a/apps/opencs/view/world/util.hpp +++ b/apps/opencs/view/world/util.hpp @@ -130,10 +130,14 @@ namespace CSVWorld virtual void setModelData (QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const; + virtual QWidget *createEditor (QWidget *parent, + const QStyleOptionViewItem& option, + const QModelIndex& index) const; + virtual QWidget *createEditor (QWidget *parent, const QStyleOptionViewItem& option, const QModelIndex& index, - CSMWorld::ColumnBase::Display display = CSMWorld::ColumnBase::Display_None) const; + CSMWorld::ColumnBase::Display display) const; void setEditLock (bool locked); @@ -141,8 +145,9 @@ namespace CSVWorld ///< \return Does column require update? - virtual void setEditorData (QWidget *editor, const QModelIndex& index, bool tryDisplay = false) const; + virtual void setEditorData (QWidget *editor, const QModelIndex& index) const; + virtual void setEditorData (QWidget *editor, const QModelIndex& index, bool tryDisplay) const; public slots: From 15b9a628ac4729258d1ad93a94aae0a1e4889961 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 14 Mar 2015 19:41:55 +1100 Subject: [PATCH 622/740] Fix the name of DragRecordTable::startDrag method. Make the compiler be quiet about BulletShapeLoader's hidden overloaded methods. --- apps/opencs/view/tools/reporttable.cpp | 2 +- apps/opencs/view/world/dragrecordtable.cpp | 2 +- apps/opencs/view/world/dragrecordtable.hpp | 2 +- apps/opencs/view/world/regionmap.cpp | 2 +- apps/opencs/view/world/table.cpp | 2 +- libs/openengine/bullet/BulletShapeLoader.cpp | 7 +++++++ libs/openengine/bullet/BulletShapeLoader.h | 8 +++++++- libs/openengine/bullet/physic.cpp | 2 +- 8 files changed, 20 insertions(+), 7 deletions(-) diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index da39c1983..809a39fa4 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -30,7 +30,7 @@ void CSVTools::ReportTable::contextMenuEvent (QContextMenuEvent *event) void CSVTools::ReportTable::mouseMoveEvent (QMouseEvent *event) { if (event->buttons() & Qt::LeftButton) - startDragToTable (*this); + startDragFromTable (*this); } void CSVTools::ReportTable::mouseDoubleClickEvent (QMouseEvent *event) diff --git a/apps/opencs/view/world/dragrecordtable.cpp b/apps/opencs/view/world/dragrecordtable.cpp index f9cc4b530..f45c45809 100644 --- a/apps/opencs/view/world/dragrecordtable.cpp +++ b/apps/opencs/view/world/dragrecordtable.cpp @@ -3,7 +3,7 @@ #include "../../model/world/tablemimedata.hpp" #include "dragrecordtable.hpp" -void CSVWorld::DragRecordTable::startDragToTable (const CSVWorld::DragRecordTable& table) +void CSVWorld::DragRecordTable::startDragFromTable (const CSVWorld::DragRecordTable& table) { CSMWorld::TableMimeData* mime = new CSMWorld::TableMimeData (table.getDraggedRecords(), mDocument); diff --git a/apps/opencs/view/world/dragrecordtable.hpp b/apps/opencs/view/world/dragrecordtable.hpp index 5b7e68490..4996c03ac 100644 --- a/apps/opencs/view/world/dragrecordtable.hpp +++ b/apps/opencs/view/world/dragrecordtable.hpp @@ -33,7 +33,7 @@ namespace CSVWorld void setEditLock(bool locked); protected: - void startDragToTable(const DragRecordTable& table); + void startDragFromTable(const DragRecordTable& table); void dragEnterEvent(QDragEnterEvent *event); diff --git a/apps/opencs/view/world/regionmap.cpp b/apps/opencs/view/world/regionmap.cpp index 316c61a88..bc96b0952 100644 --- a/apps/opencs/view/world/regionmap.cpp +++ b/apps/opencs/view/world/regionmap.cpp @@ -345,7 +345,7 @@ void CSVWorld::RegionMap::viewInTable() void CSVWorld::RegionMap::mouseMoveEvent (QMouseEvent* event) { - startDragToTable(*this); + startDragFromTable(*this); } std::vector< CSMWorld::UniversalId > CSVWorld::RegionMap::getDraggedRecords() const diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 7b8b97bc8..97a3bc2e3 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -635,7 +635,7 @@ void CSVWorld::Table::mouseMoveEvent (QMouseEvent* event) { if (event->buttons() & Qt::LeftButton) { - startDragToTable(*this); + startDragFromTable(*this); } } diff --git a/libs/openengine/bullet/BulletShapeLoader.cpp b/libs/openengine/bullet/BulletShapeLoader.cpp index fd9204b44..92d56b42c 100644 --- a/libs/openengine/bullet/BulletShapeLoader.cpp +++ b/libs/openengine/bullet/BulletShapeLoader.cpp @@ -117,6 +117,13 @@ BulletShapePtr BulletShapeManager::create (const Ogre::String& name, const Ogre: return createResource(name,group,isManual,loader,createParams).staticCast(); } +Ogre::ResourcePtr BulletShapeManager::load(const Ogre::String &name, const Ogre::String &group, + bool isManual, Ogre::ManualResourceLoader *loader, const Ogre::NameValuePairList *loadParams, + bool backgroundThread) +{ + return this->load(name, group); +} + BulletShapePtr BulletShapeManager::load(const Ogre::String &name, const Ogre::String &group) { BulletShapePtr textf = getByName(name); diff --git a/libs/openengine/bullet/BulletShapeLoader.h b/libs/openengine/bullet/BulletShapeLoader.h index 31ee3cc7d..907ff8bfe 100644 --- a/libs/openengine/bullet/BulletShapeLoader.h +++ b/libs/openengine/bullet/BulletShapeLoader.h @@ -92,6 +92,11 @@ private: /** \brief Private operator= . This is a forbidden operation. */ BulletShapeManager& operator=(const BulletShapeManager &); + // Not intended to be used, declared here to keep the compiler from complaining + // about hidden virtual methods. + virtual Ogre::ResourcePtr load(const Ogre::String &name, const Ogre::String &group, + bool isManual, Ogre::ManualResourceLoader *loader, const Ogre::NameValuePairList *loadParams, + bool backgroundThread); public: @@ -101,7 +106,8 @@ public: /// Get a resource by name /// @see ResourceManager::getByName - BulletShapePtr getByName(const Ogre::String& name, const Ogre::String& groupName = Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME); + BulletShapePtr getByName(const Ogre::String& name, + const Ogre::String& groupName = Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME); /// Create a new shape /// @see ResourceManager::createResource diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 81a2eb043..013ef1003 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -828,7 +828,7 @@ namespace Physic if (callback.hasHit()) return std::make_pair(true, callback.m_closestHitFraction); else - return std::make_pair(false, 1); + return std::make_pair(false, 1.0f); } std::vector< std::pair > PhysicEngine::rayTest2(const btVector3& from, const btVector3& to, int filterGroup) From c0dfad23b355dda2d2f530001868fb1eff98ba0e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 14 Mar 2015 12:00:24 +0100 Subject: [PATCH 623/740] Fixed editor operation multi-threading (Fixes #923) --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/doc/document.cpp | 3 +- apps/opencs/model/doc/document.hpp | 4 +- apps/opencs/model/doc/operation.cpp | 25 +++++---- apps/opencs/model/doc/operation.hpp | 13 +++-- apps/opencs/model/doc/operationholder.cpp | 65 +++++++++++++++++++++++ apps/opencs/model/doc/operationholder.hpp | 56 +++++++++++++++++++ apps/opencs/model/doc/runner.cpp | 4 +- apps/opencs/model/doc/runner.hpp | 4 +- apps/opencs/model/tools/tools.cpp | 62 +++++++++++---------- apps/opencs/model/tools/tools.hpp | 11 ++-- 11 files changed, 195 insertions(+), 54 deletions(-) create mode 100644 apps/opencs/model/doc/operationholder.cpp create mode 100644 apps/opencs/model/doc/operationholder.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 7eacfd7ef..e618d2961 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -5,7 +5,7 @@ set (OPENCS_SRC main.cpp opencs_units (. editor) opencs_units (model/doc - document operation saving documentmanager loader runner + document operation saving documentmanager loader runner operationholder ) opencs_units_noqt (model/doc diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index e688a9474..7d27143b4 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2254,7 +2254,8 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, mTools (*this), mResDir(resDir), mProjectPath ((configuration.getUserDataPath() / "projects") / (savePath.filename().string() + ".project")), - mSaving (*this, mProjectPath, encoding), + mSavingOperation (*this, mProjectPath, encoding), + mSaving (&mSavingOperation), mRunner (mProjectPath), mPhysics(boost::shared_ptr()) { if (mContentFiles.empty()) diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index f3aef6db6..a0905e5ad 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -20,6 +20,7 @@ #include "saving.hpp" #include "blacklist.hpp" #include "runner.hpp" +#include "operationholder.hpp" class QAbstractItemModel; @@ -59,7 +60,8 @@ namespace CSMDoc CSMWorld::Data mData; CSMTools::Tools mTools; boost::filesystem::path mProjectPath; - Saving mSaving; + Saving mSavingOperation; + OperationHolder mSaving; boost::filesystem::path mResDir; Blacklist mBlacklist; Runner mRunner; diff --git a/apps/opencs/model/doc/operation.cpp b/apps/opencs/model/doc/operation.cpp index e728050f4..3f1674f50 100644 --- a/apps/opencs/model/doc/operation.cpp +++ b/apps/opencs/model/doc/operation.cpp @@ -29,9 +29,9 @@ void CSMDoc::Operation::prepareStages() CSMDoc::Operation::Operation (int type, bool ordered, bool finalAlways) : mType (type), mStages(std::vector >()), mCurrentStage(mStages.begin()), mCurrentStep(0), mCurrentStepTotal(0), mTotalSteps(0), mOrdered (ordered), - mFinalAlways (finalAlways), mError(false) + mFinalAlways (finalAlways), mError(false), mConnected (false) { - connect (this, SIGNAL (finished()), this, SLOT (operationDone())); + mTimer = new QTimer (this); } CSMDoc::Operation::~Operation() @@ -42,15 +42,17 @@ CSMDoc::Operation::~Operation() void CSMDoc::Operation::run() { + mTimer->stop(); + + if (!mConnected) + { + connect (mTimer, SIGNAL (timeout()), this, SLOT (executeStage())); + mConnected = true; + } + prepareStages(); - QTimer timer; - - timer.connect (&timer, SIGNAL (timeout()), this, SLOT (executeStage())); - - timer.start (0); - - exec(); + mTimer->start (0); } void CSMDoc::Operation::appendStage (Stage *stage) @@ -65,7 +67,7 @@ bool CSMDoc::Operation::hasError() const void CSMDoc::Operation::abort() { - if (!isRunning()) + if (!mTimer->isActive()) return; mError = true; @@ -116,10 +118,11 @@ void CSMDoc::Operation::executeStage() emit reportMessage (iter->mId, iter->mMessage, iter->mHint, mType); if (mCurrentStage==mStages.end()) - exit(); + operationDone(); } void CSMDoc::Operation::operationDone() { + mTimer->stop(); emit done (mType, mError); } diff --git a/apps/opencs/model/doc/operation.hpp b/apps/opencs/model/doc/operation.hpp index 3c9467754..a6217fe2d 100644 --- a/apps/opencs/model/doc/operation.hpp +++ b/apps/opencs/model/doc/operation.hpp @@ -3,7 +3,8 @@ #include -#include +#include +#include namespace CSMWorld { @@ -14,7 +15,7 @@ namespace CSMDoc { class Stage; - class Operation : public QThread + class Operation : public QObject { Q_OBJECT @@ -27,6 +28,8 @@ namespace CSMDoc int mOrdered; bool mFinalAlways; bool mError; + bool mConnected; + QTimer *mTimer; void prepareStages(); @@ -38,8 +41,6 @@ namespace CSMDoc virtual ~Operation(); - virtual void run(); - void appendStage (Stage *stage); ///< The ownership of \a stage is transferred to *this. /// @@ -60,6 +61,8 @@ namespace CSMDoc void abort(); + void run(); + private slots: void executeStage(); @@ -68,4 +71,4 @@ namespace CSMDoc }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/doc/operationholder.cpp b/apps/opencs/model/doc/operationholder.cpp new file mode 100644 index 000000000..d79e14023 --- /dev/null +++ b/apps/opencs/model/doc/operationholder.cpp @@ -0,0 +1,65 @@ + +#include "operationholder.hpp" + +#include "operation.hpp" + +CSMDoc::OperationHolder::OperationHolder (Operation *operation) : mRunning (false) +{ + if (operation) + setOperation (operation); +} + +void CSMDoc::OperationHolder::setOperation (Operation *operation) +{ + mOperation = operation; + mOperation->moveToThread (&mThread); + + connect ( + mOperation, SIGNAL (progress (int, int, int)), + this, SIGNAL (progress (int, int, int))); + + connect ( + mOperation, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)), + this, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int))); + + connect ( + mOperation, SIGNAL (done (int, bool)), + this, SLOT (doneSlot (int, bool))); + + connect (this, SIGNAL (abortSignal()), mOperation, SLOT (abort())); + + connect (&mThread, SIGNAL (started()), mOperation, SLOT (run())); +} + +bool CSMDoc::OperationHolder::isRunning() const +{ + return mRunning; +} + +void CSMDoc::OperationHolder::start() +{ + mRunning = true; + mThread.start(); +} + +void CSMDoc::OperationHolder::abort() +{ + mRunning = false; + emit abortSignal(); +} + +void CSMDoc::OperationHolder::abortAndWait() +{ + if (mRunning) + { + mThread.quit(); + mThread.wait(); + } +} + +void CSMDoc::OperationHolder::doneSlot (int type, bool failed) +{ + mRunning = false; + mThread.quit(); + emit done (type, failed); +} diff --git a/apps/opencs/model/doc/operationholder.hpp b/apps/opencs/model/doc/operationholder.hpp new file mode 100644 index 000000000..6fe6df053 --- /dev/null +++ b/apps/opencs/model/doc/operationholder.hpp @@ -0,0 +1,56 @@ +#ifndef CSM_DOC_OPERATIONHOLDER_H +#define CSM_DOC_OPERATIONHOLDER_H + +#include +#include + +namespace CSMWorld +{ + class UniversalId; +} + +namespace CSMDoc +{ + class Operation; + + class OperationHolder : public QObject + { + Q_OBJECT + + QThread mThread; + Operation *mOperation; + bool mRunning; + + public: + + OperationHolder (Operation *operation = 0); + + void setOperation (Operation *operation); + + bool isRunning() const; + + void start(); + + void abort(); + + // Abort and wait until thread has finished. + void abortAndWait(); + + private slots: + + void doneSlot (int type, bool failed); + + signals: + + void progress (int current, int max, int type); + + void reportMessage (const CSMWorld::UniversalId& id, const std::string& message, + const std::string& hint, int type); + + void done (int type, bool failed); + + void abortSignal(); + }; +} + +#endif diff --git a/apps/opencs/model/doc/runner.cpp b/apps/opencs/model/doc/runner.cpp index d679c1890..14fe0cda8 100644 --- a/apps/opencs/model/doc/runner.cpp +++ b/apps/opencs/model/doc/runner.cpp @@ -6,7 +6,7 @@ #include #include -#include "operation.hpp" +#include "operationholder.hpp" CSMDoc::Runner::Runner (const boost::filesystem::path& projectPath) : mRunning (false), mStartup (0), mProjectPath (projectPath) @@ -145,7 +145,7 @@ void CSMDoc::Runner::readyReadStandardOutput() } -CSMDoc::SaveWatcher::SaveWatcher (Runner *runner, Operation *operation) +CSMDoc::SaveWatcher::SaveWatcher (Runner *runner, OperationHolder *operation) : QObject (runner), mRunner (runner) { connect (operation, SIGNAL (done (int, bool)), this, SLOT (saveDone (int, bool))); diff --git a/apps/opencs/model/doc/runner.hpp b/apps/opencs/model/doc/runner.hpp index 38b52a73b..517122492 100644 --- a/apps/opencs/model/doc/runner.hpp +++ b/apps/opencs/model/doc/runner.hpp @@ -16,6 +16,8 @@ class QTemporaryFile; namespace CSMDoc { + class OperationHolder; + class Runner : public QObject { Q_OBJECT @@ -74,7 +76,7 @@ namespace CSMDoc public: /// *this attaches itself to runner - SaveWatcher (Runner *runner, Operation *operation); + SaveWatcher (Runner *runner, OperationHolder *operation); private slots: diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 2139f890f..170ea8ccd 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -26,30 +26,30 @@ #include "referencecheck.hpp" #include "startscriptcheck.hpp" -CSMDoc::Operation *CSMTools::Tools::get (int type) +CSMDoc::OperationHolder *CSMTools::Tools::get (int type) { switch (type) { - case CSMDoc::State_Verifying: return mVerifier; + case CSMDoc::State_Verifying: return &mVerifier; } return 0; } -const CSMDoc::Operation *CSMTools::Tools::get (int type) const +const CSMDoc::OperationHolder *CSMTools::Tools::get (int type) const { return const_cast (this)->get (type); } -CSMDoc::Operation *CSMTools::Tools::getVerifier() +CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() { - if (!mVerifier) + if (!mVerifierOperation) { - mVerifier = new CSMDoc::Operation (CSMDoc::State_Verifying, false); + mVerifierOperation = new CSMDoc::Operation (CSMDoc::State_Verifying, false); - connect (mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int))); - connect (mVerifier, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool))); - connect (mVerifier, + connect (&mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int))); + connect (&mVerifier, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool))); + connect (&mVerifier, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)), this, SLOT (verifierMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int))); @@ -60,46 +60,48 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier() mandatoryIds.push_back ("Month"); mandatoryIds.push_back ("PCRace"); - mVerifier->appendStage (new MandatoryIdStage (mData.getGlobals(), + mVerifierOperation->appendStage (new MandatoryIdStage (mData.getGlobals(), CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Globals), mandatoryIds)); - mVerifier->appendStage (new SkillCheckStage (mData.getSkills())); + mVerifierOperation->appendStage (new SkillCheckStage (mData.getSkills())); - mVerifier->appendStage (new ClassCheckStage (mData.getClasses())); + mVerifierOperation->appendStage (new ClassCheckStage (mData.getClasses())); - mVerifier->appendStage (new FactionCheckStage (mData.getFactions())); + mVerifierOperation->appendStage (new FactionCheckStage (mData.getFactions())); - mVerifier->appendStage (new RaceCheckStage (mData.getRaces())); + mVerifierOperation->appendStage (new RaceCheckStage (mData.getRaces())); - mVerifier->appendStage (new SoundCheckStage (mData.getSounds())); + mVerifierOperation->appendStage (new SoundCheckStage (mData.getSounds())); - mVerifier->appendStage (new RegionCheckStage (mData.getRegions())); + mVerifierOperation->appendStage (new RegionCheckStage (mData.getRegions())); - mVerifier->appendStage (new BirthsignCheckStage (mData.getBirthsigns())); + mVerifierOperation->appendStage (new BirthsignCheckStage (mData.getBirthsigns())); - mVerifier->appendStage (new SpellCheckStage (mData.getSpells())); + mVerifierOperation->appendStage (new SpellCheckStage (mData.getSpells())); - mVerifier->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions())); + mVerifierOperation->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions())); - mVerifier->appendStage (new ReferenceCheckStage(mData.getReferences(), mData.getReferenceables(), mData.getCells(), mData.getFactions())); + mVerifierOperation->appendStage (new ReferenceCheckStage(mData.getReferences(), mData.getReferenceables(), mData.getCells(), mData.getFactions())); - mVerifier->appendStage (new ScriptCheckStage (mDocument)); + mVerifierOperation->appendStage (new ScriptCheckStage (mDocument)); - mVerifier->appendStage (new StartScriptCheckStage (mData.getStartScripts(), mData.getScripts())); + mVerifierOperation->appendStage (new StartScriptCheckStage (mData.getStartScripts(), mData.getScripts())); - mVerifier->appendStage( + mVerifierOperation->appendStage( new BodyPartCheckStage( mData.getBodyParts(), mData.getResources( CSMWorld::UniversalId( CSMWorld::UniversalId::Type_Meshes )), mData.getRaces() )); + + mVerifier.setOperation (mVerifierOperation); } - return mVerifier; + return &mVerifier; } CSMTools::Tools::Tools (CSMDoc::Document& document) -: mDocument (document), mData (document.getData()), mVerifier (0), mNextReportNumber (0) +: mDocument (document), mData (document.getData()), mVerifierOperation (0), mNextReportNumber (0) { // index 0: load error log mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel)); @@ -108,7 +110,11 @@ CSMTools::Tools::Tools (CSMDoc::Document& document) CSMTools::Tools::~Tools() { - delete mVerifier; + if (mVerifierOperation) + { + mVerifier.abortAndWait(); + delete mVerifierOperation; + } for (std::map::iterator iter (mReports.begin()); iter!=mReports.end(); ++iter) delete iter->second; @@ -126,7 +132,7 @@ CSMWorld::UniversalId CSMTools::Tools::runVerifier() void CSMTools::Tools::abortOperation (int type) { - if (CSMDoc::Operation *operation = get (type)) + if (CSMDoc::OperationHolder *operation = get (type)) operation->abort(); } @@ -141,7 +147,7 @@ int CSMTools::Tools::getRunningOperations() const int result = 0; for (int i=0; sOperations[i]!=-1; ++i) - if (const CSMDoc::Operation *operation = get (sOperations[i])) + if (const CSMDoc::OperationHolder *operation = get (sOperations[i])) if (operation->isRunning()) result |= sOperations[i]; diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp index 5125a3638..b8ded8a83 100644 --- a/apps/opencs/model/tools/tools.hpp +++ b/apps/opencs/model/tools/tools.hpp @@ -5,6 +5,8 @@ #include +#include "../doc/operationholder.hpp" + namespace CSMWorld { class Data; @@ -27,7 +29,8 @@ namespace CSMTools CSMDoc::Document& mDocument; CSMWorld::Data& mData; - CSMDoc::Operation *mVerifier; + CSMDoc::Operation *mVerifierOperation; + CSMDoc::OperationHolder mVerifier; std::map mReports; int mNextReportNumber; std::map mActiveReports; // type, report number @@ -36,12 +39,12 @@ namespace CSMTools Tools (const Tools&); Tools& operator= (const Tools&); - CSMDoc::Operation *getVerifier(); + CSMDoc::OperationHolder *getVerifier(); - CSMDoc::Operation *get (int type); + CSMDoc::OperationHolder *get (int type); ///< Returns a 0-pointer, if operation hasn't been used yet. - const CSMDoc::Operation *get (int type) const; + const CSMDoc::OperationHolder *get (int type) const; ///< Returns a 0-pointer, if operation hasn't been used yet. public: From 2ef7fc4e2c4c5e0ecf3f15bbec027b796a452a78 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 15 Mar 2015 08:08:55 +1300 Subject: [PATCH 624/740] Installer work for Windows (Fixes #1621) 1. Correctly reads Windows registry for vanilla MW install location. 2. Populates existing installation page with location of vanilla, when found. 3. On Windows, installer wizard now gets to Import page. --- apps/wizard/componentselectionpage.cpp | 4 ++++ apps/wizard/existinginstallationpage.cpp | 6 +----- apps/wizard/mainwizard.cpp | 25 +++++++++++++++++------- apps/wizard/mainwizard.hpp | 2 ++ components/files/windowspath.cpp | 15 +++----------- 5 files changed, 28 insertions(+), 24 deletions(-) diff --git a/apps/wizard/componentselectionpage.cpp b/apps/wizard/componentselectionpage.cpp index 1fcde7857..21a5c58d9 100644 --- a/apps/wizard/componentselectionpage.cpp +++ b/apps/wizard/componentselectionpage.cpp @@ -156,9 +156,13 @@ bool Wizard::ComponentSelectionPage::validatePage() int Wizard::ComponentSelectionPage::nextId() const { +#ifdef OPENMW_USE_UNSHIELD if (isCommitPage()) { return MainWizard::Page_Installation; } else { return MainWizard::Page_Import; } +#else + return MainWizard::Page_Import; +#endif } diff --git a/apps/wizard/existinginstallationpage.cpp b/apps/wizard/existinginstallationpage.cpp index 83ea20f5a..f821b38ba 100644 --- a/apps/wizard/existinginstallationpage.cpp +++ b/apps/wizard/existinginstallationpage.cpp @@ -29,11 +29,7 @@ void Wizard::ExistingInstallationPage::initializePage() QStringList paths(mWizard->mInstallations.keys()); // Hide the default item if there are installations to choose from - if (paths.isEmpty()) { - installationsList->item(0)->setHidden(false); - } else { - installationsList->item(0)->setHidden(true); - } + installationsList->item(0)->setHidden(!paths.isEmpty()); foreach (const QString &path, paths) { QListWidgetItem *item = new QListWidgetItem(path); diff --git a/apps/wizard/mainwizard.cpp b/apps/wizard/mainwizard.cpp index a1370b125..a61daa5a4 100644 --- a/apps/wizard/mainwizard.cpp +++ b/apps/wizard/mainwizard.cpp @@ -62,6 +62,12 @@ Wizard::MainWizard::MainWizard(QWidget *parent) : setupLauncherSettings(); setupInstallations(); setupPages(); + + const boost::filesystem::path& installedPath = mCfgMgr.getInstallPath(); + if (!installedPath.empty()) + { + addInstallation(toQString(installedPath)); + } } Wizard::MainWizard::~MainWizard() @@ -71,7 +77,7 @@ Wizard::MainWizard::~MainWizard() void Wizard::MainWizard::setupLog() { - QString logPath(QString::fromUtf8(mCfgMgr.getLogPath().string().c_str())); + QString logPath(toQString(mCfgMgr.getLogPath())); logPath.append(QLatin1String("wizard.log")); QFile file(logPath); @@ -93,7 +99,7 @@ void Wizard::MainWizard::setupLog() void Wizard::MainWizard::addLogText(const QString &text) { - QString logPath(QString::fromUtf8(mCfgMgr.getLogPath().string().c_str())); + QString logPath(toQString(mCfgMgr.getLogPath())); logPath.append(QLatin1String("wizard.log")); QFile file(logPath); @@ -121,8 +127,8 @@ void Wizard::MainWizard::addLogText(const QString &text) void Wizard::MainWizard::setupGameSettings() { - QString userPath(QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str())); - QString globalPath(QString::fromUtf8(mCfgMgr.getGlobalPath().string().c_str())); + QString userPath(toQString(mCfgMgr.getUserConfigPath())); + QString globalPath(toQString(mCfgMgr.getGlobalPath())); QString message(tr("

Could not open %1 for reading

\

Please make sure you have the right permissions \ and try again.

")); @@ -181,7 +187,7 @@ void Wizard::MainWizard::setupGameSettings() void Wizard::MainWizard::setupLauncherSettings() { - QString path(QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str())); + QString path(toQString(mCfgMgr.getUserConfigPath())); path.append(QLatin1String(Config::LauncherSettings::sLauncherConfigFileName)); QString message(tr("

Could not open %1 for reading

\ @@ -228,7 +234,7 @@ void Wizard::MainWizard::runSettingsImporter() QString path(field(QLatin1String("installation.path")).toString()); // Create the file if it doesn't already exist, else the importer will fail - QString userPath(QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str())); + QString userPath(toQString(mCfgMgr.getUserConfigPath())); QFile file(userPath + QLatin1String("openmw.cfg")); if (!file.exists()) { @@ -387,7 +393,7 @@ void Wizard::MainWizard::writeSettings() mGameSettings.removeDataDir(path); mGameSettings.addDataDir(path); - QString userPath(QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str())); + QString userPath(toQString(mCfgMgr.getUserConfigPath())); QDir dir(userPath); if (!dir.exists()) { @@ -460,3 +466,8 @@ bool Wizard::MainWizard::findFiles(const QString &name, const QString &path) return (dir.entryList().contains(name + QLatin1String(".esm"), Qt::CaseInsensitive) && dir.entryList().contains(name + QLatin1String(".bsa"), Qt::CaseInsensitive)); } + +QString Wizard::MainWizard::toQString(const boost::filesystem::path& path) +{ + return QString::fromUtf8(path.string().c_str()); +} diff --git a/apps/wizard/mainwizard.hpp b/apps/wizard/mainwizard.hpp index c22f20c25..7f6e48a87 100644 --- a/apps/wizard/mainwizard.hpp +++ b/apps/wizard/mainwizard.hpp @@ -59,6 +59,8 @@ namespace Wizard void addLogText(const QString &text); private: + /// convert boost::filesystem::path to QString + QString toQString(const boost::filesystem::path& path); void setupLog(); void setupGameSettings(); diff --git a/components/files/windowspath.cpp b/components/files/windowspath.cpp index 6b58304a0..0df782702 100644 --- a/components/files/windowspath.cpp +++ b/components/files/windowspath.cpp @@ -94,18 +94,8 @@ boost::filesystem::path WindowsPath::getInstallPath() const HKEY hKey; - BOOL f64 = FALSE; - LPCTSTR regkey; - if ((IsWow64Process(GetCurrentProcess(), &f64) && f64) || sizeof(void*) == 8) - { - regkey = "SOFTWARE\\Wow6432Node\\Bethesda Softworks\\Morrowind"; - } - else - { - regkey = "SOFTWARE\\Bethesda Softworks\\Morrowind"; - } - - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(regkey), 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) + LPCTSTR regkey = TEXT("SOFTWARE\\Bethesda Softworks\\Morrowind"); + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey, 0, KEY_READ | KEY_WOW64_32KEY, &hKey) == ERROR_SUCCESS) { //Key existed, let's try to read the install dir std::vector buf(512); @@ -115,6 +105,7 @@ boost::filesystem::path WindowsPath::getInstallPath() const { installPath = &buf[0]; } + RegCloseKey(hKey); } return installPath; From 1d7f3474fa139a013e0255be468333d842fd4ceb Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 15 Mar 2015 08:49:03 +1300 Subject: [PATCH 625/740] Fixed more MSVC 2013 warnings. --- apps/openmw/main.cpp | 2 +- apps/openmw/mwgui/tradewindow.cpp | 2 +- apps/openmw/mwmechanics/actors.cpp | 8 ++++---- apps/openmw/mwmechanics/combat.cpp | 2 +- apps/openmw/mwsound/ffmpeg_decoder.cpp | 10 +++++----- components/bsa/bsa_file.cpp | 2 +- components/compiler/exprparser.cpp | 2 +- extern/ogre-ffmpeg-videoplayer/videostate.cpp | 16 ++++++++-------- extern/shiny/Platforms/Ogre/OgrePass.cpp | 2 +- libs/openengine/bullet/BtOgre.cpp | 2 +- libs/openengine/bullet/BtOgreGP.h | 1 - 11 files changed, 24 insertions(+), 25 deletions(-) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 82fda060e..070136dfd 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -290,7 +290,7 @@ public: std::streamsize write(const char *str, std::streamsize size) { // Make a copy for null termination - std::string tmp (str, size); + std::string tmp (str, static_cast(size)); // Write string to Visual Studio Debug output OutputDebugString (tmp.c_str ()); return size; diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 841e2e185..dc6e2de5a 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -343,7 +343,7 @@ namespace MWGui else d = int(100 * (b - a) / a); - float clampedDisposition = std::max(0,std::min(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr) + int clampedDisposition = std::max(0, std::min(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr) + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange(),100)); const MWMechanics::CreatureStats &sellerStats = mPtr.getClass().getCreatureStats(mPtr); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index c25e207c6..c6df24154 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -524,9 +524,9 @@ namespace MWMechanics for(int i = 0;i < ESM::Attribute::Length;++i) { AttributeValue stat = creatureStats.getAttribute(i); - stat.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifyAttribute, i)).getMagnitude() - + stat.setModifier(static_cast(effects.get(EffectKey(ESM::MagicEffect::FortifyAttribute, i)).getMagnitude() - effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).getMagnitude() - - effects.get(EffectKey(ESM::MagicEffect::AbsorbAttribute, i)).getMagnitude()); + effects.get(EffectKey(ESM::MagicEffect::AbsorbAttribute, i)).getMagnitude())); stat.damage(effects.get(EffectKey(ESM::MagicEffect::DamageAttribute, i)).getMagnitude() * duration); stat.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreAttribute, i)).getMagnitude() * duration); @@ -793,9 +793,9 @@ namespace MWMechanics for(int i = 0;i < ESM::Skill::Length;++i) { SkillValue& skill = npcStats.getSkill(i); - skill.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifySkill, i)).getMagnitude() - + skill.setModifier(static_cast(effects.get(EffectKey(ESM::MagicEffect::FortifySkill, i)).getMagnitude() - effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).getMagnitude() - - effects.get(EffectKey(ESM::MagicEffect::AbsorbSkill, i)).getMagnitude()); + effects.get(EffectKey(ESM::MagicEffect::AbsorbSkill, i)).getMagnitude())); skill.damage(effects.get(EffectKey(ESM::MagicEffect::DamageSkill, i)).getMagnitude() * duration); skill.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreSkill, i)).getMagnitude() * duration); diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index fdb375846..bfc542cda 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -267,7 +267,7 @@ namespace MWMechanics attackTerm += mageffects.get(ESM::MagicEffect::FortifyAttack).getMagnitude() - mageffects.get(ESM::MagicEffect::Blind).getMagnitude(); - return static_cast((attackTerm - defenseTerm) + 0.5f); + return round(attackTerm - defenseTerm); } void applyElementalShields(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index bc467acff..0185d3ecc 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -30,7 +30,7 @@ int FFmpeg_Decoder::readPacket(void *user_data, uint8_t *buf, int buf_size) Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream; return stream->read(buf, buf_size); } - catch (std::exception& e) + catch (std::exception& ) { return 0; } @@ -43,7 +43,7 @@ int FFmpeg_Decoder::writePacket(void *user_data, uint8_t *buf, int buf_size) Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream; return stream->write(buf, buf_size); } - catch (std::exception& e) + catch (std::exception& ) { return 0; } @@ -57,11 +57,11 @@ int64_t FFmpeg_Decoder::seek(void *user_data, int64_t offset, int whence) if(whence == AVSEEK_SIZE) return stream->size(); if(whence == SEEK_SET) - stream->seek(offset); + stream->seek(static_cast(offset)); else if(whence == SEEK_CUR) - stream->seek(stream->tell()+offset); + stream->seek(static_cast(stream->tell()+offset)); else if(whence == SEEK_END) - stream->seek(stream->size()+offset); + stream->seek(static_cast(stream->size()+offset)); else return -1; diff --git a/components/bsa/bsa_file.cpp b/components/bsa/bsa_file.cpp index 0958c8f0c..0d60f4cf0 100644 --- a/components/bsa/bsa_file.cpp +++ b/components/bsa/bsa_file.cpp @@ -79,7 +79,7 @@ void BSAFile::readHeader() bfs::ifstream input(bfs::path(filename), std::ios_base::binary); // Total archive size - size_t fsize = 0; + std::streamoff fsize = 0; if(input.seekg(0, std::ios_base::end)) { fsize = input.tellg(); diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 7eaca5c02..dc36b58d8 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -324,7 +324,7 @@ namespace Compiler mNextOperand = false; mOperands.push_back ('l'); - return 2; + return true; } } diff --git a/extern/ogre-ffmpeg-videoplayer/videostate.cpp b/extern/ogre-ffmpeg-videoplayer/videostate.cpp index 0894499b2..66c7c2ad5 100644 --- a/extern/ogre-ffmpeg-videoplayer/videostate.cpp +++ b/extern/ogre-ffmpeg-videoplayer/videostate.cpp @@ -179,7 +179,7 @@ int VideoState::OgreResource_Read(void *user_data, uint8_t *buf, int buf_size) { return stream->read(buf, buf_size); } - catch (std::exception& e) + catch (std::exception& ) { return 0; } @@ -192,7 +192,7 @@ int VideoState::OgreResource_Write(void *user_data, uint8_t *buf, int buf_size) { return stream->write(buf, buf_size); } - catch (std::exception& e) + catch (std::exception& ) { return 0; } @@ -206,11 +206,11 @@ int64_t VideoState::OgreResource_Seek(void *user_data, int64_t offset, int whenc if(whence == AVSEEK_SIZE) return stream->size(); if(whence == SEEK_SET) - stream->seek(offset); + stream->seek(static_cast(offset)); else if(whence == SEEK_CUR) - stream->seek(stream->tell()+offset); + stream->seek(static_cast(stream->tell()+offset)); else if(whence == SEEK_END) - stream->seek(stream->size()+offset); + stream->seek(static_cast(stream->size() + offset)); else return -1; @@ -400,7 +400,7 @@ void VideoState::video_thread_loop(VideoState *self) self->pictq_mutex.unlock(); self->frame_last_pts = packet->pts * av_q2d((*self->video_st)->time_base); - global_video_pkt_pts = self->frame_last_pts; + global_video_pkt_pts = static_cast(self->frame_last_pts); continue; } @@ -412,9 +412,9 @@ void VideoState::video_thread_loop(VideoState *self) double pts = 0; if(packet->dts != AV_NOPTS_VALUE) - pts = packet->dts; + pts = static_cast(packet->dts); else if(pFrame->opaque && *(int64_t*)pFrame->opaque != AV_NOPTS_VALUE) - pts = *(int64_t*)pFrame->opaque; + pts = static_cast(*(int64_t*)pFrame->opaque); pts *= av_q2d((*self->video_st)->time_base); av_free_packet(packet); diff --git a/extern/shiny/Platforms/Ogre/OgrePass.cpp b/extern/shiny/Platforms/Ogre/OgrePass.cpp index 3a25c5c74..5cd501094 100644 --- a/extern/shiny/Platforms/Ogre/OgrePass.cpp +++ b/extern/shiny/Platforms/Ogre/OgrePass.cpp @@ -109,7 +109,7 @@ namespace sh { params->addSharedParameters (name); } - catch (Ogre::Exception& e) + catch (Ogre::Exception& ) { std::stringstream msg; msg << "Could not create a shared parameter instance for '" diff --git a/libs/openengine/bullet/BtOgre.cpp b/libs/openengine/bullet/BtOgre.cpp index 88619b7fc..0af173adc 100644 --- a/libs/openengine/bullet/BtOgre.cpp +++ b/libs/openengine/bullet/BtOgre.cpp @@ -150,7 +150,7 @@ namespace BtOgre { if (i == mBoneIndex->end()) { l = new Vector3Array; - mBoneIndex->insert(BoneKeyIndex(currBone, l)); + mBoneIndex->insert(std::make_pair(currBone, l)); } else { diff --git a/libs/openengine/bullet/BtOgreGP.h b/libs/openengine/bullet/BtOgreGP.h index dde606a4f..7e497b535 100644 --- a/libs/openengine/bullet/BtOgreGP.h +++ b/libs/openengine/bullet/BtOgreGP.h @@ -27,7 +27,6 @@ namespace BtOgre { typedef std::map BoneIndex; -typedef std::pair BoneKeyIndex; class VertexIndexToShape { From 3f28634d1f617691c672e41a3ee950e6daec8c77 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 15 Mar 2015 14:07:47 +1300 Subject: [PATCH 626/740] consolidate random number logic Note, I suspect Rng::rollClosedProbability() is not needed. The only difference between it and rollProbability() is that one time in 37k (on Windows), it will give an output of 1.0. On some versions of Linux, the value of 1.0 will occur about 1 time in 4 billion. --- apps/openmw/engine.cpp | 3 ++ apps/openmw/mwclass/creature.cpp | 9 ++--- apps/openmw/mwclass/npc.cpp | 12 +++---- apps/openmw/mwgui/jailscreen.cpp | 4 ++- apps/openmw/mwgui/loadingscreen.cpp | 4 ++- apps/openmw/mwgui/pickpocketitemmodel.cpp | 6 +++- apps/openmw/mwgui/recharge.cpp | 4 ++- apps/openmw/mwgui/tradewindow.cpp | 4 ++- apps/openmw/mwgui/waitdialog.cpp | 7 ++-- apps/openmw/mwmechanics/activespells.cpp | 5 +-- apps/openmw/mwmechanics/aicombat.cpp | 25 ++++++------- apps/openmw/mwmechanics/aiwander.cpp | 10 +++--- apps/openmw/mwmechanics/alchemy.cpp | 6 ++-- apps/openmw/mwmechanics/character.cpp | 8 +++-- apps/openmw/mwmechanics/combat.cpp | 12 +++---- apps/openmw/mwmechanics/disease.hpp | 6 ++-- apps/openmw/mwmechanics/enchanting.cpp | 5 ++- apps/openmw/mwmechanics/levelledlist.hpp | 7 ++-- .../mwmechanics/mechanicsmanagerimp.cpp | 7 ++-- apps/openmw/mwmechanics/pickpocket.cpp | 4 ++- apps/openmw/mwmechanics/repair.cpp | 4 ++- apps/openmw/mwmechanics/security.cpp | 8 ++--- apps/openmw/mwmechanics/spellcasting.cpp | 20 +++++------ apps/openmw/mwmechanics/spells.cpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 4 ++- apps/openmw/mwrender/sky.cpp | 6 ++-- apps/openmw/mwsound/soundmanagerimp.cpp | 8 +++-- apps/openmw/mwworld/inventorystore.cpp | 2 +- apps/openmw/mwworld/store.hpp | 4 ++- apps/openmw/mwworld/weather.cpp | 8 +++-- apps/openmw/mwworld/worldimp.cpp | 6 ++-- components/CMakeLists.txt | 6 +++- components/nifogre/particles.cpp | 4 ++- libs/openengine/CMakeLists.txt | 7 +++- libs/openengine/misc/rng.cpp | 29 +++++++++++++++ libs/openengine/misc/rng.hpp | 36 +++++++++++++++++++ libs/openengine/ogre/selectionbuffer.cpp | 4 ++- 37 files changed, 214 insertions(+), 92 deletions(-) create mode 100644 libs/openengine/misc/rng.cpp create mode 100644 libs/openengine/misc/rng.hpp diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 92731ee1a..a4bb8c538 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -10,6 +10,8 @@ #include +#include + #include #include @@ -191,6 +193,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) , mExportFonts(false) , mNewGame (false) { + OEngine::Misc::Rng::init(); std::srand ( static_cast(std::time(NULL)) ); MWClass::registerClasses(); diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 908de02d8..8404b9523 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -1,6 +1,8 @@ #include "creature.hpp" +#include + #include #include @@ -249,7 +251,7 @@ namespace MWClass float hitchance = MWMechanics::getHitChance(ptr, victim, ref->mBase->mData.mCombat); - if((::rand()/(RAND_MAX+1.0)) >= hitchance/100.0f) + if(OEngine::Misc::Rng::rollProbability() >= hitchance/100.0f) { victim.getClass().onHit(victim, 0.0f, false, MWWorld::Ptr(), ptr, false); MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr); @@ -375,8 +377,7 @@ namespace MWClass float agilityTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * getGmst().fKnockDownMult->getFloat(); float knockdownTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * getGmst().iKnockDownOddsMult->getInt() * 0.01f + getGmst().iKnockDownOddsBase->getInt(); - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] - if (ishealth && agilityTerm <= damage && knockdownTerm <= roll) + if (ishealth && agilityTerm <= damage && knockdownTerm <= OEngine::Misc::Rng::roll0to99()) { getCreatureStats(ptr).setKnockedDown(true); @@ -680,7 +681,7 @@ namespace MWClass ++sound; } if(!sounds.empty()) - return sounds[(int)(rand()/(RAND_MAX+1.0)*sounds.size())]->mSound; + return sounds[OEngine::Misc::Rng::rollDice(sounds.size())]->mSound; } if (type == ESM::SoundGenerator::Land) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index d5055fcb2..1d58dc87e 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -5,6 +5,8 @@ #include +#include + #include #include #include @@ -513,7 +515,7 @@ namespace MWClass float hitchance = MWMechanics::getHitChance(ptr, victim, ptr.getClass().getSkill(ptr, weapskill)); - if((::rand()/(RAND_MAX+1.0)) >= hitchance/100.0f) + if (OEngine::Misc::Rng::rollProbability() >= hitchance / 100.0f) { othercls.onHit(victim, 0.0f, false, weapon, ptr, false); MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr); @@ -643,8 +645,7 @@ namespace MWClass const GMST& gmst = getGmst(); int chance = store.get().find("iVoiceHitOdds")->getInt(); - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] - if (roll < chance) + if (OEngine::Misc::Rng::roll0to99() < chance) { MWBase::Environment::get().getDialogueManager()->say(ptr, "hit"); } @@ -653,8 +654,7 @@ namespace MWClass float agilityTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * gmst.fKnockDownMult->getFloat(); float knockdownTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * gmst.iKnockDownOddsMult->getInt() * 0.01f + gmst.iKnockDownOddsBase->getInt(); - roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] - if (ishealth && agilityTerm <= damage && knockdownTerm <= roll) + if (ishealth && agilityTerm <= damage && knockdownTerm <= OEngine::Misc::Rng::roll0to99()) { getCreatureStats(ptr).setKnockedDown(true); @@ -680,7 +680,7 @@ namespace MWClass MWWorld::InventoryStore::Slot_RightPauldron, MWWorld::InventoryStore::Slot_RightPauldron, MWWorld::InventoryStore::Slot_LeftGauntlet, MWWorld::InventoryStore::Slot_RightGauntlet }; - int hitslot = hitslots[(int)(::rand()/(RAND_MAX+1.0)*20.0)]; + int hitslot = hitslots[OEngine::Misc::Rng::rollDice(20)]; float unmitigatedDamage = damage; float x = damage / (damage + getArmorRating(ptr)); diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index 728c46023..5c0a6ec5f 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -1,5 +1,7 @@ #include +#include + #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/world.hpp" @@ -83,7 +85,7 @@ namespace MWGui std::set skills; for (int day=0; day(std::rand() / (static_cast (RAND_MAX)+1) * ESM::Skill::Length); + int skill = OEngine::Misc::Rng::rollDice(ESM::Skill::Length); skills.insert(skill); MWMechanics::SkillValue& value = player.getClass().getNpcStats(player).getSkill(skill); diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index f920acf1a..3204c6548 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -15,6 +15,8 @@ #include #include +#include + #include #include "../mwbase/environment.hpp" @@ -146,7 +148,7 @@ namespace MWGui if (!mResources.empty()) { - std::string const & randomSplash = mResources.at (rand() % mResources.size()); + std::string const & randomSplash = mResources.at(OEngine::Misc::Rng::rollDice(mResources.size())); Ogre::TextureManager::getSingleton ().load (randomSplash, Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME); diff --git a/apps/openmw/mwgui/pickpocketitemmodel.cpp b/apps/openmw/mwgui/pickpocketitemmodel.cpp index f6882ada6..bc7c5528e 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.cpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.cpp @@ -1,5 +1,7 @@ #include "pickpocketitemmodel.hpp" +#include + #include "../mwmechanics/npcstats.hpp" #include "../mwworld/class.hpp" @@ -12,11 +14,13 @@ namespace MWGui int chance = thief.getClass().getSkill(thief, ESM::Skill::Sneak); mSourceModel->update(); + + // build list of items that player is unable to find when attempts to pickpocket. if (hideItems) { for (size_t i = 0; igetItemCount(); ++i) { - if (std::rand() / static_cast(RAND_MAX) * 100 > chance) + if (chance <= OEngine::Misc::Rng::roll0to99()) mHiddenItems.push_back(mSourceModel->getItem(i)); } } diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 1af31373c..a0e5991b4 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -5,6 +5,8 @@ #include #include +#include + #include #include "../mwbase/world.hpp" @@ -161,7 +163,7 @@ void Recharge::onItemClicked(MyGUI::Widget *sender) intelligenceTerm = 1; float x = (npcStats.getSkill(ESM::Skill::Enchant).getModified() + intelligenceTerm + luckTerm) * stats.getFatigueTerm(); - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] + int roll = OEngine::Misc::Rng::roll0to99(); if (roll < x) { std::string soul = gem.getCellRef().getSoul(); diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 841e2e185..e14642fe7 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -4,6 +4,8 @@ #include #include +#include + #include #include "../mwbase/environment.hpp" @@ -365,7 +367,7 @@ namespace MWGui else x += abs(int(npcTerm - pcTerm)); - int roll = std::rand()%100 + 1; + int roll = OEngine::Misc::Rng::rollDice(100) + 1; if(roll > x || (mCurrentMerchantOffer < 0) != (mCurrentBalance < 0)) //trade refused { MWBase::Environment::get().getWindowManager()-> diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index b73ab38f2..f74b06891 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -2,6 +2,8 @@ #include +#include + #include #include @@ -152,10 +154,9 @@ namespace MWGui const ESM::Region *region = world->getStore().get().find (regionstr); if (!region->mSleepList.empty()) { + // figure out if player will be woken while sleeping float fSleepRandMod = world->getStore().get().find("fSleepRandMod")->getFloat(); - int x = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * hoursToWait); // [0, hoursRested] - float y = fSleepRandMod * hoursToWait; - if (x > y) + if (OEngine::Misc::Rng::rollProbability() > fSleepRandMod) { float fSleepRestMod = world->getStore().get().find("fSleepRestMod")->getFloat(); mInterruptAt = hoursToWait - int(fSleepRestMod * hoursToWait); diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index 5eea08caa..a6cc9af8e 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -1,5 +1,7 @@ #include "activespells.hpp" +#include + #include #include @@ -229,8 +231,7 @@ namespace MWMechanics { for (TContainer::iterator it = mSpells.begin(); it != mSpells.end(); ) { - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] - if (roll < chance) + if (OEngine::Misc::Rng::roll0to99() < chance) mSpells.erase(it++); else ++it; diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index c16baefaa..bac7d7286 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -2,6 +2,8 @@ #include +#include + #include #include "../mwworld/class.hpp" @@ -393,7 +395,7 @@ namespace MWMechanics if (!distantCombat) attackType = chooseBestAttack(weapon, movement); else attackType = ESM::Weapon::AT_Chop; // cause it's =0 - strength = static_cast(rand()) / RAND_MAX; + strength = OEngine::Misc::Rng::rollClosedProbability(); // Note: may be 0 for some animations timerAttack = minMaxAttackDuration[attackType][0] + @@ -404,8 +406,7 @@ namespace MWMechanics { const MWWorld::ESMStore &store = world->getStore(); int chance = store.get().find("iVoiceAttackOdds")->getInt(); - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] - if (roll < chance) + if (OEngine::Misc::Rng::roll0to99() < chance) { MWBase::Environment::get().getDialogueManager()->say(actor, "attack"); } @@ -512,17 +513,17 @@ namespace MWMechanics { if(movement.mPosition[0] || movement.mPosition[1]) { - timerCombatMove = 0.1f + 0.1f * static_cast(rand())/RAND_MAX; + timerCombatMove = 0.1f + 0.1f * OEngine::Misc::Rng::rollClosedProbability(); combatMove = true; } // only NPCs are smart enough to use dodge movements else if(actorClass.isNpc() && (!distantCombat || (distantCombat && distToTarget < rangeAttack/2))) { //apply sideway movement (kind of dodging) with some probability - if(static_cast(rand())/RAND_MAX < 0.25) + if (OEngine::Misc::Rng::rollClosedProbability() < 0.25) { - movement.mPosition[0] = static_cast(rand())/RAND_MAX < 0.5? 1.0f : -1.0f; - timerCombatMove = 0.05f + 0.15f * static_cast(rand())/RAND_MAX; + movement.mPosition[0] = OEngine::Misc::Rng::rollProbability() < 0.5 ? 1.0f : -1.0f; + timerCombatMove = 0.05f + 0.15f * OEngine::Misc::Rng::rollClosedProbability(); combatMove = true; } } @@ -637,7 +638,7 @@ namespace MWMechanics float s2 = speed2 * t; float t_swing = minMaxAttackDuration[ESM::Weapon::AT_Thrust][0] + - (minMaxAttackDuration[ESM::Weapon::AT_Thrust][1] - minMaxAttackDuration[ESM::Weapon::AT_Thrust][0]) * static_cast(rand()) / RAND_MAX; + (minMaxAttackDuration[ESM::Weapon::AT_Thrust][1] - minMaxAttackDuration[ESM::Weapon::AT_Thrust][0]) * OEngine::Misc::Rng::rollClosedProbability(); if (t + s2/speed1 <= t_swing) { @@ -761,10 +762,10 @@ ESM::Weapon::AttackType chooseBestAttack(const ESM::Weapon* weapon, MWMechanics: if (weapon == NULL) { //hand-to-hand deal equal damage for each type - float roll = static_cast(rand())/RAND_MAX; + float roll = OEngine::Misc::Rng::rollClosedProbability(); if(roll <= 0.333f) //side punch { - movement.mPosition[0] = (static_cast(rand())/RAND_MAX < 0.5f)? 1.0f : -1.0f; + movement.mPosition[0] = OEngine::Misc::Rng::rollClosedProbability() ? 1.0f : -1.0f; movement.mPosition[1] = 0; attackType = ESM::Weapon::AT_Slash; } @@ -788,10 +789,10 @@ ESM::Weapon::AttackType chooseBestAttack(const ESM::Weapon* weapon, MWMechanics: float total = static_cast(slash + chop + thrust); - float roll = static_cast(rand())/RAND_MAX; + float roll = OEngine::Misc::Rng::rollClosedProbability(); if(roll <= (slash/total)) { - movement.mPosition[0] = (static_cast(rand())/RAND_MAX < 0.5f)? 1.0f : -1.0f; + movement.mPosition[0] = (OEngine::Misc::Rng::rollClosedProbability() < 0.5f) ? 1.0f : -1.0f; movement.mPosition[1] = 0; attackType = ESM::Weapon::AT_Slash; } diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 842f03edf..b791ff3a9 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -3,6 +3,8 @@ #include #include +#include + #include #include "../mwbase/world.hpp" @@ -315,7 +317,7 @@ namespace MWMechanics static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore() .get().find("fVoiceIdleOdds")->getFloat(); - float roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 10000; + float roll = OEngine::Misc::Rng::rollProbability() * 10000.0f; // In vanilla MW the chance was FPS dependent, and did not allow proper changing of fVoiceIdleOdds // due to the roll being an integer. @@ -490,7 +492,7 @@ namespace MWMechanics if(!storage.mPathFinder.isPathConstructed()) { assert(mAllowedNodes.size()); - unsigned int randNode = (int)(rand() / ((double)RAND_MAX + 1) * mAllowedNodes.size()); + unsigned int randNode = OEngine::Misc::Rng::rollDice(mAllowedNodes.size()); // NOTE: initially constructed with local (i.e. cell) co-ordinates Ogre::Vector3 destNodePos(PathFinder::MakeOgreVector3(mAllowedNodes[randNode])); @@ -637,7 +639,7 @@ namespace MWMechanics .get().find("fIdleChanceMultiplier")->getFloat(); unsigned short idleChance = static_cast(fIdleChanceMultiplier * mIdle[counter]); - unsigned short randSelect = (int)(rand() / ((double)RAND_MAX + 1) * int(100 / fIdleChanceMultiplier)); + unsigned short randSelect = (int)(OEngine::Misc::Rng::rollProbability() * int(100 / fIdleChanceMultiplier)); if(randSelect < idleChance && randSelect > idleRoll) { playedIdle = counter+2; @@ -659,7 +661,7 @@ namespace MWMechanics state.moveIn(new AiWanderStorage()); - int index = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * mAllowedNodes.size()); + int index = OEngine::Misc::Rng::rollDice(mAllowedNodes.size()); ESM::Pathgrid::Point dest = mAllowedNodes[index]; // apply a slight offset to prevent overcrowding diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index a833e28d9..58c42ddb8 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -8,6 +8,8 @@ #include #include +#include + #include #include #include @@ -294,7 +296,7 @@ void MWMechanics::Alchemy::addPotion (const std::string& name) newRecord.mName = name; - int index = static_cast (std::rand()/(static_cast (RAND_MAX)+1)*6); + int index = OEngine::Misc::Rng::rollDice(6); assert (index>=0 && index<6); static const char *meshes[] = { "standard", "bargain", "cheap", "fresh", "exclusive", "quality" }; @@ -467,7 +469,7 @@ MWMechanics::Alchemy::Result MWMechanics::Alchemy::create (const std::string& na return Result_RandomFailure; } - if (getAlchemyFactor() (RAND_MAX)*100) + if (getAlchemyFactor() < OEngine::Misc::Rng::roll0to99()) { removeIngredients(); return Result_RandomFailure; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 28028500a..ffde59aee 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -27,6 +27,8 @@ #include "creaturestats.hpp" #include "security.hpp" +#include + #include #include "../mwrender/animation.hpp" @@ -220,7 +222,7 @@ std::string CharacterController::chooseRandomGroup (const std::string& prefix, i while (mAnimation->hasAnimation(prefix + Ogre::StringConverter::toString(numAnims+1))) ++numAnims; - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * numAnims) + 1; // [1, numAnims] + int roll = OEngine::Misc::Rng::rollDice(numAnims) + 1; // [1, numAnims] if (num) *num = roll; return prefix + Ogre::StringConverter::toString(roll); @@ -829,7 +831,7 @@ bool CharacterController::updateCreatureState() } if (weapType != WeapType_Spell || !mAnimation->hasAnimation("spellcast")) // Not all creatures have a dedicated spellcast animation { - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 3); // [0, 2] + int roll = OEngine::Misc::Rng::rollDice(3); // [0, 2] if (roll == 0) mCurrentWeapon = "attack1"; else if (roll == 1) @@ -1125,7 +1127,7 @@ bool CharacterController::updateWeaponState() // most creatures don't actually have an attack wind-up animation, so use a uniform random value // (even some creatures that can use weapons don't have a wind-up animation either, e.g. Rieklings) // Note: vanilla MW uses a random value for *all* non-player actors, but we probably don't need to go that far. - attackStrength = std::min(1.f, 0.1f + std::rand() / float(RAND_MAX)); + attackStrength = std::min(1.f, 0.1f + OEngine::Misc::Rng::rollClosedProbability()); } if(mWeaponType != WeapType_Crossbow && mWeaponType != WeapType_BowAndArrow) diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index fdb375846..6a1e08df8 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -2,6 +2,8 @@ #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -107,8 +109,7 @@ namespace MWMechanics int iBlockMinChance = gmst.find("iBlockMinChance")->getInt(); x = std::min(iBlockMaxChance, std::max(iBlockMinChance, x)); - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] - if (roll < x) + if (OEngine::Misc::Rng::roll0to99() < x) { // Reduce shield durability by incoming damage int shieldhealth = shield->getClass().getItemHealth(*shield); @@ -186,7 +187,7 @@ namespace MWMechanics int skillValue = attacker.getClass().getSkill(attacker, weapon.getClass().getEquipmentSkill(weapon)); - if((::rand()/(RAND_MAX+1.0)) >= getHitChance(attacker, victim, skillValue)/100.0f) + if (OEngine::Misc::Rng::rollProbability() >= getHitChance(attacker, victim, skillValue) / 100.0f) { victim.getClass().onHit(victim, 0.0f, false, projectile, attacker, false); MWMechanics::reduceWeaponCondition(0.f, false, weapon, attacker); @@ -224,7 +225,7 @@ namespace MWMechanics && !appliedEnchantment) { float fProjectileThrownStoreChance = gmst.find("fProjectileThrownStoreChance")->getFloat(); - if ((::rand()/(RAND_MAX+1.0)) < fProjectileThrownStoreChance/100.f) + if (OEngine::Misc::Rng::rollProbability() < fProjectileThrownStoreChance / 100.f) victim.getClass().getContainerStore(victim).add(projectile, 1, victim); } @@ -291,8 +292,7 @@ namespace MWMechanics saveTerm *= 1.25f * normalisedFatigue; - float roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] - float x = std::max(0.f, saveTerm - roll); + float x = std::max(0.f, saveTerm - OEngine::Misc::Rng::roll0to99()); int element = ESM::MagicEffect::FireDamage; if (i == 1) diff --git a/apps/openmw/mwmechanics/disease.hpp b/apps/openmw/mwmechanics/disease.hpp index 2f7d65dfd..0153be3dc 100644 --- a/apps/openmw/mwmechanics/disease.hpp +++ b/apps/openmw/mwmechanics/disease.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_MECHANICS_DISEASE_H #define OPENMW_MECHANICS_DISEASE_H +#include + #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -49,9 +51,7 @@ namespace MWMechanics continue; int x = static_cast(fDiseaseXferChance * 100 * resist); - float roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 10000); // [0, 9999] - - if (roll < x) + if (OEngine::Misc::Rng::rollDice(10000) < x) { // Contracted disease! actor.getClass().getCreatureStats(actor).getSpells().add(it->first); diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index d99b337d5..bb02fb41d 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -1,4 +1,7 @@ #include "enchanting.hpp" + +#include + #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" @@ -67,7 +70,7 @@ namespace MWMechanics if(mSelfEnchanting) { - if(getEnchantChance() (RAND_MAX)*100) + if(getEnchantChance() <= (OEngine::Misc::Rng::roll0to99())) return false; mEnchanter.getClass().skillUsageSucceeded (mEnchanter, ESM::Skill::Enchant, 2); diff --git a/apps/openmw/mwmechanics/levelledlist.hpp b/apps/openmw/mwmechanics/levelledlist.hpp index cd1276038..20b87a3a9 100644 --- a/apps/openmw/mwmechanics/levelledlist.hpp +++ b/apps/openmw/mwmechanics/levelledlist.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_MECHANICS_LEVELLEDLIST_H #define OPENMW_MECHANICS_LEVELLEDLIST_H +#include + #include "../mwworld/ptr.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/manualref.hpp" @@ -22,8 +24,7 @@ namespace MWMechanics failChance += levItem->mChanceNone; - int random = static_cast(static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100)); // [0, 99] - if (random < failChance) + if (OEngine::Misc::Rng::roll0to99() < failChance) return std::string(); std::vector candidates; @@ -52,7 +53,7 @@ namespace MWMechanics } if (candidates.empty()) return std::string(); - std::string item = candidates[std::rand()%candidates.size()]; + std::string item = candidates[OEngine::Misc::Rng::rollDice(candidates.size())]; // Vanilla doesn't fail on nonexistent items in levelled lists if (!MWBase::Environment::get().getWorld()->getStore().find(Misc::StringUtils::lowerCase(item))) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index bf1d3ec19..0d4518f87 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -2,6 +2,8 @@ #include "mechanicsmanagerimp.hpp" #include "npcstats.hpp" +#include + #include #include "../mwworld/esmstore.hpp" @@ -723,7 +725,7 @@ namespace MWMechanics float x = 0; float y = 0; - float roll = static_cast (std::rand()) / RAND_MAX * 100; + float roll = OEngine::Misc::Rng::rollClosedProbability() * 100; if (type == PT_Admire) { @@ -1378,9 +1380,8 @@ namespace MWMechanics y = obsTerm * observerStats.getFatigueTerm() * fSneakViewMult; float target = x - y; - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] - return (roll >= target); + return (OEngine::Misc::Rng::roll0to99() >= target); } void MechanicsManager::startCombat(const MWWorld::Ptr &ptr, const MWWorld::Ptr &target) diff --git a/apps/openmw/mwmechanics/pickpocket.cpp b/apps/openmw/mwmechanics/pickpocket.cpp index 12db9d6f5..561011df3 100644 --- a/apps/openmw/mwmechanics/pickpocket.cpp +++ b/apps/openmw/mwmechanics/pickpocket.cpp @@ -1,5 +1,7 @@ #include "pickpocket.hpp" +#include + #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" @@ -39,7 +41,7 @@ namespace MWMechanics int iPickMaxChance = MWBase::Environment::get().getWorld()->getStore().get() .find("iPickMaxChance")->getInt(); - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] + int roll = OEngine::Misc::Rng::roll0to99(); if (t < pcSneak / iPickMinChance) { return (roll > int(pcSneak / iPickMinChance)); diff --git a/apps/openmw/mwmechanics/repair.cpp b/apps/openmw/mwmechanics/repair.cpp index 486a9183d..b5058fb88 100644 --- a/apps/openmw/mwmechanics/repair.cpp +++ b/apps/openmw/mwmechanics/repair.cpp @@ -2,6 +2,8 @@ #include +#include + #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -46,7 +48,7 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair) float x = (0.1f * pcStrength + 0.1f * pcLuck + armorerSkill) * fatigueTerm; - int roll = static_cast(static_cast (std::rand()) / RAND_MAX * 100); + int roll = OEngine::Misc::Rng::roll0to99(); if (roll <= x) { int y = static_cast(fRepairAmountMult * toolQuality * roll); diff --git a/apps/openmw/mwmechanics/security.cpp b/apps/openmw/mwmechanics/security.cpp index d987814e5..3f72f1b66 100644 --- a/apps/openmw/mwmechanics/security.cpp +++ b/apps/openmw/mwmechanics/security.cpp @@ -1,5 +1,7 @@ #include "security.hpp" +#include + #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/esmstore.hpp" @@ -48,8 +50,7 @@ namespace MWMechanics else { MWBase::Environment::get().getMechanicsManager()->objectOpened(mActor, lock); - int roll = static_cast(static_cast (std::rand()) / RAND_MAX * 100); - if (roll <= x) + if (OEngine::Misc::Rng::roll0to99() <= x) { lock.getClass().unlock(lock); resultMessage = "#{sLockSuccess}"; @@ -90,8 +91,7 @@ namespace MWMechanics else { MWBase::Environment::get().getMechanicsManager()->objectOpened(mActor, trap); - int roll = static_cast(static_cast (std::rand()) / RAND_MAX * 100); - if (roll <= x) + if (OEngine::Misc::Rng::roll0to99() <= x) { trap.getCellRef().setTrap(""); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 590c8fe83..8a43cc932 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -4,6 +4,8 @@ #include +#include + #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -280,7 +282,7 @@ namespace MWMechanics if (castChance > 0) x *= 50 / castChance; - float roll = static_cast(std::rand()) / RAND_MAX * 100; + float roll = OEngine::Misc::Rng::rollClosedProbability() * 100; if (magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude) roll -= resistance; @@ -383,8 +385,7 @@ namespace MWMechanics target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::ResistCommonDisease).getMagnitude() : target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::ResistBlightDisease).getMagnitude(); - int roll = static_cast(std::rand()/ (static_cast (RAND_MAX) + 1) * 100); // [0, 99] - if (roll <= x) + if (OEngine::Misc::Rng::roll0to99() <= x) { // Fully resisted, show message if (target == MWBase::Environment::get().getWorld()->getPlayerPtr()) @@ -414,8 +415,7 @@ namespace MWMechanics if (spell && caster != target && target.getClass().isActor()) { float absorb = target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::SpellAbsorption).getMagnitude(); - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] - absorbed = (roll < absorb); + absorbed = (OEngine::Misc::Rng::roll0to99() < absorb); if (absorbed) { const ESM::Static* absorbStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Absorb"); @@ -463,8 +463,7 @@ namespace MWMechanics if (!reflected && magnitudeMult > 0 && !caster.isEmpty() && caster != target && !(magicEffect->mData.mFlags & ESM::MagicEffect::Unreflectable)) { float reflect = target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Reflect).getMagnitude(); - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] - bool isReflected = (roll < reflect); + bool isReflected = (OEngine::Misc::Rng::roll0to99() < reflect); if (isReflected) { const ESM::Static* reflectStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Reflect"); @@ -492,7 +491,7 @@ namespace MWMechanics if (magnitudeMult > 0 && !absorbed) { - float random = std::rand() / static_cast(RAND_MAX); + float random = OEngine::Misc::Rng::rollClosedProbability(); float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random; magnitude *= magnitudeMult; @@ -824,8 +823,7 @@ namespace MWMechanics // Check success float successChance = getSpellSuccessChance(spell, mCaster); - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] - if (!fail && roll >= successChance) + if (OEngine::Misc::Rng::roll0to99() >= successChance) { if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicSkillFail}"); @@ -903,7 +901,7 @@ namespace MWMechanics + 0.1f * creatureStats.getAttribute (ESM::Attribute::Luck).getModified()) * creatureStats.getFatigueTerm(); - int roll = static_cast(std::rand() / (static_cast (RAND_MAX)+1) * 100); // [0, 99] + int roll = OEngine::Misc::Rng::roll0to99(); if (roll > x) { // "X has no effect on you" diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index dcbd3f09f..04225b43e 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -38,7 +38,7 @@ namespace MWMechanics for (unsigned int i=0; imEffects.mList.size();++i) { if (spell->mEffects.mList[i].mMagnMin != spell->mEffects.mList[i].mMagnMax) - random[i] = static_cast (std::rand()) / RAND_MAX; + random[i] = OEngine::Misc::Rng::rollClosedProbability(); } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 284788522..a724644a7 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -12,6 +12,8 @@ #include +#include + #include #include "../mwworld/esmstore.hpp" @@ -101,7 +103,7 @@ void HeadAnimationTime::setEnabled(bool enabled) void HeadAnimationTime::resetBlinkTimer() { - mBlinkTimer = -(2 + (std::rand() / static_cast(RAND_MAX)) * 6); + mBlinkTimer = -(2.0f + OEngine::Misc::Rng::rollDice(6)); } void HeadAnimationTime::update(float dt) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 6e9684475..d591cca2e 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -19,6 +19,8 @@ #include +#include + #include #include @@ -464,8 +466,8 @@ void SkyManager::updateRain(float dt) // TODO: handle rain settings from Morrowind.ini const float rangeRandom = 100; - float xOffs = (std::rand()/(RAND_MAX+1.0f)) * rangeRandom - (rangeRandom/2); - float yOffs = (std::rand()/(RAND_MAX+1.0f)) * rangeRandom - (rangeRandom/2); + float xOffs = OEngine::Misc::Rng::rollProbability() * rangeRandom - (rangeRandom / 2); + float yOffs = OEngine::Misc::Rng::rollProbability() * rangeRandom - (rangeRandom / 2); // Create a separate node to control the offset, since a node with setInheritOrientation(false) will still // consider the orientation of the parent node for its position, just not for its orientation diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 998cc460b..06c40dd8e 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -4,6 +4,8 @@ #include #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/statemanager.hpp" @@ -224,7 +226,7 @@ namespace MWSound if(!filelist.size()) return; - int i = rand()%filelist.size(); + int i = OEngine::Misc::Rng::rollDice(filelist.size()); // Don't play the same music track twice in a row if (filelist[i] == mLastPlayedMusic) @@ -559,7 +561,7 @@ namespace MWSound if(!cell->isExterior() || sTimePassed < sTimeToNextEnvSound) return; - float a = std::rand() / static_cast(RAND_MAX); + float a = OEngine::Misc::Rng::rollClosedProbability(); // NOTE: We should use the "Minimum Time Between Environmental Sounds" and // "Maximum Time Between Environmental Sounds" fallback settings here. sTimeToNextEnvSound = 5.0f*a + 15.0f*(1.0f-a); @@ -588,7 +590,7 @@ namespace MWSound return; } - int r = (int)(rand()/((double)RAND_MAX+1) * total); + int r = OEngine::Misc::Rng::rollDice(total); int pos = 0; soundIter = regn->mSoundList.begin(); diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index da43df513..4503e66f5 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -364,7 +364,7 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor) // Roll some dice, one for each effect params.resize(enchantment.mEffects.mList.size()); for (unsigned int i=0; i (std::rand()) / RAND_MAX; + params[i].mRandom = OEngine::Misc::Rng::rollClosedProbability(); // Try resisting each effect int i=0; diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 56f16377b..d6aeeb51e 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -7,6 +7,8 @@ #include #include +#include + #include #include @@ -178,7 +180,7 @@ namespace MWWorld std::vector results; std::for_each(mShared.begin(), mShared.end(), GetRecords(id, &results)); if(!results.empty()) - return results[int(std::rand()/((double)RAND_MAX+1)*results.size())]; + return results[OEngine::Misc::Rng::rollDice(results.size())]; return NULL; } diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 69495cdd2..a9ca8e72b 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -3,6 +3,8 @@ #include "weather.hpp" +#include + #include #include "../mwbase/environment.hpp" @@ -526,7 +528,7 @@ void WeatherManager::update(float duration, bool paused) if (mThunderSoundDelay <= 0) { // pick a random sound - int sound = rand() % 4; + int sound = OEngine::Misc::Rng::rollDice(4); std::string* soundName = NULL; if (sound == 0) soundName = &mThunderSoundID0; else if (sound == 1) soundName = &mThunderSoundID1; @@ -542,7 +544,7 @@ void WeatherManager::update(float duration, bool paused) mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); else { - mThunderChanceNeeded = static_cast(rand() % 100); + mThunderChanceNeeded = static_cast(OEngine::Misc::Rng::rollDice(100)); mThunderChance = 0; mRendering->getSkyManager()->setLightningStrength( 0.f ); } @@ -624,7 +626,7 @@ std::string WeatherManager::nextWeather(const ESM::Region* region) const * 70% will be greater than 30 (in theory). */ - int chance = (rand() % 100) + 1; // 1..100 + int chance = OEngine::Misc::Rng::rollDice(100) + 1; // 1..100 int sum = 0; unsigned int i = 0; for (; i < probability.size(); ++i) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ce4b10dfc..013386f8f 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -14,6 +14,8 @@ #include #include +#include + #include #include #include @@ -3133,7 +3135,7 @@ namespace MWWorld const ESM::CreatureLevList* list = getStore().get().find(creatureList); int iNumberCreatures = getStore().get().find("iNumberCreatures")->getInt(); - int numCreatures = static_cast(1 + std::rand() / (static_cast (RAND_MAX)+1) * iNumberCreatures); // [1, iNumberCreatures] + int numCreatures = 1 + OEngine::Misc::Rng::rollDice(iNumberCreatures); // [1, iNumberCreatures] for (int i=0; i(std::rand() / (static_cast (RAND_MAX)+1) * 3); // [0, 2] + int roll = OEngine::Misc::Rng::rollDice(3); // [0, 2] modelName << roll; std::string model = "meshes\\" + getFallback()->getFallbackString(modelName.str()); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 971897619..38fcd88e3 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -160,7 +160,11 @@ include_directories(${BULLET_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS} ${ESM_UI_HDR}) -target_link_libraries(components ${Boost_LIBRARIES} ${OGRE_LIBRARIES}) +target_link_libraries(components + ${Boost_LIBRARIES} + ${OGRE_LIBRARIES} + ${OENGINE_LIBRARY} +) if (GIT_CHECKOUT) add_dependencies (components git-version) diff --git a/components/nifogre/particles.cpp b/components/nifogre/particles.cpp index 4fec2d29e..936bfb435 100644 --- a/components/nifogre/particles.cpp +++ b/components/nifogre/particles.cpp @@ -12,6 +12,8 @@ #include #include +#include + /* FIXME: "Nif" isn't really an appropriate emitter name. */ class NifEmitter : public Ogre::ParticleEmitter { @@ -171,7 +173,7 @@ public: Ogre::Real& timeToLive = particle->timeToLive; #endif - Ogre::Node* emitterBone = mEmitterBones.at((int)(::rand()/(RAND_MAX+1.0)*mEmitterBones.size())); + Ogre::Node* emitterBone = mEmitterBones.at(OEngine::Misc::Rng::rollDice(mEmitterBones.size())); position = xOff + yOff + zOff + mParticleBone->_getDerivedOrientation().Inverse() * (emitterBone->_getDerivedPosition() diff --git a/libs/openengine/CMakeLists.txt b/libs/openengine/CMakeLists.txt index 7a0a791d1..3542becf6 100644 --- a/libs/openengine/CMakeLists.txt +++ b/libs/openengine/CMakeLists.txt @@ -23,7 +23,12 @@ set(OENGINE_BULLET bullet/trace.h ) -set(OENGINE_ALL ${OENGINE_OGRE} ${OENGINE_GUI} ${OENGINE_BULLET}) +set(OENGINE_MISC + misc/rng.cpp + misc/rng.hpp +) + +set(OENGINE_ALL ${OENGINE_OGRE} ${OENGINE_GUI} ${OENGINE_BULLET} ${OENGINE_MISC}) set(OENGINE_LIBRARY "oengine") set(OENGINE_LIBRARY ${OENGINE_LIBRARY} PARENT_SCOPE) diff --git a/libs/openengine/misc/rng.cpp b/libs/openengine/misc/rng.cpp new file mode 100644 index 000000000..140aa337e --- /dev/null +++ b/libs/openengine/misc/rng.cpp @@ -0,0 +1,29 @@ +#include "rng.hpp" +#include +#include + +namespace OEngine { +namespace Misc { + + void Rng::init() + { + std::srand(static_cast(std::time(NULL))); + } + + float Rng::rollProbability() + { + return static_cast(std::rand() / (static_cast(RAND_MAX)+1.0)); + } + + float Rng::rollClosedProbability() + { + return static_cast(std::rand() / static_cast(RAND_MAX)); + } + + int Rng::rollDice(int max) + { + return static_cast((std::rand() / (static_cast(RAND_MAX)+1.0)) * (max)); + } + +} +} \ No newline at end of file diff --git a/libs/openengine/misc/rng.hpp b/libs/openengine/misc/rng.hpp new file mode 100644 index 000000000..4e1da17e1 --- /dev/null +++ b/libs/openengine/misc/rng.hpp @@ -0,0 +1,36 @@ +#ifndef MISC_RNG_H +#define MISC_RNG_H + +#include + +namespace OEngine { +namespace Misc +{ + +/* + Provides central implementation of the RNG logic +*/ +class Rng +{ +public: + + /// seed the RNG + static void init(); + + /// return value in range [0.0f, 1.0f) <- note open upper range. + static float rollProbability(); + + /// return value in range [0.0f, 1.0f] <- note closed upper range. + static float rollClosedProbability(); + + /// return value in range [0, max) <- note open upper range. + static int rollDice(int max); + + /// return value in range [0, 99] + static int roll0to99() { return rollDice(100); } +}; + +} +} + +#endif diff --git a/libs/openengine/ogre/selectionbuffer.cpp b/libs/openengine/ogre/selectionbuffer.cpp index 87b85732b..741b672ff 100644 --- a/libs/openengine/ogre/selectionbuffer.cpp +++ b/libs/openengine/ogre/selectionbuffer.cpp @@ -10,6 +10,8 @@ #include +#include + #include namespace OEngine @@ -145,7 +147,7 @@ namespace Render void SelectionBuffer::getNextColour () { - Ogre::ARGB color = static_cast((float(rand()) / float(RAND_MAX)) * std::numeric_limits::max()); + Ogre::ARGB color = static_cast(OEngine::Misc::Rng::rollClosedProbability() * std::numeric_limits::max()); if (mCurrentColour.getAsARGB () == color) { From a418b709370e23df0d3b0612ff93a666032387eb Mon Sep 17 00:00:00 2001 From: sylar Date: Sun, 15 Mar 2015 21:15:58 +0400 Subject: [PATCH 627/740] command line support for Android --- apps/openmw/CMakeLists.txt | 1 + apps/openmw/android_commandLine.cpp | 18 +++++++++++++ apps/openmw/android_commandLine.h | 16 ++++++++++++ apps/openmw/android_main.c | 40 ++++++++++++----------------- 4 files changed, 52 insertions(+), 23 deletions(-) create mode 100644 apps/openmw/android_commandLine.cpp create mode 100644 apps/openmw/android_commandLine.h diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 860cc2fcb..a183d172d 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -7,6 +7,7 @@ set(GAME ) if (ANDROID) + set(GAME ${GAME} android_commandLine.cpp) set(GAME ${GAME} android_main.c) endif() diff --git a/apps/openmw/android_commandLine.cpp b/apps/openmw/android_commandLine.cpp new file mode 100644 index 000000000..bb95a0534 --- /dev/null +++ b/apps/openmw/android_commandLine.cpp @@ -0,0 +1,18 @@ +#include "android_commandLine.h" +#include "string.h" + + const char *argvData[15]; + int argcData; + +JNIEXPORT void JNICALL Java_ui_activity_GameActivity_commandLine(JNIEnv *env, + jobject obj, jint argc, jobjectArray stringArray) { + jboolean iscopy; + argcData = (int) argc; + argvData[0]="openmw"; + for (int i = 0; i < argcData; i++) { + jstring string = (jstring) (*env).GetObjectArrayElement(stringArray, i); + argvData[i+1] = (env)->GetStringUTFChars(string, &iscopy); + } + +} + diff --git a/apps/openmw/android_commandLine.h b/apps/openmw/android_commandLine.h new file mode 100644 index 000000000..21d1064c6 --- /dev/null +++ b/apps/openmw/android_commandLine.h @@ -0,0 +1,16 @@ + + +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +#ifndef _Included_ui_activity_GameActivity_commandLine +#define _Included_ui_activity_GameActivity_commandLine +#ifdef __cplusplus +extern "C" { +#endif + +JNIEXPORT void JNICALL Java_ui_activity_GameActivity_commandLine(JNIEnv *env, jobject obj,jint argcData, jobjectArray stringArray); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/apps/openmw/android_main.c b/apps/openmw/android_main.c index 76da91c4f..0cfb8dcfa 100644 --- a/apps/openmw/android_main.c +++ b/apps/openmw/android_main.c @@ -1,42 +1,36 @@ - #include "../../SDL_internal.h" #ifdef __ANDROID__ #include "SDL_main.h" - /******************************************************************************* - Functions called by JNI -*******************************************************************************/ + Functions called by JNI + *******************************************************************************/ #include /* Called before to initialize JNI bindings */ - - extern void SDL_Android_Init(JNIEnv* env, jclass cls); +extern int argcData; +extern const char *argvData[15]; + +int Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jclass cls, + jobject obj) { + + SDL_Android_Init(env, cls); + + SDL_SetMainReady(); + /* Run the application code! */ -int Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jclass cls, jobject obj) -{ - - SDL_Android_Init(env, cls); - - SDL_SetMainReady(); + int status; - -/* Run the application code! */ - - int status; - char *argv[2]; - argv[0] = SDL_strdup("openmw"); - argv[1] = NULL; - status = main(1, argv); + status = main(argcData+1, argvData); - /* Do not issue an exit or the whole application will terminate instead of just the SDL thread */ - /* exit(status); */ + /* Do not issue an exit or the whole application will terminate instead of just the SDL thread */ + /* exit(status); */ - return status; + return status; } #endif /* __ANDROID__ */ From 48e2ec2840a1f3d16fa5e90d9b70bae95f770aaa Mon Sep 17 00:00:00 2001 From: Nathan Aclander Date: Sun, 15 Mar 2015 16:20:17 -0700 Subject: [PATCH 628/740] Fix comparison of integers of different signs Clang reported comparison of unsigned long with long. This cast should fix it. --- components/bsa/bsa_file.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bsa/bsa_file.cpp b/components/bsa/bsa_file.cpp index 0d60f4cf0..3bf73ede2 100644 --- a/components/bsa/bsa_file.cpp +++ b/components/bsa/bsa_file.cpp @@ -111,7 +111,7 @@ void BSAFile::readHeader() // Each file must take up at least 21 bytes of data in the bsa. So // if files*21 overflows the file size then we are guaranteed that // the archive is corrupt. - if((filenum*21 > fsize -12) || (dirsize+8*filenum > fsize -12) ) + if((filenum*21 > unsigned(fsize -12)) || (dirsize+8*filenum > unsigned(fsize -12)) ) fail("Directory information larger than entire archive"); // Read the offset info into a temporary buffer From 4d0bb6329a17d0f3d66ae885342d00be842a6221 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 16 Mar 2015 01:50:57 +0100 Subject: [PATCH 629/740] Fix incorrect reference check This check was broken for exterior cells (empty cell id). It was superfluous anyway. A CellRef is owned by the cell it is in, so the cell must always exist. --- apps/opencs/model/tools/referencecheck.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/apps/opencs/model/tools/referencecheck.cpp b/apps/opencs/model/tools/referencecheck.cpp index 68de87d80..198c3627f 100644 --- a/apps/opencs/model/tools/referencecheck.cpp +++ b/apps/opencs/model/tools/referencecheck.cpp @@ -48,10 +48,6 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message } } - // Check if referenced object is in valid cell - if (mCells.searchId(cellRef.mCell) == -1) - messages.push_back(std::make_pair(id, " is referencing object from non existing cell " + cellRef.mCell)); - // If object have owner, check if that owner reference is valid if (!cellRef.mOwner.empty() && mReferencables.searchId(cellRef.mOwner) == -1) messages.push_back(std::make_pair(id, " has non existing owner " + cellRef.mOwner)); From 295ca86ac1f28414186d6785713d8fa7c283f519 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 16 Mar 2015 02:43:02 +0100 Subject: [PATCH 630/740] OpenCS FileDialog crash fix The file dialog would crash when no game file is selected and an addon file with no dependency is checked, then unchecked. --- apps/opencs/view/doc/filedialog.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/doc/filedialog.cpp b/apps/opencs/view/doc/filedialog.cpp index 8dd83f24a..1b3196112 100644 --- a/apps/opencs/view/doc/filedialog.cpp +++ b/apps/opencs/view/doc/filedialog.cpp @@ -153,11 +153,13 @@ void CSVDoc::FileDialog::slotUpdateAcceptButton(const QString &name, bool) if (isNew) success = success && !(name.isEmpty()); - else + else if (success) { ContentSelectorModel::EsmFile *file = mSelector->selectedFiles().back(); mAdjusterWidget->setName (file->filePath(), !file->isGameFile()); } + else + mAdjusterWidget->setName ("", true); ui.projectButtonBox->button (QDialogButtonBox::Ok)->setEnabled (success); } From 6ff2523d8ada97b45333a30831817a674fe915e4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 16 Mar 2015 03:07:37 +0100 Subject: [PATCH 631/740] Fix for line focus when clicking on a verifier script error - setFocus() on the script editor, otherwise setting the text cursor has no effect. - setFocus() must be done after the widgets are created/shown, or the newly created widgets will "steal" the focus again. - Missing useHint in case subviews are reused. --- apps/opencs/view/doc/view.cpp | 7 +++++-- apps/opencs/view/world/scriptsubview.cpp | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 211f74187..5d42902e8 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -485,6 +485,8 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin (!isReferenceable && id == sb->getUniversalId())) { sb->setFocus(); + if (!hint.empty()) + sb->useHint (hint); return; } } @@ -515,8 +517,6 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin assert(view); view->setParent(this); mSubViews.append(view); // only after assert - if (!hint.empty()) - view->useHint (hint); int minWidth = userSettings.setting ("window/minimum-width", QString("325")).toInt(); view->setMinimumWidth(minWidth); @@ -538,6 +538,9 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin this, SLOT (updateSubViewIndicies (SubView *))); view->show(); + + if (!hint.empty()) + view->useHint (hint); } void CSVDoc::View::newView() diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 9b50a61f8..211462a26 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -68,6 +68,7 @@ void CSVWorld::ScriptSubView::useHint (const std::string& hint) if (cursor.movePosition (QTextCursor::Down, QTextCursor::MoveAnchor, line)) cursor.movePosition (QTextCursor::Right, QTextCursor::MoveAnchor, column); + mEditor->setFocus(); mEditor->setTextCursor (cursor); } } From 76adb64e20f90d58d53e43aa2d2587ea89992924 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 16 Mar 2015 13:21:02 +1100 Subject: [PATCH 632/740] Compilation fix after merging commt e30f24 --- apps/opencs/model/world/nestedadaptors.hpp | 134 ++++++++++----------- 1 file changed, 66 insertions(+), 68 deletions(-) diff --git a/apps/opencs/model/world/nestedadaptors.hpp b/apps/opencs/model/world/nestedadaptors.hpp index 6e3d447b2..cc062e827 100644 --- a/apps/opencs/model/world/nestedadaptors.hpp +++ b/apps/opencs/model/world/nestedadaptors.hpp @@ -34,16 +34,16 @@ namespace CSMWorld public: HelperBase(CSMWorld::UniversalId::Type type); - + virtual ~HelperBase(); - + virtual void setNestedTable(RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) = 0; - + virtual NestedTableWrapperBase* nestedTable(const RefIdData& data, int index) const = 0; - + virtual QVariant getNestedData(const CSMWorld::RefIdData& data, int index, int subRowIndex, @@ -58,7 +58,7 @@ namespace CSMWorld const QVariant& value, int subRowIndex, int subColIndex) const = 0; - + virtual void addNestedRow (RefIdData& data, int index, int position) const = 0; @@ -72,7 +72,7 @@ namespace CSMWorld template class CastableHelper : public HelperBase { - + public: CastableHelper(CSMWorld::UniversalId::Type type) : HelperBase(type) {} @@ -96,23 +96,23 @@ namespace CSMWorld { public: - SpellsHelper(CSMWorld::UniversalId::Type type) + SpellsHelper(CSMWorld::UniversalId::Type type) : CastableHelper(type) {} virtual void setNestedTable(RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) { - CastableHelper::getRecord(data, index).get().mSpells.mList = + CastableHelper::getRecord(data, index).get().mSpells.mList = (static_cast >&>(nestedTable)).mNestedTable; } - + virtual NestedTableWrapperBase* nestedTable(const RefIdData& data, int index) const { return new NestedTableWrapper >(CastableHelper::getRecord(data, index).get().mSpells.mList); } - + virtual QVariant getNestedData(const CSMWorld::RefIdData& data, int index, int subRowIndex, @@ -124,7 +124,7 @@ namespace CSMWorld { return QString::fromUtf8(content.c_str()); } - + throw std::logic_error("Trying to access non-existing column in the nested table!"); } @@ -144,11 +144,11 @@ namespace CSMWorld if (subColIndex == 0) { CastableHelper::getRecord(data, index).get().mSpells.mList.at(subRowIndex) = std::string(value.toString().toUtf8()); - } + } throw std::logic_error("Trying to access non-existing column in the nested table!"); } - + virtual void addNestedRow (RefIdData& data, int index, int position) const { std::vector& list = CastableHelper::getRecord(data, index).get().mSpells.mList; @@ -159,15 +159,15 @@ namespace CSMWorld list.push_back(newString); return; } - + list.insert(list.begin()+position, newString); } - + virtual int getNestedColumnsCount(const RefIdData& data) const { return 1; } - + virtual int getNestedRowsCount(const RefIdData& data, int index) const @@ -183,23 +183,23 @@ namespace CSMWorld { public: - MagicEffectsHelper(CSMWorld::UniversalId::Type type) + MagicEffectsHelper(CSMWorld::UniversalId::Type type) : CastableHelper(type) {} virtual void setNestedTable(RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) { - CastableHelper::getRecord(data, index).get().mEffects = + CastableHelper::getRecord(data, index).get().mEffects = (static_cast&>(nestedTable)).mNestedTable; } - + virtual NestedTableWrapperBase* nestedTable(const RefIdData& data, int index) const { return new NestedTableWrapper(CastableHelper::getRecord(data, index).get().mEffects); } - + virtual QVariant getNestedData(const CSMWorld::RefIdData& data, int index, int subRowIndex, @@ -211,7 +211,7 @@ namespace CSMWorld { case 0: return content.at(subRowIndex).mEffectID; - + case 1: return content.at(subRowIndex).mRange; @@ -226,13 +226,13 @@ namespace CSMWorld case 5: return content.at(subRowIndex).mMagMax; - + case 6: return (int)content.at(rubRowIndex).mSkill; case 7: return (int)content.at(subRowIndex).mAttribute; - + default: throw std::logic_error("Trying to access non-existing column in the nested table!"); } @@ -261,10 +261,10 @@ namespace CSMWorld throw std::logic_error("Trying to access non-existing column in the nested table!"); } } - + virtual void addNestedRow (RefIdData& data, int index, int position) const { - std::vector& list = CastableHelper::getRecord(data, index).get().mTransport; + std::vector& list = CastableHelper::getRecord(data, index).get().mTransport.mList; ESM::Position newPos; for (unsigned i = 0; i < 3; ++i) @@ -273,7 +273,7 @@ namespace CSMWorld newPos.rot[i] = 0; } - ESM::NPC::Dest newRow; + ESM::Transport::Dest newRow; newRow.mPos = newPos; newRow.mCellName = ""; @@ -282,20 +282,20 @@ namespace CSMWorld list.push_back(newRow); return; } - + list.insert(list.begin()+position, newRow); } - + virtual int getNestedColumnsCount(const RefIdData& data) const { return 7; } - + virtual int getNestedRowsCount(const RefIdData& data, int index) const { - return CastableHelper::getRecord(data, index).get().mTransport.size(); + return CastableHelper::getRecord(data, index).get().mTransport.mList.size(); } }; @@ -305,35 +305,35 @@ namespace CSMWorld { public: - DestinationsHelper(CSMWorld::UniversalId::Type type) + DestinationsHelper(CSMWorld::UniversalId::Type type) : CastableHelper(type) {} virtual void setNestedTable(RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) { - CastableHelper::getRecord(data, index).get().mTransport = - (static_cast >&>(nestedTable)).mNestedTable; + CastableHelper::getRecord(data, index).get().mTransport.mList = + (static_cast >&>(nestedTable)).mNestedTable; } - + virtual NestedTableWrapperBase* nestedTable(const RefIdData& data, int index) const { - return new NestedTableWrapper >(CastableHelper::getRecord(data, index).get().mTransport); + return new NestedTableWrapper >(CastableHelper::getRecord(data, index).get().mTransport.mList); } - + virtual QVariant getNestedData(const CSMWorld::RefIdData& data, int index, int subRowIndex, int subColIndex) const { - const ESM::NPC::Dest& content = CastableHelper::getRecord(data, index).get().mTransport.at(subRowIndex); + const ESM::Transport::Dest& content = CastableHelper::getRecord(data, index).get().mTransport.mList.at(subRowIndex); switch (subColIndex) { case 0: return QString::fromUtf8(content.mCellName.c_str()); - + case 1: return content.mPos.pos[0]; @@ -351,7 +351,7 @@ namespace CSMWorld case 6: return content.mPos.rot[2]; - + default: throw std::logic_error("Trying to access non-existing column in the nested table!"); } @@ -359,7 +359,7 @@ namespace CSMWorld virtual void removeNestedRow (RefIdData& data, int index, int rowToRemove) const { - std::vector& list = CastableHelper::getRecord(data, index).get().mTransport; + std::vector& list = CastableHelper::getRecord(data, index).get().mTransport.mList; list.erase (list.begin () + rowToRemove); } @@ -373,41 +373,41 @@ namespace CSMWorld switch(subColIndex) { case 0: - CastableHelper::getRecord(data, index).get().mTransport.at(subRowIndex).mCellName = std::string(value.toString().toUtf8().constData()); + CastableHelper::getRecord(data, index).get().mTransport.mList.at(subRowIndex).mCellName = std::string(value.toString().toUtf8().constData()); break; case 1: - CastableHelper::getRecord(data, index).get().mTransport.at(subRowIndex).mPos.pos[0] = value.toFloat(); + CastableHelper::getRecord(data, index).get().mTransport.mList.at(subRowIndex).mPos.pos[0] = value.toFloat(); break; - + case 2: - CastableHelper::getRecord(data, index).get().mTransport.at(subRowIndex).mPos.pos[1] = value.toFloat(); + CastableHelper::getRecord(data, index).get().mTransport.mList.at(subRowIndex).mPos.pos[1] = value.toFloat(); break; - + case 3: - CastableHelper::getRecord(data, index).get().mTransport.at(subRowIndex).mPos.pos[2] = value.toFloat(); + CastableHelper::getRecord(data, index).get().mTransport.mList.at(subRowIndex).mPos.pos[2] = value.toFloat(); break; - + case 4: - CastableHelper::getRecord(data, index).get().mTransport.at(subRowIndex).mPos.rot[0] = value.toFloat(); + CastableHelper::getRecord(data, index).get().mTransport.mList.at(subRowIndex).mPos.rot[0] = value.toFloat(); break; case 5: - CastableHelper::getRecord(data, index).get().mTransport.at(subRowIndex).mPos.rot[1] = value.toFloat(); + CastableHelper::getRecord(data, index).get().mTransport.mList.at(subRowIndex).mPos.rot[1] = value.toFloat(); break; case 6: - CastableHelper::getRecord(data, index).get().mTransport.at(subRowIndex).mPos.rot[2] = value.toFloat(); + CastableHelper::getRecord(data, index).get().mTransport.mList.at(subRowIndex).mPos.rot[2] = value.toFloat(); break; default: throw std::logic_error("Trying to access non-existing column in the nested table!"); } } - + virtual void addNestedRow (RefIdData& data, int index, int position) const { - std::vector& list = CastableHelper::getRecord(data, index).get().mTransport; + std::vector& list = CastableHelper::getRecord(data, index).get().mTransport.mList; ESM::Position newPos; for (unsigned i = 0; i < 3; ++i) @@ -416,7 +416,7 @@ namespace CSMWorld newPos.rot[i] = 0; } - ESM::NPC::Dest newRow; + ESM::Transport::Dest newRow; newRow.mPos = newPos; newRow.mCellName = ""; @@ -425,20 +425,19 @@ namespace CSMWorld list.push_back(newRow); return; } - + list.insert(list.begin()+position, newRow); } - + virtual int getNestedColumnsCount(const RefIdData& data) const { return 7; } - virtual int getNestedRowsCount(const RefIdData& data, int index) const { - return CastableHelper::getRecord(data, index).get().mTransport.size(); + return CastableHelper::getRecord(data, index).get().mTransport.mList.size(); } }; @@ -448,23 +447,23 @@ namespace CSMWorld { public: - InventoryHelper(CSMWorld::UniversalId::Type type) + InventoryHelper(CSMWorld::UniversalId::Type type) : CastableHelper(type) {} virtual void setNestedTable(RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) { - CastableHelper::getRecord(data, index).get().mInventory.mList = + CastableHelper::getRecord(data, index).get().mInventory.mList = (static_cast >&>(nestedTable)).mNestedTable; } - + virtual NestedTableWrapperBase* nestedTable(const RefIdData& data, int index) const { return new NestedTableWrapper >(CastableHelper::getRecord(data, index).get().mInventory.mList); } - + virtual QVariant getNestedData(const CSMWorld::RefIdData& data, int index, int subRowIndex, @@ -476,10 +475,10 @@ namespace CSMWorld { case 0: return QString::fromUtf8(content.mItem.toString().c_str()); - + case 1: return content.mCount; - + default: throw std::logic_error("Trying to access non-existing column in the nested table!"); } @@ -507,12 +506,12 @@ namespace CSMWorld case 1: CastableHelper::getRecord(data, index).get().mInventory.mList.at(subRowIndex).mCount = value.toInt(); break; - + default: throw std::logic_error("Trying to access non-existing column in the nested table!"); } } - + virtual void addNestedRow (RefIdData& data, int index, int position) const { std::vector& list = CastableHelper::getRecord(data, index).get().mInventory.mList; @@ -523,15 +522,14 @@ namespace CSMWorld list.push_back(newRow); return; } - + list.insert(list.begin()+position, newRow); } - + virtual int getNestedColumnsCount(const RefIdData& data) const { return 2; } - virtual int getNestedRowsCount(const RefIdData& data, int index) const From bd4e832cf3c691ad027df5326b91226cfcedbe17 Mon Sep 17 00:00:00 2001 From: sylar Date: Mon, 16 Mar 2015 07:41:51 +0400 Subject: [PATCH 633/740] fix memory leaks in emulating command line --- apps/openmw/android_commandLine.cpp | 16 +++++++++------- apps/openmw/android_main.c | 3 ++- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/apps/openmw/android_commandLine.cpp b/apps/openmw/android_commandLine.cpp index bb95a0534..129e63797 100644 --- a/apps/openmw/android_commandLine.cpp +++ b/apps/openmw/android_commandLine.cpp @@ -1,18 +1,20 @@ #include "android_commandLine.h" #include "string.h" - const char *argvData[15]; - int argcData; + + +const char **argvData; +int argcData; JNIEXPORT void JNICALL Java_ui_activity_GameActivity_commandLine(JNIEnv *env, jobject obj, jint argc, jobjectArray stringArray) { jboolean iscopy; argcData = (int) argc; - argvData[0]="openmw"; - for (int i = 0; i < argcData; i++) { - jstring string = (jstring) (*env).GetObjectArrayElement(stringArray, i); - argvData[i+1] = (env)->GetStringUTFChars(string, &iscopy); + argvData= new const char * [argcData+1]; + argvData[0] = "openmw"; + for (int i = 1; i < argcData+1; i++) { + jstring string = (jstring) (*env).GetObjectArrayElement(stringArray, i-1); + argvData[i] = (env)->GetStringUTFChars(string, &iscopy); } - } diff --git a/apps/openmw/android_main.c b/apps/openmw/android_main.c index 0cfb8dcfa..d3a6ca63a 100644 --- a/apps/openmw/android_main.c +++ b/apps/openmw/android_main.c @@ -12,7 +12,7 @@ extern void SDL_Android_Init(JNIEnv* env, jclass cls); extern int argcData; -extern const char *argvData[15]; +extern const char **argvData; int Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jclass cls, jobject obj) { @@ -26,6 +26,7 @@ int Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jclass cls, int status; status = main(argcData+1, argvData); + free (argvData); /* Do not issue an exit or the whole application will terminate instead of just the SDL thread */ /* exit(status); */ From db10c87b8961779ea76f930d1738b36c729cb9de Mon Sep 17 00:00:00 2001 From: sylar Date: Mon, 16 Mar 2015 18:21:38 +0400 Subject: [PATCH 634/740] release jni memory --- apps/openmw/android_commandLine.cpp | 17 ++++++++++++----- apps/openmw/android_main.c | 4 ++-- components/files/androidpath.cpp | 1 + 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/apps/openmw/android_commandLine.cpp b/apps/openmw/android_commandLine.cpp index 129e63797..ebfff28ca 100644 --- a/apps/openmw/android_commandLine.cpp +++ b/apps/openmw/android_commandLine.cpp @@ -1,20 +1,27 @@ #include "android_commandLine.h" #include "string.h" - - const char **argvData; int argcData; +extern "C" void releaseArgv(); + +void releaseArgv() { + delete[] argvData; +} + JNIEXPORT void JNICALL Java_ui_activity_GameActivity_commandLine(JNIEnv *env, jobject obj, jint argc, jobjectArray stringArray) { jboolean iscopy; argcData = (int) argc; - argvData= new const char * [argcData+1]; + argvData = new const char *[argcData + 1]; argvData[0] = "openmw"; - for (int i = 1; i < argcData+1; i++) { - jstring string = (jstring) (*env).GetObjectArrayElement(stringArray, i-1); + for (int i = 1; i < argcData + 1; i++) { + jstring string = (jstring) (env)->GetObjectArrayElement(stringArray, + i - 1); argvData[i] = (env)->GetStringUTFChars(string, &iscopy); + (env)->DeleteLocalRef(string); } + (env)->DeleteLocalRef(stringArray); } diff --git a/apps/openmw/android_main.c b/apps/openmw/android_main.c index d3a6ca63a..1b2839519 100644 --- a/apps/openmw/android_main.c +++ b/apps/openmw/android_main.c @@ -13,6 +13,7 @@ extern void SDL_Android_Init(JNIEnv* env, jclass cls); extern int argcData; extern const char **argvData; +void releaseArgv(); int Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jclass cls, jobject obj) { @@ -26,8 +27,7 @@ int Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jclass cls, int status; status = main(argcData+1, argvData); - free (argvData); - + releaseArgv(); /* Do not issue an exit or the whole application will terminate instead of just the SDL thread */ /* exit(status); */ diff --git a/components/files/androidpath.cpp b/components/files/androidpath.cpp index 009bd98a2..84886f473 100644 --- a/components/files/androidpath.cpp +++ b/components/files/androidpath.cpp @@ -31,6 +31,7 @@ JNIEXPORT void JNICALL Java_ui_activity_GameActivity_getPathToJni(JNIEnv *env, j { jboolean iscopy; Buffer::setData((env)->GetStringUTFChars(prompt, &iscopy)); + (env)->DeleteLocalRef(prompt); } namespace From f7ecda68c92e48779f376f27fb30738ec617dd25 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 16 Mar 2015 15:33:12 +0100 Subject: [PATCH 635/740] Fix for unicode filenames in ContentModel (Fixes #2451) --- components/contentselector/model/contentmodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 3dc02af21..62f6d9014 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -449,7 +449,7 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path) ToUTF8::Utf8Encoder encoder = ToUTF8::calculateEncoding(mEncoding.toStdString()); fileReader.setEncoder(&encoder); - fileReader.open(dir.absoluteFilePath(path).toStdString()); + fileReader.open(std::string(dir.absoluteFilePath(path).toUtf8().constData())); EsmFile *file = new EsmFile(path); From 19e8280f4550b1c3d14ca94c9fcccd7ae90fd1e8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 16 Mar 2015 15:45:41 +0100 Subject: [PATCH 636/740] OpenCS window title unicode fixes --- apps/opencs/view/doc/loader.cpp | 2 +- apps/opencs/view/doc/subview.cpp | 2 +- apps/opencs/view/doc/view.cpp | 2 +- apps/opencs/view/doc/viewmanager.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/doc/loader.cpp b/apps/opencs/view/doc/loader.cpp index 046eb5229..30235d0f5 100644 --- a/apps/opencs/view/doc/loader.cpp +++ b/apps/opencs/view/doc/loader.cpp @@ -20,7 +20,7 @@ void CSVDoc::LoadingDocument::closeEvent (QCloseEvent *event) CSVDoc::LoadingDocument::LoadingDocument (CSMDoc::Document *document) : mDocument (document), mAborted (false), mMessages (0), mTotalRecords (0) { - setWindowTitle (("Opening " + document->getSavePath().filename().string()).c_str()); + setWindowTitle (QString::fromUtf8((std::string("Opening ") + document->getSavePath().filename().string()).c_str())); setMinimumWidth (400); diff --git a/apps/opencs/view/doc/subview.cpp b/apps/opencs/view/doc/subview.cpp index a399b5b5b..df1e7ee49 100644 --- a/apps/opencs/view/doc/subview.cpp +++ b/apps/opencs/view/doc/subview.cpp @@ -26,7 +26,7 @@ void CSVDoc::SubView::updateUserSetting (const QString &, const QStringList &) void CSVDoc::SubView::setUniversalId (const CSMWorld::UniversalId& id) { mUniversalId = id; - setWindowTitle (mUniversalId.toString().c_str()); + setWindowTitle (QString::fromUtf8(mUniversalId.toString().c_str())); } void CSVDoc::SubView::closeEvent (QCloseEvent *event) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 5d42902e8..cf2940b99 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -324,7 +324,7 @@ void CSVDoc::View::updateTitle() if (hideTitle) stream << " - " << mSubViews.at (0)->getTitle(); - setWindowTitle (stream.str().c_str()); + setWindowTitle (QString::fromUtf8(stream.str().c_str())); } void CSVDoc::View::updateSubViewIndicies(SubView *view) diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 5f6b6b46a..9fee26078 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -248,7 +248,7 @@ bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (CSVDoc::View *view) QMessageBox messageBox(view); CSMDoc::Document *document = view->getDocument(); - messageBox.setWindowTitle (document->getSavePath().filename().string().c_str()); + messageBox.setWindowTitle (QString::fromUtf8(document->getSavePath().filename().string().c_str())); messageBox.setText ("The document has been modified."); messageBox.setInformativeText ("Do you want to save your changes?"); messageBox.setStandardButtons (QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); From d5734588964d9d8d7e99142ed72e7c8f60cc819f Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 16 Mar 2015 17:37:54 +0100 Subject: [PATCH 637/740] Fix case sensitivity bug in default head/hair selection (Fixes #2453) --- apps/openmw/mwgui/race.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 97dbfbafc..f908a9dd0 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -142,13 +142,13 @@ namespace MWGui for (unsigned int i=0; i Date: Tue, 17 Mar 2015 12:30:47 +0100 Subject: [PATCH 638/740] setting up global search operation and subview --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/doc/document.cpp | 6 +++++ apps/opencs/model/doc/document.hpp | 2 ++ apps/opencs/model/doc/state.hpp | 2 +- apps/opencs/model/tools/tools.cpp | 23 +++++++++++++--- apps/opencs/model/tools/tools.hpp | 5 ++++ apps/opencs/model/world/universalid.cpp | 1 + apps/opencs/model/world/universalid.hpp | 1 + apps/opencs/view/doc/view.cpp | 9 +++++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/tools/searchsubview.cpp | 23 ++++++++++++++++ apps/opencs/view/tools/searchsubview.hpp | 34 ++++++++++++++++++++++++ apps/opencs/view/tools/subviews.cpp | 3 +++ 13 files changed, 108 insertions(+), 5 deletions(-) create mode 100644 apps/opencs/view/tools/searchsubview.cpp create mode 100644 apps/opencs/view/tools/searchsubview.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index e618d2961..e3b44ac91 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -91,7 +91,7 @@ opencs_hdrs_noqt (view/render opencs_units (view/tools - reportsubview reporttable + reportsubview reporttable searchsubview ) opencs_units_noqt (view/tools diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 7d27143b4..a06eb0ebf 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2374,6 +2374,12 @@ CSMWorld::UniversalId CSMDoc::Document::verify() return id; } + +CSMWorld::UniversalId CSMDoc::Document::newSearch() +{ + return mTools.newSearch(); +} + void CSMDoc::Document::abortOperation (int type) { if (type==State_Saving) diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 1f96b44a1..4300a9c64 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -120,6 +120,8 @@ namespace CSMDoc CSMWorld::UniversalId verify(); + CSMWorld::UniversalId newSearch(); + void abortOperation (int type); const CSMWorld::Data& getData() const; diff --git a/apps/opencs/model/doc/state.hpp b/apps/opencs/model/doc/state.hpp index 287439a8b..78f468101 100644 --- a/apps/opencs/model/doc/state.hpp +++ b/apps/opencs/model/doc/state.hpp @@ -13,7 +13,7 @@ namespace CSMDoc State_Saving = 16, State_Verifying = 32, State_Compiling = 64, // not implemented yet - State_Searching = 128, // not implemented yet + State_Searching = 128, State_Loading = 256 // pseudo-state; can not be encountered in a loaded document }; } diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 170ea8ccd..07bd4205b 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -31,6 +31,7 @@ CSMDoc::OperationHolder *CSMTools::Tools::get (int type) switch (type) { case CSMDoc::State_Verifying: return &mVerifier; + case CSMDoc::State_Searching: return &mSearch; } return 0; @@ -101,7 +102,8 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() } CSMTools::Tools::Tools (CSMDoc::Document& document) -: mDocument (document), mData (document.getData()), mVerifierOperation (0), mNextReportNumber (0) +: mDocument (document), mData (document.getData()), mVerifierOperation (0), mNextReportNumber (0), + mSearchOperation (0) { // index 0: load error log mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel)); @@ -116,6 +118,12 @@ CSMTools::Tools::~Tools() delete mVerifierOperation; } + if (mSearchOperation) + { + mSearch.abortAndWait(); + delete mSearchOperation; + } + for (std::map::iterator iter (mReports.begin()); iter!=mReports.end(); ++iter) delete iter->second; } @@ -130,6 +138,13 @@ CSMWorld::UniversalId CSMTools::Tools::runVerifier() return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_VerificationResults, mNextReportNumber-1); } +CSMWorld::UniversalId CSMTools::Tools::newSearch() +{ + mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel)); + + return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Search, mNextReportNumber-1); +} + void CSMTools::Tools::abortOperation (int type) { if (CSMDoc::OperationHolder *operation = get (type)) @@ -141,6 +156,7 @@ int CSMTools::Tools::getRunningOperations() const static const int sOperations[] = { CSMDoc::State_Verifying, + CSMDoc::State_Searching, -1 }; @@ -157,9 +173,10 @@ int CSMTools::Tools::getRunningOperations() const CSMTools::ReportModel *CSMTools::Tools::getReport (const CSMWorld::UniversalId& id) { if (id.getType()!=CSMWorld::UniversalId::Type_VerificationResults && - id.getType()!=CSMWorld::UniversalId::Type_LoadErrorLog) + id.getType()!=CSMWorld::UniversalId::Type_LoadErrorLog && + id.getType()!=CSMWorld::UniversalId::Type_Search) throw std::logic_error ("invalid request for report model: " + id.toString()); - + return mReports.at (id.getIndex()); } diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp index b8ded8a83..bd27767a6 100644 --- a/apps/opencs/model/tools/tools.hpp +++ b/apps/opencs/model/tools/tools.hpp @@ -31,6 +31,8 @@ namespace CSMTools CSMWorld::Data& mData; CSMDoc::Operation *mVerifierOperation; CSMDoc::OperationHolder mVerifier; + CSMDoc::Operation *mSearchOperation; + CSMDoc::OperationHolder mSearch; std::map mReports; int mNextReportNumber; std::map mActiveReports; // type, report number @@ -56,6 +58,9 @@ namespace CSMTools CSMWorld::UniversalId runVerifier(); ///< \return ID of the report for this verification run + /// Return ID of the report for this search. + CSMWorld::UniversalId newSearch(); + void abortOperation (int type); ///< \attention The operation is not aborted immediately. diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 50ac846db..6aa129f25 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -128,6 +128,7 @@ namespace { { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_VerificationResults, "Verification Results", 0 }, { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_LoadErrorLog, "Load Error Log", 0 }, + { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_Search, "Global Search", 0 }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker }; } diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index a716aec03..f01e811ca 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -130,6 +130,7 @@ namespace CSMWorld Type_Pathgrid, Type_StartScripts, Type_StartScript, + Type_Search, Type_RunLog }; diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 211f74187..3cabd8737 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -113,6 +113,10 @@ void CSVDoc::View::setupViewMenu() QAction *filters = new QAction (tr ("Filters"), this); connect (filters, SIGNAL (triggered()), this, SLOT (addFiltersSubView())); view->addAction (filters); + + QAction *search = new QAction (tr ("Search"), this); + connect (search, SIGNAL (triggered()), this, SLOT (addSearchSubView())); + view->addAction (search); } void CSVDoc::View::setupWorldMenu() @@ -725,6 +729,11 @@ void CSVDoc::View::addStartScriptsSubView() addSubView (CSMWorld::UniversalId::Type_StartScripts); } +void CSVDoc::View::addSearchSubView() +{ + addSubView (mDocument->newSearch()); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index baadca85c..32d7159c2 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -217,6 +217,8 @@ namespace CSVDoc void addStartScriptsSubView(); + void addSearchSubView(); + void toggleShowStatusBar (bool show); void loadErrorLog(); diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp new file mode 100644 index 000000000..7173a6634 --- /dev/null +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -0,0 +1,23 @@ + +#include "searchsubview.hpp" + +#include "reporttable.hpp" + +CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) +: CSVDoc::SubView (id) +{ + setWidget (mTable = new ReportTable (document, id, this)); + + connect (mTable, SIGNAL (editRequest (const CSMWorld::UniversalId&, const std::string&)), + SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&))); +} + +void CSVTools::SearchSubView::setEditLock (bool locked) +{ + // ignored. We don't change document state anyway. +} + +void CSVTools::SearchSubView::updateUserSetting (const QString &name, const QStringList &list) +{ + mTable->updateUserSetting (name, list); +} diff --git a/apps/opencs/view/tools/searchsubview.hpp b/apps/opencs/view/tools/searchsubview.hpp new file mode 100644 index 000000000..abedd5e6d --- /dev/null +++ b/apps/opencs/view/tools/searchsubview.hpp @@ -0,0 +1,34 @@ +#ifndef CSV_TOOLS_SEARCHSUBVIEW_H +#define CSV_TOOLS_SEARCHSUBVIEW_H + +#include "../doc/subview.hpp" + +class QTableView; +class QModelIndex; + +namespace CSMDoc +{ + class Document; +} + +namespace CSVTools +{ + class ReportTable; + + class SearchSubView : public CSVDoc::SubView + { + Q_OBJECT + + ReportTable *mTable; + + public: + + SearchSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); + + virtual void setEditLock (bool locked); + + virtual void updateUserSetting (const QString &, const QStringList &); + }; +} + +#endif diff --git a/apps/opencs/view/tools/subviews.cpp b/apps/opencs/view/tools/subviews.cpp index a50b5724a..8a343ebe8 100644 --- a/apps/opencs/view/tools/subviews.cpp +++ b/apps/opencs/view/tools/subviews.cpp @@ -4,6 +4,7 @@ #include "../doc/subviewfactoryimp.hpp" #include "reportsubview.hpp" +#include "searchsubview.hpp" void CSVTools::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) { @@ -11,4 +12,6 @@ void CSVTools::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) new CSVDoc::SubViewFactory); manager.add (CSMWorld::UniversalId::Type_LoadErrorLog, new CSVDoc::SubViewFactory); + manager.add (CSMWorld::UniversalId::Type_Search, + new CSVDoc::SubViewFactory); } From 3e45e9a48a196d3199d54a949c663b2349b6e58c Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Wed, 18 Mar 2015 23:37:54 +0200 Subject: [PATCH 639/740] Remove no longer required strnlen wrapper It was used for MinGW & OS X < 10.7. Minimal OS X version was bumped to 10.7 and MinGW support was recently dropped (see 1eaa64c49caeb753facf36c5173d5236c1f969e0). --- components/esm/esmcommon.hpp | 2 +- components/esm/esmreader.hpp | 2 +- libs/platform/string.h | 34 ---------------------------------- 3 files changed, 2 insertions(+), 36 deletions(-) delete mode 100644 libs/platform/string.h diff --git a/components/esm/esmcommon.hpp b/components/esm/esmcommon.hpp index 54b18aeaf..d90a3444d 100644 --- a/components/esm/esmcommon.hpp +++ b/components/esm/esmcommon.hpp @@ -5,7 +5,7 @@ #include #include -#include +#include namespace ESM { diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index ebbc935f6..2df2a86b3 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -2,7 +2,7 @@ #define OPENMW_ESM_READER_H #include -#include +#include #include #include #include diff --git a/libs/platform/string.h b/libs/platform/string.h deleted file mode 100644 index 5368d757c..000000000 --- a/libs/platform/string.h +++ /dev/null @@ -1,34 +0,0 @@ -// Wrapper for string.h on Mac and MinGW -#ifndef _STRING_WRAPPER_H -#define _STRING_WRAPPER_H - -#ifdef __APPLE__ -#include -#endif - -#include -#if (defined(__APPLE__) && __MAC_OS_X_VERSION_MIN_REQUIRED < 1070) || defined(__MINGW32__) -// need our own implementation of strnlen -#ifdef __MINGW32__ -static size_t strnlen(const char *s, size_t n) -{ - const char *p = (const char *)memchr(s, 0, n); - return(p ? p-s : n); -} -#elif (defined(__APPLE__) && __MAC_OS_X_VERSION_MIN_REQUIRED < 1070) -static size_t mw_strnlen(const char *s, size_t n) -{ - if (strnlen != NULL) { - return strnlen(s, n); - } - else { - const char *p = (const char *)memchr(s, 0, n); - return(p ? p-s : n); - } -} -#define strnlen mw_strnlen -#endif - -#endif - -#endif From af2b08214bacc528b66fa6047ef941a7f7208668 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Wed, 18 Mar 2015 23:48:03 +0200 Subject: [PATCH 640/740] #2460: use Application Support as user data path on OS X --- components/files/macospath.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/components/files/macospath.cpp b/components/files/macospath.cpp index 3e53f5306..6e794796f 100644 --- a/components/files/macospath.cpp +++ b/components/files/macospath.cpp @@ -7,10 +7,6 @@ #include #include -/** - * FIXME: Someone with MacOS system should check this and correct if necessary - */ - namespace { boost::filesystem::path getUserHome() @@ -49,9 +45,8 @@ boost::filesystem::path MacOsPath::getUserConfigPath() const boost::filesystem::path MacOsPath::getUserDataPath() const { - // TODO: probably wrong? boost::filesystem::path userPath (getUserHome()); - userPath /= "Library/Preferences/"; + userPath /= "Library/Application Support/"; return userPath / mName; } From 413b35de6c8ab3cfccc13965aaef2c20bf3b7f01 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 19 Mar 2015 21:03:24 +0100 Subject: [PATCH 641/740] moved search menu item from view to edit --- apps/opencs/view/doc/view.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 3cabd8737..533cab049 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -91,6 +91,10 @@ void CSVDoc::View::setupEditMenu() QAction *userSettings = new QAction (tr ("&Preferences"), this); connect (userSettings, SIGNAL (triggered()), this, SIGNAL (editSettingsRequest())); edit->addAction (userSettings); + + QAction *search = new QAction (tr ("Search"), this); + connect (search, SIGNAL (triggered()), this, SLOT (addSearchSubView())); + edit->addAction (search); } void CSVDoc::View::setupViewMenu() @@ -113,10 +117,6 @@ void CSVDoc::View::setupViewMenu() QAction *filters = new QAction (tr ("Filters"), this); connect (filters, SIGNAL (triggered()), this, SLOT (addFiltersSubView())); view->addAction (filters); - - QAction *search = new QAction (tr ("Search"), this); - connect (search, SIGNAL (triggered()), this, SLOT (addSearchSubView())); - view->addAction (search); } void CSVDoc::View::setupWorldMenu() From 154bb04a77f259e09af65022fa76e3b69bf0595a Mon Sep 17 00:00:00 2001 From: Scott Howard Date: Tue, 17 Mar 2015 09:45:31 -0400 Subject: [PATCH 642/740] add scan-build to travis matrix --- .travis.yml | 10 +++++++++- CI/before_install.linux.sh | 10 ++++++++-- CI/before_script.linux.sh | 4 +++- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1be8aa59c..1fc85dca3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,6 +21,14 @@ addons: build_command_prepend: "cmake ." build_command: "make -j3" branch_pattern: coverity_scan +matrix: + include: + - os: linux + env: + ANALYZE="scan-build-3.6 --use-cc clang-3.6 --use-c++ clang++-3.6 " + compiler: clang + allow_failures: + - env: ANALYZE="scan-build-3.6 --use-cc clang-3.6 --use-c++ clang++-3.6 " before_install: - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./CI/before_install.linux.sh; fi @@ -30,7 +38,7 @@ before_script: - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then ./CI/before_script.osx.sh; fi script: - cd ./build - - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then make -j4; fi + - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then ${ANALYZE}make -j4; fi - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "osx" ]; then make package; fi after_script: - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi diff --git a/CI/before_install.linux.sh b/CI/before_install.linux.sh index 998c285db..27cb71463 100755 --- a/CI/before_install.linux.sh +++ b/CI/before_install.linux.sh @@ -1,7 +1,12 @@ #!/bin/sh -export CXX=g++ -export CC=gcc +if [ "${ANALYZE}" ]; then + if [ $(lsb_release -sc) = "precise" ]; then + echo "yes" | sudo apt-add-repository ppa:ubuntu-toolchain-r/test + fi + echo "yes" | sudo add-apt-repository "deb http://llvm.org/apt/`lsb_release -sc`/ llvm-toolchain-`lsb_release -sc`-3.6 main" + wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key|sudo apt-key add - +fi echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse" echo "yes" | sudo apt-add-repository ppa:openmw/openmw @@ -10,6 +15,7 @@ sudo apt-get install -qq libgtest-dev google-mock sudo apt-get install -qq libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-thread-dev libboost-wave-dev sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libavresample-dev sudo apt-get install -qq libbullet-dev libogre-1.9-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev +if [ "${ANALYZE}" ]; then sudo apt-get install -qq clang-3.6; fi sudo mkdir /usr/src/gtest/build cd /usr/src/gtest/build sudo cmake .. -DBUILD_SHARED_LIBS=1 diff --git a/CI/before_script.linux.sh b/CI/before_script.linux.sh index b4889c9e1..71ddd2040 100755 --- a/CI/before_script.linux.sh +++ b/CI/before_script.linux.sh @@ -2,4 +2,6 @@ mkdir build cd build -cmake .. -DBUILD_WITH_CODE_COVERAGE=1 -DBUILD_UNITTESTS=1 -DCMAKE_INSTALL_PREFIX=/usr -DBINDIR=/usr/games -DCMAKE_BUILD_TYPE="RelWithDebInfo" -DUSE_SYSTEM_TINYXML=TRUE +export CODE_COVERAGE=1 +if [ "${CC}" = "clang" ]; then export CODE_COVERAGE=0; fi +${ANALYZE}cmake .. -DBUILD_WITH_CODE_COVERAGE=${CODE_COVERAGE} -DBUILD_UNITTESTS=1 -DCMAKE_INSTALL_PREFIX=/usr -DBINDIR=/usr/games -DCMAKE_BUILD_TYPE="RelWithDebInfo" -DUSE_SYSTEM_TINYXML=TRUE From 2cfc4c02866bf36ebf874ff12075ec85e685a724 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 21 Mar 2015 18:21:01 +1300 Subject: [PATCH 643/740] script Random() command now returns correct range. --- components/interpreter/miscopcodes.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/interpreter/miscopcodes.hpp b/components/interpreter/miscopcodes.hpp index 1da8cf695..f566a5499 100644 --- a/components/interpreter/miscopcodes.hpp +++ b/components/interpreter/miscopcodes.hpp @@ -12,6 +12,8 @@ #include "runtime.hpp" #include "defines.hpp" +#include + namespace Interpreter { inline std::string formatMessage (const std::string& message, Runtime& runtime) @@ -140,15 +142,13 @@ namespace Interpreter virtual void execute (Runtime& runtime) { - double r = static_cast (std::rand()) / RAND_MAX; // [0, 1) - Type_Integer limit = runtime[0].mInteger; if (limit<0) throw std::runtime_error ( "random: argument out of range (Don't be so negative!)"); - Type_Integer value = static_cast (r*limit); // [o, limit) + Type_Integer value = OEngine::Misc::Rng::rollDice(limit); // [o, limit) runtime[0].mInteger = value; } From eb1090a1b68999d00df3778cffb59d2a933a9f81 Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 23 Mar 2015 20:09:46 +1300 Subject: [PATCH 644/740] Waypoint check only considers X & Y distance (Fixes #2423) When pathfinder checks if actor has reached a waypoint, ignore actor's altitude. --- apps/openmw/mwmechanics/aicombat.cpp | 2 +- apps/openmw/mwmechanics/aipackage.cpp | 2 +- apps/openmw/mwmechanics/aitravel.cpp | 2 +- apps/openmw/mwmechanics/aiwander.cpp | 2 +- apps/openmw/mwmechanics/pathfinding.cpp | 9 ++++----- apps/openmw/mwmechanics/pathfinding.hpp | 2 +- 6 files changed, 9 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index bac7d7286..2f68087e5 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -581,7 +581,7 @@ namespace MWMechanics buildNewPath(actor, target); //may fail to build a path, check before use //delete visited path node - mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]); + mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1]); // This works on the borders between the path grid and areas with no waypoints. if(inLOS && mPathFinder.getPath().size() > 1) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index f93376779..52a975320 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -86,7 +86,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po //************************ /// Checks if you aren't moving; attempts to unstick you //************************ - if(mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2])) //Path finished? + if(mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1])) //Path finished? return true; else if(mStuckTimer>0.5) //Every half second see if we need to take action to avoid something { diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index a46fe7296..2824e2c6c 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -100,7 +100,7 @@ namespace MWMechanics mPathFinder.buildPath(start, dest, actor.getCell(), true); } - if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2])) + if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1])) { movement.mPosition[1] = 0; return true; diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index b791ff3a9..2bd2cfe5d 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -205,7 +205,7 @@ namespace MWMechanics // Are we there yet? bool& chooseAction = storage.mChooseAction; if(walking && - storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2], 64.f)) + storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], 64.f)) { stopWalking(actor, storage); moveNow = false; diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index e8abb9e98..5795f818a 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -90,12 +90,11 @@ namespace namespace MWMechanics { - float sqrDistanceZCorrected(ESM::Pathgrid::Point point, float x, float y, float z) + float sqrDistanceIgnoreZ(ESM::Pathgrid::Point point, float x, float y) { x -= point.mX; y -= point.mY; - z -= point.mZ; - return (x * x + y * y + 0.1f * z * z); + return (x * x + y * y); } float distance(ESM::Pathgrid::Point point, float x, float y, float z) @@ -283,13 +282,13 @@ namespace MWMechanics return Ogre::Math::ATan2(directionX,directionY).valueDegrees(); } - bool PathFinder::checkPathCompleted(float x, float y, float z, float tolerance) + bool PathFinder::checkPathCompleted(float x, float y, float tolerance) { if(mPath.empty()) return true; ESM::Pathgrid::Point nextPoint = *mPath.begin(); - if(sqrDistanceZCorrected(nextPoint, x, y, z) < tolerance*tolerance) + if (sqrDistanceIgnoreZ(nextPoint, x, y) < tolerance*tolerance) { mPath.pop_front(); if(mPath.empty()) diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 490cf9b88..f48de6624 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -41,7 +41,7 @@ namespace MWMechanics void buildPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint, const MWWorld::CellStore* cell, bool allowShortcuts = true); - bool checkPathCompleted(float x, float y, float z, float tolerance=32.f); + bool checkPathCompleted(float x, float y, float tolerance=32.f); ///< \Returns true if we are within \a tolerance units of the last path point. float getZAngleToNext(float x, float y) const; From 63ab856024abb36401da58744f9f5fe40063c908 Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 23 Mar 2015 20:57:36 +1300 Subject: [PATCH 645/740] Removed duplicated code. --- apps/openmw/mwmechanics/aiwander.cpp | 56 ++++++++++++---------------- apps/openmw/mwmechanics/aiwander.hpp | 8 ++++ 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 2bd2cfe5d..d277b1249 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -31,6 +31,18 @@ namespace MWMechanics static const int GREETING_SHOULD_START = 4; //how many reaction intervals should pass before NPC can greet player static const int GREETING_SHOULD_END = 10; + const std::string AiWander::sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1] = + { + std::string("idle2"), + std::string("idle3"), + std::string("idle4"), + std::string("idle5"), + std::string("idle6"), + std::string("idle7"), + std::string("idle8"), + std::string("idle9"), + }; + /// \brief This class holds the variables AiWander needs which are deleted if the package becomes inactive. struct AiWanderStorage : AiTemporaryBase { @@ -580,44 +592,24 @@ namespace MWMechanics void AiWander::playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect) { - if(idleSelect == 2) - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle2", 0, 1); - else if(idleSelect == 3) - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle3", 0, 1); - else if(idleSelect == 4) - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle4", 0, 1); - else if(idleSelect == 5) - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle5", 0, 1); - else if(idleSelect == 6) - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle6", 0, 1); - else if(idleSelect == 7) - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle7", 0, 1); - else if(idleSelect == 8) - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle8", 0, 1); - else if(idleSelect == 9) - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle9", 0, 1); + if ((GroupIndex_MinIdle <= idleSelect) && (idleSelect <= GroupIndex_MaxIdle)) + { + const std::string& groupName = sIdleSelectToGroupName[idleSelect - GroupIndex_MinIdle]; + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, groupName, 0, 1); + } } bool AiWander::checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect) { - if(idleSelect == 2) - return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle2"); - else if(idleSelect == 3) - return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle3"); - else if(idleSelect == 4) - return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle4"); - else if(idleSelect == 5) - return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle5"); - else if(idleSelect == 6) - return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle6"); - else if(idleSelect == 7) - return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle7"); - else if(idleSelect == 8) - return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle8"); - else if(idleSelect == 9) - return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle9"); + if ((GroupIndex_MinIdle <= idleSelect) && (idleSelect <= GroupIndex_MaxIdle)) + { + const std::string& groupName = sIdleSelectToGroupName[idleSelect - GroupIndex_MinIdle]; + return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, groupName); + } else + { return false; + } } void AiWander::setReturnPosition(const Ogre::Vector3& position) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 54e215cb9..7e138c001 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -113,7 +113,15 @@ namespace MWMechanics float mDoorCheckDuration; int mStuckCount; + // constants for converting idleSelect values into groupNames + enum GroupIndex + { + GroupIndex_MinIdle = 2, + GroupIndex_MaxIdle = 9 + }; + /// lookup table for converting idleSelect value to groupName + static const std::string sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1]; }; From b7867d6f0acf2a167581d8478816823f7a85371b Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 25 Mar 2015 05:29:00 +0100 Subject: [PATCH 646/740] Stop warning about unused nif properties --- components/nif/node.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/nif/node.cpp b/components/nif/node.cpp index fb68da548..d99d157ae 100644 --- a/components/nif/node.cpp +++ b/components/nif/node.cpp @@ -38,7 +38,10 @@ void Node::getProperties(const Nif::NiTexturingProperty *&texprop, wireprop = static_cast(pr); else if (pr->recType == Nif::RC_NiStencilProperty) stencilprop = static_cast(pr); - else + // the following are unused by the MW engine + else if (pr->recType != Nif::RC_NiFogProperty + && pr->recType != Nif::RC_NiDitherProperty + && pr->recType != Nif::RC_NiShadeProperty) std::cerr<< "Unhandled property type: "<recName < Date: Wed, 25 Mar 2015 11:56:14 +0100 Subject: [PATCH 647/740] added search class and search box widget --- apps/opencs/CMakeLists.txt | 4 +- apps/opencs/model/tools/search.cpp | 213 +++++++++++++++++++++++ apps/opencs/model/tools/search.hpp | 82 +++++++++ apps/opencs/model/world/columnbase.cpp | 72 +++++++- apps/opencs/model/world/columnbase.hpp | 6 + apps/opencs/view/tools/searchbox.cpp | 145 +++++++++++++++ apps/opencs/view/tools/searchbox.hpp | 57 ++++++ apps/opencs/view/tools/searchsubview.cpp | 29 ++- apps/opencs/view/tools/searchsubview.hpp | 7 + 9 files changed, 611 insertions(+), 4 deletions(-) create mode 100644 apps/opencs/model/tools/search.cpp create mode 100644 apps/opencs/model/tools/search.hpp create mode 100644 apps/opencs/view/tools/searchbox.cpp create mode 100644 apps/opencs/view/tools/searchbox.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index e3b44ac91..eb83b14d5 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -40,7 +40,7 @@ opencs_units (model/tools opencs_units_noqt (model/tools mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck - startscriptcheck + startscriptcheck search ) @@ -91,7 +91,7 @@ opencs_hdrs_noqt (view/render opencs_units (view/tools - reportsubview reporttable searchsubview + reportsubview reporttable searchsubview searchbox ) opencs_units_noqt (view/tools diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp new file mode 100644 index 000000000..1b7be6fbf --- /dev/null +++ b/apps/opencs/model/tools/search.cpp @@ -0,0 +1,213 @@ + +#include "search.hpp" + +#include +#include + +#include "../../model/doc/messages.hpp" + +#include "../../model/world/idtablebase.hpp" +#include "../../model/world/columnbase.hpp" +#include "../../model/world/universalid.hpp" + +void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model, + const QModelIndex& index, const CSMWorld::UniversalId& id, bool multiple, + CSMDoc::Messages& messages) const +{ + // using QString here for easier handling of case folding. + + QString search = QString::fromUtf8 (mText.c_str()); + QString text = model->data (index).toString(); + + int pos = 0; + + while ((pos = text.indexOf (search, pos, Qt::CaseInsensitive))!=-1) + { + std::ostringstream message; + message << text.mid (pos).toUtf8().data(); + + std::ostringstream hint; + message << "r: " << index.column() << " " << pos << " " << search.length(); + + messages.add (id, message.str(), hint.str()); + + if (!multiple) + break; + + pos += search.length(); + } +} + +void CSMTools::Search::searchRegExCell (const CSMWorld::IdTableBase *model, + const QModelIndex& index, const CSMWorld::UniversalId& id, bool multiple, + CSMDoc::Messages& messages) const +{ + QString text = model->data (index).toString(); + + int pos = 0; + + while ((pos = mRegExp.indexIn (text, pos))!=-1) + { + std::ostringstream message; + message << text.mid (pos).toUtf8().data(); + + int length = mRegExp.matchedLength(); + + std::ostringstream hint; + message << "r: " << index.column() << " " << pos << " " << length; + + messages.add (id, message.str(), hint.str()); + + if (!multiple) + break; + + pos += length; + } +} + +void CSMTools::Search::searchRecordStateCell (const CSMWorld::IdTableBase *model, + const QModelIndex& index, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) const +{ + int data = model->data (index).toInt(); + + if (data==mValue) + { + std::vector states = + CSMWorld::Columns::getEnums (CSMWorld::Columns::ColumnId_Modification); + + std::ostringstream message; + message << id.getId() << " " << states.at (data); + + std::ostringstream hint; + message << "r: " << index.column(); + + messages.add (id, message.str(), hint.str()); + } +} + +CSMTools::Search::Search() : mType (Type_None) {} + +CSMTools::Search::Search (Type type, const std::string& value) +: mType (type), mText (value) +{ + if (type!=Type_Text && type!=Type_Reference) + throw std::logic_error ("Invalid search parameter (string)"); +} + +CSMTools::Search::Search (Type type, const QRegExp& value) +: mType (type), mRegExp (value) +{ + if (type!=Type_TextRegEx && type!=Type_ReferenceRegEx) + throw std::logic_error ("Invalid search parameter (RegExp)"); +} + +CSMTools::Search::Search (Type type, int value) +: mType (type), mValue (value) +{ + if (type!=Type_RecordState) + throw std::logic_error ("invalid search parameter (int)"); +} + +void CSMTools::Search::configure (const CSMWorld::IdTableBase *model) +{ + mColumns.clear(); + + int columns = model->columnCount(); + + for (int i=0; i ( + model->headerData ( + i, Qt::Horizontal, static_cast (CSMWorld::ColumnBase::Role_Display)).toInt()); + + bool consider = false; + bool multiple = false; + + switch (mType) + { + case Type_Text: + case Type_TextRegEx: + + if (CSMWorld::ColumnBase::isText (display) || + CSMWorld::ColumnBase::isScript (display)) + { + consider = true; + multiple = true; + } + + break; + + case Type_Reference: + case Type_ReferenceRegEx: + + if (CSMWorld::ColumnBase::isId (display)) + { + consider = true; + } + else if (CSMWorld::ColumnBase::isScript (display)) + { + consider = true; + multiple = true; + } + + break; + + case Type_RecordState: + + if (display==CSMWorld::ColumnBase::Display_RecordState) + consider = true; + + break; + + case Type_None: + + break; + } + + if (consider) + mColumns.insert (std::make_pair (i, multiple)); + } + + mIdColumn = model->findColumnIndex (CSMWorld::Columns::ColumnId_Id); + mTypeColumn = model->findColumnIndex (CSMWorld::Columns::ColumnId_RecordType); +} + +void CSMTools::Search::searchRow (const CSMWorld::IdTableBase *model, int row, + CSMDoc::Messages& messages) const +{ + for (std::map::const_iterator iter (mColumns.begin()); iter!=mColumns.end(); + ++iter) + { + QModelIndex index = model->index (row, iter->first); + + CSMWorld::UniversalId::Type type = static_cast ( + model->data (model->index (row, mTypeColumn)).toInt()); + + CSMWorld::UniversalId id ( + type, model->data (model->index (row, mIdColumn)).toString().toUtf8().data()); + + switch (mType) + { + case Type_Text: + case Type_Reference: + + searchTextCell (model, index, id, iter->second, messages); + break; + + case Type_TextRegEx: + case Type_ReferenceRegEx: + + searchRegExCell (model, index, id, iter->second, messages); + break; + + case Type_RecordState: + + searchRecordStateCell (model, index, id, messages); + break; + + case Type_None: + + break; + } + } +} diff --git a/apps/opencs/model/tools/search.hpp b/apps/opencs/model/tools/search.hpp new file mode 100644 index 000000000..3683f9c9b --- /dev/null +++ b/apps/opencs/model/tools/search.hpp @@ -0,0 +1,82 @@ +#ifndef CSM_TOOLS_SEARCH_H +#define CSM_TOOLS_SEARCH_H + +#include +#include + +#include +#include + +class QModelIndex; + +namespace CSMDoc +{ + class Messages; +} + +namespace CSMWorld +{ + class IdTableBase; + class UniversalId; +} + +namespace CSMTools +{ + class Search + { + public: + + enum Type + { + Type_Text = 0, + Type_TextRegEx = 1, + Type_Reference = 2, + Type_ReferenceRegEx = 3, + Type_RecordState = 4, + Type_None + }; + + private: + + Type mType; + std::string mText; + QRegExp mRegExp; + int mValue; + std::map mColumns; // column, multiple finds per cell + int mIdColumn; + int mTypeColumn; + + void searchTextCell (const CSMWorld::IdTableBase *model, const QModelIndex& index, + const CSMWorld::UniversalId& id, bool multiple, CSMDoc::Messages& messages) const; + + void searchRegExCell (const CSMWorld::IdTableBase *model, const QModelIndex& index, + const CSMWorld::UniversalId& id, bool multiple, CSMDoc::Messages& messages) const; + + void searchRecordStateCell (const CSMWorld::IdTableBase *model, + const QModelIndex& index, const CSMWorld::UniversalId& id, + CSMDoc::Messages& messages) const; + + public: + + Search(); + + Search (Type type, const std::string& value); + + Search (Type type, const QRegExp& value); + + Search (Type type, int value); + + // Configure search for the specified model. + void configure (const CSMWorld::IdTableBase *model); + + // Search row in \a model and store results in \a messages. + // + // \attention *this needs to be configured for \a model. + void searchRow (const CSMWorld::IdTableBase *model, int row, + CSMDoc::Messages& messages) const; + }; +} + +Q_DECLARE_METATYPE (CSMTools::Search) + +#endif diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 665ab9354..f4f2310b6 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -19,7 +19,77 @@ std::string CSMWorld::ColumnBase::getTitle() const return Columns::getName (static_cast (mColumnId)); } -int CSMWorld::ColumnBase::getId() const +int CSMWorld::ColumnBase::getId() const { return mColumnId; } + +bool CSMWorld::ColumnBase::isId (Display display) +{ + static const Display ids[] = + { + Display_Skill, + Display_Class, + Display_Faction, + Display_Race, + Display_Sound, + Display_Region, + Display_Birthsign, + Display_Spell, + Display_Cell, + Display_Referenceable, + Display_Activator, + Display_Potion, + Display_Apparatus, + Display_Armor, + Display_Book, + Display_Clothing, + Display_Container, + Display_Creature, + Display_Door, + Display_Ingredient, + Display_CreatureLevelledList, + Display_ItemLevelledList, + Display_Light, + Display_Lockpick, + Display_Miscellaneous, + Display_Npc, + Display_Probe, + Display_Repair, + Display_Static, + Display_Weapon, + Display_Reference, + Display_Filter, + Display_Topic, + Display_Journal, + Display_TopicInfo, + Display_JournalInfo, + Display_Scene, + Display_GlobalVariable, + + Display_Mesh, + Display_Icon, + Display_Music, + Display_SoundRes, + Display_Texture, + Display_Video, + + Display_None + }; + + for (int i=0; ids[i]!=Display_None; ++i) + if (ids[i]==display) + return true; + + return false; +} + +bool CSMWorld::ColumnBase::isText (Display display) +{ + return display==Display_String || display==Display_LongString; +} + +bool CSMWorld::ColumnBase::isScript (Display display) +{ + return display==Display_Script || display==Display_ScriptLines; +} diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index db9b8b3c6..c49785154 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -122,6 +122,12 @@ namespace CSMWorld virtual std::string getTitle() const; virtual int getId() const; + + static bool isId (Display display); + + static bool isText (Display display); + + static bool isScript (Display display); }; template diff --git a/apps/opencs/view/tools/searchbox.cpp b/apps/opencs/view/tools/searchbox.cpp new file mode 100644 index 000000000..1b11d8a4d --- /dev/null +++ b/apps/opencs/view/tools/searchbox.cpp @@ -0,0 +1,145 @@ + +#include "searchbox.hpp" + +#include + +#include +#include +#include + +#include "../../model/world/columns.hpp" + +#include "../../model/tools/search.hpp" + +void CSVTools::SearchBox::updateSearchButton() +{ + if (!mSearchEnabled) + mSearch.setEnabled (false); + else + { + switch (mMode.currentIndex()) + { + case 0: + case 1: + case 2: + case 3: + + mSearch.setEnabled (!mText.text().isEmpty()); + break; + + case 4: + + mSearch.setEnabled (true); + break; + } + } +} + +CSVTools::SearchBox::SearchBox (QWidget *parent) +: QWidget (parent), mSearch ("Search"), mSearchEnabled (false) +{ + std::vector states = + CSMWorld::Columns::getEnums (CSMWorld::Columns::ColumnId_Modification); + states.resize (states.size()-1); // ignore erased state + + for (std::vector::const_iterator iter (states.begin()); iter!=states.end(); + ++iter) + mRecordState.addItem (QString::fromUtf8 (iter->c_str())); + + mLayout = new QGridLayout (this); + + mMode.addItem ("Text"); + mMode.addItem ("Text (RegEx)"); + mMode.addItem ("Reference"); + mMode.addItem ("Reference (RegEx)"); + mMode.addItem ("Record State"); + + mLayout->addWidget (&mMode, 0, 0); + + mLayout->addWidget (&mSearch, 0, 3); + + mInput.insertWidget (0, &mText); + mInput.insertWidget (1, &mRecordState); + + mLayout->addWidget (&mInput, 0, 1); + + mLayout->setColumnMinimumWidth (2, 50); + mLayout->setColumnStretch (1, 1); + + mLayout->setContentsMargins (0, 0, 0, 0); + + connect (&mMode, SIGNAL (activated (int)), this, SLOT (modeSelected (int))); + + connect (&mText, SIGNAL (textChanged (const QString&)), + this, SLOT (textChanged (const QString&))); + + connect (&mSearch, SIGNAL (clicked (bool)), this, SLOT (startSearch (bool))); + + modeSelected (0); + + updateSearchButton(); +} + +void CSVTools::SearchBox::setSearchMode (bool enabled) +{ + mSearchEnabled = enabled; + updateSearchButton(); +} + +CSMTools::Search CSVTools::SearchBox::getSearch() const +{ + CSMTools::Search::Type type = static_cast (mMode.currentIndex()); + + switch (type) + { + case CSMTools::Search::Type_Text: + case CSMTools::Search::Type_Reference: + + return CSMTools::Search (type, std::string (mText.text().toUtf8().data())); + + case CSMTools::Search::Type_TextRegEx: + case CSMTools::Search::Type_ReferenceRegEx: + + return CSMTools::Search (type, QRegExp (mText.text().toUtf8().data(), Qt::CaseInsensitive)); + + case CSMTools::Search::Type_RecordState: + + return CSMTools::Search (type, mRecordState.currentIndex()); + + case CSMTools::Search::Type_None: + + break; + } + + throw std::logic_error ("invalid search mode index"); +} + +void CSVTools::SearchBox::modeSelected (int index) +{ + switch (index) + { + case CSMTools::Search::Type_Text: + case CSMTools::Search::Type_TextRegEx: + case CSMTools::Search::Type_Reference: + case CSMTools::Search::Type_ReferenceRegEx: + + mInput.setCurrentIndex (0); + break; + + case CSMTools::Search::Type_RecordState: + mInput.setCurrentIndex (1); + break; + } + + updateSearchButton(); +} + +void CSVTools::SearchBox::textChanged (const QString& text) +{ + updateSearchButton(); +} + +void CSVTools::SearchBox::startSearch (bool checked) +{ + emit startSearch (getSearch()); +} diff --git a/apps/opencs/view/tools/searchbox.hpp b/apps/opencs/view/tools/searchbox.hpp new file mode 100644 index 000000000..dc975cac9 --- /dev/null +++ b/apps/opencs/view/tools/searchbox.hpp @@ -0,0 +1,57 @@ +#ifndef CSV_TOOLS_SEARCHBOX_H +#define CSV_TOOLS_SEARCHBOX_H + +#include +#include +#include +#include +#include + +class QGridLayout; + +namespace CSMTools +{ + class Search; +} + +namespace CSVTools +{ + class SearchBox : public QWidget + { + Q_OBJECT + + QStackedWidget mInput; + QLineEdit mText; + QComboBox mRecordState; + QPushButton mSearch; + QGridLayout *mLayout; + QComboBox mMode; + bool mSearchEnabled; + + private: + + void updateSearchButton(); + + public: + + SearchBox (QWidget *parent = 0); + + void setSearchMode (bool enabled); + + CSMTools::Search getSearch() const; + + private slots: + + void modeSelected (int index); + + void textChanged (const QString& text); + + void startSearch (bool checked); + + signals: + + void startSearch (const CSMTools::Search& search); + }; +} + +#endif diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index 7173a6634..bc818df07 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -1,15 +1,37 @@ #include "searchsubview.hpp" +#include + +#include "../../model/doc/document.hpp" + #include "reporttable.hpp" +#include "searchbox.hpp" CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) : CSVDoc::SubView (id) { - setWidget (mTable = new ReportTable (document, id, this)); + QVBoxLayout *layout = new QVBoxLayout; + + layout->setContentsMargins (QMargins (0, 0, 0, 0)); + + layout->addWidget (&mSearchBox); + + layout->addWidget (mTable = new ReportTable (document, id), 2); + + QWidget *widget = new QWidget; + + widget->setLayout (layout); + setWidget (widget); + + stateChanged (document.getState(), &document); + connect (mTable, SIGNAL (editRequest (const CSMWorld::UniversalId&, const std::string&)), SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&))); + + connect (&document, SIGNAL (stateChanged (int, CSMDoc::Document *)), + this, SLOT (stateChanged (int, CSMDoc::Document *))); } void CSVTools::SearchSubView::setEditLock (bool locked) @@ -21,3 +43,8 @@ void CSVTools::SearchSubView::updateUserSetting (const QString &name, const QStr { mTable->updateUserSetting (name, list); } + +void CSVTools::SearchSubView::stateChanged (int state, CSMDoc::Document *document) +{ + mSearchBox.setSearchMode (!(state & CSMDoc::State_Searching)); +} diff --git a/apps/opencs/view/tools/searchsubview.hpp b/apps/opencs/view/tools/searchsubview.hpp index abedd5e6d..b389805bb 100644 --- a/apps/opencs/view/tools/searchsubview.hpp +++ b/apps/opencs/view/tools/searchsubview.hpp @@ -3,6 +3,8 @@ #include "../doc/subview.hpp" +#include "searchbox.hpp" + class QTableView; class QModelIndex; @@ -20,6 +22,7 @@ namespace CSVTools Q_OBJECT ReportTable *mTable; + SearchBox mSearchBox; public: @@ -28,6 +31,10 @@ namespace CSVTools virtual void setEditLock (bool locked); virtual void updateUserSetting (const QString &, const QStringList &); + + private slots: + + void stateChanged (int state, CSMDoc::Document *document); }; } From 23cf859fee045877d7a6cc64fea023939f9ab4f2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 27 Mar 2015 16:33:54 +0100 Subject: [PATCH 648/740] added search stages (cell table only for now) --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/doc/document.cpp | 5 +++ apps/opencs/model/doc/document.hpp | 2 ++ apps/opencs/model/tools/searchoperation.cpp | 33 ++++++++++++++++++ apps/opencs/model/tools/searchoperation.hpp | 38 +++++++++++++++++++++ apps/opencs/model/tools/searchstage.cpp | 30 ++++++++++++++++ apps/opencs/model/tools/searchstage.hpp | 37 ++++++++++++++++++++ apps/opencs/model/tools/tools.cpp | 22 ++++++++++++ apps/opencs/model/tools/tools.hpp | 6 +++- apps/opencs/view/doc/operation.cpp | 1 + apps/opencs/view/doc/view.cpp | 2 +- apps/opencs/view/tools/searchsubview.cpp | 10 +++++- apps/opencs/view/tools/searchsubview.hpp | 3 ++ 13 files changed, 187 insertions(+), 4 deletions(-) create mode 100644 apps/opencs/model/tools/searchoperation.cpp create mode 100644 apps/opencs/model/tools/searchoperation.hpp create mode 100644 apps/opencs/model/tools/searchstage.cpp create mode 100644 apps/opencs/model/tools/searchstage.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index eb83b14d5..f27231c5a 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -40,7 +40,7 @@ opencs_units (model/tools opencs_units_noqt (model/tools mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck - startscriptcheck search + startscriptcheck search searchoperation searchstage ) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index a06eb0ebf..cb3b4ba18 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2380,6 +2380,11 @@ CSMWorld::UniversalId CSMDoc::Document::newSearch() return mTools.newSearch(); } +void CSMDoc::Document::runSearch (const CSMWorld::UniversalId& searchId, const CSMTools::Search& search) +{ + return mTools.runSearch (searchId, search); +} + void CSMDoc::Document::abortOperation (int type) { if (type==State_Saving) diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 4300a9c64..6b1a1fc1e 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -121,6 +121,8 @@ namespace CSMDoc CSMWorld::UniversalId verify(); CSMWorld::UniversalId newSearch(); + + void runSearch (const CSMWorld::UniversalId& searchId, const CSMTools::Search& search); void abortOperation (int type); diff --git a/apps/opencs/model/tools/searchoperation.cpp b/apps/opencs/model/tools/searchoperation.cpp new file mode 100644 index 000000000..134b83b72 --- /dev/null +++ b/apps/opencs/model/tools/searchoperation.cpp @@ -0,0 +1,33 @@ + +#include "searchoperation.hpp" + +#include "../doc/state.hpp" +#include "../doc/document.hpp" + +#include "../world/data.hpp" +#include "../world/idtablebase.hpp" + +#include "searchstage.hpp" + +CSMTools::SearchOperation::SearchOperation (CSMDoc::Document& document) +: CSMDoc::Operation (CSMDoc::State_Searching, false) +{ +appendStage (new SearchStage (&dynamic_cast (*document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells)))); + +} + +void CSMTools::SearchOperation::configure (const Search& search) +{ + mSearch = search; +} + +void CSMTools::SearchOperation::appendStage (SearchStage *stage) +{ + CSMDoc::Operation::appendStage (stage); + stage->setOperation (this); +} + +const CSMTools::Search& CSMTools::SearchOperation::getSearch() const +{ + return mSearch; +} diff --git a/apps/opencs/model/tools/searchoperation.hpp b/apps/opencs/model/tools/searchoperation.hpp new file mode 100644 index 000000000..fbbb38898 --- /dev/null +++ b/apps/opencs/model/tools/searchoperation.hpp @@ -0,0 +1,38 @@ +#ifndef CSM_TOOLS_SEARCHOPERATION_H +#define CSM_TOOLS_SEARCHOPERATION_H + +#include "../doc/operation.hpp" + +#include "search.hpp" + +namespace CSMDoc +{ + class Document; +} + +namespace CSMTools +{ + class SearchStage; + + class SearchOperation : public CSMDoc::Operation + { + Search mSearch; + + public: + + SearchOperation (CSMDoc::Document& document); + + /// \attention Do not call this function while a search is running. + void configure (const Search& search); + + void appendStage (SearchStage *stage); + ///< The ownership of \a stage is transferred to *this. + /// + /// \attention Do no call this function while this Operation is running. + + const Search& getSearch() const; + + }; +} + +#endif diff --git a/apps/opencs/model/tools/searchstage.cpp b/apps/opencs/model/tools/searchstage.cpp new file mode 100644 index 000000000..17859d930 --- /dev/null +++ b/apps/opencs/model/tools/searchstage.cpp @@ -0,0 +1,30 @@ + +#include "searchstage.hpp" + +#include "../world/idtablebase.hpp" + +#include "searchoperation.hpp" + +CSMTools::SearchStage::SearchStage (const CSMWorld::IdTableBase *model) +: mModel (model), mOperation (0) +{} + +int CSMTools::SearchStage::setup() +{ + if (mOperation) + mSearch = mOperation->getSearch(); + + mSearch.configure (mModel); + + return mModel->rowCount(); +} + +void CSMTools::SearchStage::perform (int stage, CSMDoc::Messages& messages) +{ + mSearch.searchRow (mModel, stage, messages); +} + +void CSMTools::SearchStage::setOperation (const SearchOperation *operation) +{ + mOperation = operation; +} diff --git a/apps/opencs/model/tools/searchstage.hpp b/apps/opencs/model/tools/searchstage.hpp new file mode 100644 index 000000000..073487c0d --- /dev/null +++ b/apps/opencs/model/tools/searchstage.hpp @@ -0,0 +1,37 @@ +#ifndef CSM_TOOLS_SEARCHSTAGE_H +#define CSM_TOOLS_SEARCHSTAGE_H + +#include "../doc/stage.hpp" + +#include "search.hpp" + +namespace CSMWorld +{ + class IdTableBase; +} + +namespace CSMTools +{ + class SearchOperation; + + class SearchStage : public CSMDoc::Stage + { + const CSMWorld::IdTableBase *mModel; + Search mSearch; + const SearchOperation *mOperation; + + public: + + SearchStage (const CSMWorld::IdTableBase *model); + + 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. + + void setOperation (const SearchOperation *operation); + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 07bd4205b..957e20296 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -25,6 +25,7 @@ #include "bodypartcheck.hpp" #include "referencecheck.hpp" #include "startscriptcheck.hpp" +#include "searchoperation.hpp" CSMDoc::OperationHolder *CSMTools::Tools::get (int type) { @@ -108,6 +109,12 @@ CSMTools::Tools::Tools (CSMDoc::Document& document) // index 0: load error log mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel)); mActiveReports.insert (std::make_pair (CSMDoc::State_Loading, 0)); + + connect (&mSearch, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int))); + connect (&mSearch, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool))); + connect (&mSearch, + SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)), + this, SLOT (verifierMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int))); } CSMTools::Tools::~Tools() @@ -145,6 +152,21 @@ CSMWorld::UniversalId CSMTools::Tools::newSearch() return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Search, mNextReportNumber-1); } +void CSMTools::Tools::runSearch (const CSMWorld::UniversalId& searchId, const Search& search) +{ + mActiveReports[CSMDoc::State_Searching] = searchId.getIndex(); + + if (!mSearchOperation) + { + mSearchOperation = new SearchOperation (mDocument); + mSearch.setOperation (mSearchOperation); + } + + mSearchOperation->configure (search); + + mSearch.start(); +} + void CSMTools::Tools::abortOperation (int type) { if (CSMDoc::OperationHolder *operation = get (type)) diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp index bd27767a6..0f9e57044 100644 --- a/apps/opencs/model/tools/tools.hpp +++ b/apps/opencs/model/tools/tools.hpp @@ -22,6 +22,8 @@ namespace CSMDoc namespace CSMTools { class ReportModel; + class Search; + class SearchOperation; class Tools : public QObject { @@ -31,7 +33,7 @@ namespace CSMTools CSMWorld::Data& mData; CSMDoc::Operation *mVerifierOperation; CSMDoc::OperationHolder mVerifier; - CSMDoc::Operation *mSearchOperation; + SearchOperation *mSearchOperation; CSMDoc::OperationHolder mSearch; std::map mReports; int mNextReportNumber; @@ -60,6 +62,8 @@ namespace CSMTools /// Return ID of the report for this search. CSMWorld::UniversalId newSearch(); + + void runSearch (const CSMWorld::UniversalId& searchId, const Search& search); void abortOperation (int type); ///< \attention The operation is not aborted immediately. diff --git a/apps/opencs/view/doc/operation.cpp b/apps/opencs/view/doc/operation.cpp index 6977d7953..95cbf012d 100644 --- a/apps/opencs/view/doc/operation.cpp +++ b/apps/opencs/view/doc/operation.cpp @@ -18,6 +18,7 @@ void CSVDoc::Operation::updateLabel (int threads) { case CSMDoc::State_Saving: name = "saving"; break; case CSMDoc::State_Verifying: name = "verifying"; break; + case CSMDoc::State_Searching: name = "searching"; break; } std::ostringstream stream; diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 533cab049..e7eb28337 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -447,7 +447,7 @@ void CSVDoc::View::updateDocumentState() static const int operations[] = { - CSMDoc::State_Saving, CSMDoc::State_Verifying, + CSMDoc::State_Saving, CSMDoc::State_Verifying, CSMDoc::State_Searching, -1 // end marker }; diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index bc818df07..b4a0f893a 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -9,7 +9,7 @@ #include "searchbox.hpp" CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) -: CSVDoc::SubView (id) +: CSVDoc::SubView (id), mDocument (document) { QVBoxLayout *layout = new QVBoxLayout; @@ -32,6 +32,9 @@ CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc: connect (&document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (stateChanged (int, CSMDoc::Document *))); + + connect (&mSearchBox, SIGNAL (startSearch (const CSMTools::Search&)), + this, SLOT (startSearch (const CSMTools::Search&))); } void CSVTools::SearchSubView::setEditLock (bool locked) @@ -48,3 +51,8 @@ void CSVTools::SearchSubView::stateChanged (int state, CSMDoc::Document *documen { mSearchBox.setSearchMode (!(state & CSMDoc::State_Searching)); } + +void CSVTools::SearchSubView::startSearch (const CSMTools::Search& search) +{ + mDocument.runSearch (getUniversalId(), search); +} diff --git a/apps/opencs/view/tools/searchsubview.hpp b/apps/opencs/view/tools/searchsubview.hpp index b389805bb..d17f7a340 100644 --- a/apps/opencs/view/tools/searchsubview.hpp +++ b/apps/opencs/view/tools/searchsubview.hpp @@ -23,6 +23,7 @@ namespace CSVTools ReportTable *mTable; SearchBox mSearchBox; + CSMDoc::Document& mDocument; public: @@ -35,6 +36,8 @@ namespace CSVTools private slots: void stateChanged (int state, CSMDoc::Document *document); + + void startSearch (const CSMTools::Search& search); }; } From 705ee67265ca1028bba2adb143e2219f0c6aab54 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 27 Mar 2015 18:55:48 +0100 Subject: [PATCH 649/740] fixed hints getting mixed up with message text --- apps/opencs/model/tools/search.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index 1b7be6fbf..f37425ea8 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -27,7 +27,7 @@ void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model, message << text.mid (pos).toUtf8().data(); std::ostringstream hint; - message << "r: " << index.column() << " " << pos << " " << search.length(); + hint << "r: " << index.column() << " " << pos << " " << search.length(); messages.add (id, message.str(), hint.str()); @@ -54,7 +54,7 @@ void CSMTools::Search::searchRegExCell (const CSMWorld::IdTableBase *model, int length = mRegExp.matchedLength(); std::ostringstream hint; - message << "r: " << index.column() << " " << pos << " " << length; + hint << "r: " << index.column() << " " << pos << " " << length; messages.add (id, message.str(), hint.str()); @@ -79,7 +79,7 @@ void CSMTools::Search::searchRecordStateCell (const CSMWorld::IdTableBase *model message << id.getId() << " " << states.at (data); std::ostringstream hint; - message << "r: " << index.column(); + hint << "r: " << index.column(); messages.add (id, message.str(), hint.str()); } From babefacbfac1a2411469620a518632ae9cf05a82 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 27 Mar 2015 19:10:45 +0100 Subject: [PATCH 650/740] improved message text in search results --- apps/opencs/model/tools/search.cpp | 19 ++++++++++++++++--- apps/opencs/model/tools/search.hpp | 2 ++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index f37425ea8..9e22f82dd 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -24,7 +24,7 @@ void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model, while ((pos = text.indexOf (search, pos, Qt::CaseInsensitive))!=-1) { std::ostringstream message; - message << text.mid (pos).toUtf8().data(); + message << getLocation (model, index, id) << text.mid (pos).toUtf8().data(); std::ostringstream hint; hint << "r: " << index.column() << " " << pos << " " << search.length(); @@ -49,7 +49,7 @@ void CSMTools::Search::searchRegExCell (const CSMWorld::IdTableBase *model, while ((pos = mRegExp.indexIn (text, pos))!=-1) { std::ostringstream message; - message << text.mid (pos).toUtf8().data(); + message << getLocation (model, index, id) << text.mid (pos).toUtf8().data(); int length = mRegExp.matchedLength(); @@ -76,7 +76,7 @@ void CSMTools::Search::searchRecordStateCell (const CSMWorld::IdTableBase *model CSMWorld::Columns::getEnums (CSMWorld::Columns::ColumnId_Modification); std::ostringstream message; - message << id.getId() << " " << states.at (data); + message << getLocation (model, index, id) << states.at (data); std::ostringstream hint; hint << "r: " << index.column(); @@ -85,6 +85,19 @@ void CSMTools::Search::searchRecordStateCell (const CSMWorld::IdTableBase *model } } +std::string CSMTools::Search::getLocation (const CSMWorld::IdTableBase *model, const QModelIndex& index, const CSMWorld::UniversalId& id) const +{ + std::ostringstream stream; + + stream + << id.getId() + << ", " + << model->headerData (index.column(), Qt::Horizontal).toString().toUtf8().data() + << ": "; + + return stream.str(); +} + CSMTools::Search::Search() : mType (Type_None) {} CSMTools::Search::Search (Type type, const std::string& value) diff --git a/apps/opencs/model/tools/search.hpp b/apps/opencs/model/tools/search.hpp index 3683f9c9b..7e95a2846 100644 --- a/apps/opencs/model/tools/search.hpp +++ b/apps/opencs/model/tools/search.hpp @@ -55,6 +55,8 @@ namespace CSMTools void searchRecordStateCell (const CSMWorld::IdTableBase *model, const QModelIndex& index, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) const; + + std::string getLocation (const CSMWorld::IdTableBase *model, const QModelIndex& index, const CSMWorld::UniversalId& id) const; public: From be6ee927b906313cc7a19ed4298da725c22aebbd Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 28 Mar 2015 20:05:54 +1300 Subject: [PATCH 651/740] AiWander, use closest two points if distance is too small (Fixes #1317) In AiWander, if wander distance is set too small to get two points, take the closest two points. --- apps/openmw/mwmechanics/aiwander.cpp | 30 ++++++++++++++++++++++++++-- apps/openmw/mwmechanics/aiwander.hpp | 7 +++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index d277b1249..560e756ce 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -686,7 +686,8 @@ namespace MWMechanics // If there is no path this actor doesn't go anywhere. See: // https://forum.openmw.org/viewtopic.php?t=1556 // http://www.fliggerty.com/phpBB3/viewtopic.php?f=30&t=5833 - if(!pathgrid || pathgrid->mPoints.empty()) + // Note: In order to wander, need at least two points. + if(!pathgrid || (pathgrid->mPoints.size() < 2)) mDistance = 0; // A distance value passed into the constructor indicates how far the @@ -730,12 +731,37 @@ namespace MWMechanics } mCurrentNode = mAllowedNodes[index]; mAllowedNodes.erase(mAllowedNodes.begin() + index); + } + + // In vanilla Morrowind, sometimes distance is too small to include at least two points, + // in which case, we will take the two closest points regardless of the wander distance + // This is a backup option, as std::sort is potentially O(n^2) in time. + if (mAllowedNodes.empty()) + { + // Start with list of PathGrid nodes, sorted by distance from actor + std::vector nodeDistances; + for (unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++) + { + float distance = npcPos.squaredDistance(PathFinder::MakeOgreVector3(pathgrid->mPoints[counter])); + nodeDistances.push_back(std::make_pair(distance, &pathgrid->mPoints.at(counter))); + } + std::sort(nodeDistances.begin(), nodeDistances.end(), sortByDistance); - mStoredAvailableNodes = true; // set only if successful in finding allowed nodes + // make closest node the current node + mCurrentNode = *nodeDistances[0].second; + + // give Actor a 2nd node to walk to + mAllowedNodes.push_back(*nodeDistances[1].second); } + mStoredAvailableNodes = true; // set only if successful in finding allowed nodes } } + bool AiWander::sortByDistance(const PathDistance& left, const PathDistance& right) + { + return left.first < right.first; + } + void AiWander::writeState(ESM::AiSequence::AiSequence &sequence) const { std::auto_ptr wander(new ESM::AiSequence::AiWander()); diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 7e138c001..7f8fc5088 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -122,6 +122,13 @@ namespace MWMechanics /// lookup table for converting idleSelect value to groupName static const std::string sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1]; + + /// record distances of pathgrid point nodes to actor + /// first value is distance between actor and node, second value is PathGrid node + typedef std::pair PathDistance; + + /// used to sort array of PathDistance objects into ascending order + static bool sortByDistance(const PathDistance& left, const PathDistance& right); }; From 128ccd81510ab7c216162672801fce24ef9602e1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 28 Mar 2015 11:54:32 +0100 Subject: [PATCH 652/740] improved search type naming --- apps/opencs/model/tools/search.cpp | 12 ++++++------ apps/opencs/model/tools/search.hpp | 4 ++-- apps/opencs/view/tools/searchbox.cpp | 12 ++++++------ 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index 9e22f82dd..b873088de 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -103,14 +103,14 @@ CSMTools::Search::Search() : mType (Type_None) {} CSMTools::Search::Search (Type type, const std::string& value) : mType (type), mText (value) { - if (type!=Type_Text && type!=Type_Reference) + if (type!=Type_Text && type!=Type_Id) throw std::logic_error ("Invalid search parameter (string)"); } CSMTools::Search::Search (Type type, const QRegExp& value) : mType (type), mRegExp (value) { - if (type!=Type_TextRegEx && type!=Type_ReferenceRegEx) + if (type!=Type_TextRegEx && type!=Type_IdRegEx) throw std::logic_error ("Invalid search parameter (RegExp)"); } @@ -150,8 +150,8 @@ void CSMTools::Search::configure (const CSMWorld::IdTableBase *model) break; - case Type_Reference: - case Type_ReferenceRegEx: + case Type_Id: + case Type_IdRegEx: if (CSMWorld::ColumnBase::isId (display)) { @@ -202,13 +202,13 @@ void CSMTools::Search::searchRow (const CSMWorld::IdTableBase *model, int row, switch (mType) { case Type_Text: - case Type_Reference: + case Type_Id: searchTextCell (model, index, id, iter->second, messages); break; case Type_TextRegEx: - case Type_ReferenceRegEx: + case Type_IdRegEx: searchRegExCell (model, index, id, iter->second, messages); break; diff --git a/apps/opencs/model/tools/search.hpp b/apps/opencs/model/tools/search.hpp index 7e95a2846..46ea99686 100644 --- a/apps/opencs/model/tools/search.hpp +++ b/apps/opencs/model/tools/search.hpp @@ -30,8 +30,8 @@ namespace CSMTools { Type_Text = 0, Type_TextRegEx = 1, - Type_Reference = 2, - Type_ReferenceRegEx = 3, + Type_Id = 2, + Type_IdRegEx = 3, Type_RecordState = 4, Type_None }; diff --git a/apps/opencs/view/tools/searchbox.cpp b/apps/opencs/view/tools/searchbox.cpp index 1b11d8a4d..bfae6f50d 100644 --- a/apps/opencs/view/tools/searchbox.cpp +++ b/apps/opencs/view/tools/searchbox.cpp @@ -50,8 +50,8 @@ CSVTools::SearchBox::SearchBox (QWidget *parent) mMode.addItem ("Text"); mMode.addItem ("Text (RegEx)"); - mMode.addItem ("Reference"); - mMode.addItem ("Reference (RegEx)"); + mMode.addItem ("ID"); + mMode.addItem ("ID (RegEx)"); mMode.addItem ("Record State"); mLayout->addWidget (&mMode, 0, 0); @@ -93,12 +93,12 @@ CSMTools::Search CSVTools::SearchBox::getSearch() const switch (type) { case CSMTools::Search::Type_Text: - case CSMTools::Search::Type_Reference: + case CSMTools::Search::Type_Id: return CSMTools::Search (type, std::string (mText.text().toUtf8().data())); case CSMTools::Search::Type_TextRegEx: - case CSMTools::Search::Type_ReferenceRegEx: + case CSMTools::Search::Type_IdRegEx: return CSMTools::Search (type, QRegExp (mText.text().toUtf8().data(), Qt::CaseInsensitive)); @@ -120,8 +120,8 @@ void CSVTools::SearchBox::modeSelected (int index) { case CSMTools::Search::Type_Text: case CSMTools::Search::Type_TextRegEx: - case CSMTools::Search::Type_Reference: - case CSMTools::Search::Type_ReferenceRegEx: + case CSMTools::Search::Type_Id: + case CSMTools::Search::Type_IdRegEx: mInput.setCurrentIndex (0); break; From eaaf816dd3a9d48fb785954188211cb9b5cddda3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 28 Mar 2015 12:05:49 +0100 Subject: [PATCH 653/740] simplified search rules --- apps/opencs/model/tools/search.cpp | 31 +++++++++--------------------- apps/opencs/model/tools/search.hpp | 8 ++++---- 2 files changed, 13 insertions(+), 26 deletions(-) diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index b873088de..2d3e4f952 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -11,7 +11,7 @@ #include "../../model/world/universalid.hpp" void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model, - const QModelIndex& index, const CSMWorld::UniversalId& id, bool multiple, + const QModelIndex& index, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) const { // using QString here for easier handling of case folding. @@ -31,15 +31,12 @@ void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model, messages.add (id, message.str(), hint.str()); - if (!multiple) - break; - pos += search.length(); } } void CSMTools::Search::searchRegExCell (const CSMWorld::IdTableBase *model, - const QModelIndex& index, const CSMWorld::UniversalId& id, bool multiple, + const QModelIndex& index, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) const { QString text = model->data (index).toString(); @@ -58,9 +55,6 @@ void CSMTools::Search::searchRegExCell (const CSMWorld::IdTableBase *model, messages.add (id, message.str(), hint.str()); - if (!multiple) - break; - pos += length; } } @@ -134,7 +128,6 @@ void CSMTools::Search::configure (const CSMWorld::IdTableBase *model) i, Qt::Horizontal, static_cast (CSMWorld::ColumnBase::Role_Display)).toInt()); bool consider = false; - bool multiple = false; switch (mType) { @@ -145,7 +138,6 @@ void CSMTools::Search::configure (const CSMWorld::IdTableBase *model) CSMWorld::ColumnBase::isScript (display)) { consider = true; - multiple = true; } break; @@ -153,14 +145,10 @@ void CSMTools::Search::configure (const CSMWorld::IdTableBase *model) case Type_Id: case Type_IdRegEx: - if (CSMWorld::ColumnBase::isId (display)) - { - consider = true; - } - else if (CSMWorld::ColumnBase::isScript (display)) + if (CSMWorld::ColumnBase::isId (display) || + CSMWorld::ColumnBase::isScript (display)) { consider = true; - multiple = true; } break; @@ -178,7 +166,7 @@ void CSMTools::Search::configure (const CSMWorld::IdTableBase *model) } if (consider) - mColumns.insert (std::make_pair (i, multiple)); + mColumns.insert (i); } mIdColumn = model->findColumnIndex (CSMWorld::Columns::ColumnId_Id); @@ -188,10 +176,9 @@ void CSMTools::Search::configure (const CSMWorld::IdTableBase *model) void CSMTools::Search::searchRow (const CSMWorld::IdTableBase *model, int row, CSMDoc::Messages& messages) const { - for (std::map::const_iterator iter (mColumns.begin()); iter!=mColumns.end(); - ++iter) + for (std::set::const_iterator iter (mColumns.begin()); iter!=mColumns.end(); ++iter) { - QModelIndex index = model->index (row, iter->first); + QModelIndex index = model->index (row, *iter); CSMWorld::UniversalId::Type type = static_cast ( model->data (model->index (row, mTypeColumn)).toInt()); @@ -204,13 +191,13 @@ void CSMTools::Search::searchRow (const CSMWorld::IdTableBase *model, int row, case Type_Text: case Type_Id: - searchTextCell (model, index, id, iter->second, messages); + searchTextCell (model, index, id, messages); break; case Type_TextRegEx: case Type_IdRegEx: - searchRegExCell (model, index, id, iter->second, messages); + searchRegExCell (model, index, id, messages); break; case Type_RecordState: diff --git a/apps/opencs/model/tools/search.hpp b/apps/opencs/model/tools/search.hpp index 46ea99686..81b8840bf 100644 --- a/apps/opencs/model/tools/search.hpp +++ b/apps/opencs/model/tools/search.hpp @@ -2,7 +2,7 @@ #define CSM_TOOLS_SEARCH_H #include -#include +#include #include #include @@ -42,15 +42,15 @@ namespace CSMTools std::string mText; QRegExp mRegExp; int mValue; - std::map mColumns; // column, multiple finds per cell + std::set mColumns; int mIdColumn; int mTypeColumn; void searchTextCell (const CSMWorld::IdTableBase *model, const QModelIndex& index, - const CSMWorld::UniversalId& id, bool multiple, CSMDoc::Messages& messages) const; + const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) const; void searchRegExCell (const CSMWorld::IdTableBase *model, const QModelIndex& index, - const CSMWorld::UniversalId& id, bool multiple, CSMDoc::Messages& messages) const; + const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) const; void searchRecordStateCell (const CSMWorld::IdTableBase *model, const QModelIndex& index, const CSMWorld::UniversalId& id, From 8e9365741f448aa1ab04867fbc7a789d02d795d2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 28 Mar 2015 12:53:01 +0100 Subject: [PATCH 654/740] make search sub-views re-usable (clear before starting a new search) --- apps/opencs/model/tools/reportmodel.cpp | 10 ++++++++++ apps/opencs/model/tools/reportmodel.hpp | 2 ++ apps/opencs/view/tools/reporttable.cpp | 5 +++++ apps/opencs/view/tools/reporttable.hpp | 2 ++ apps/opencs/view/tools/searchsubview.cpp | 1 + 5 files changed, 20 insertions(+) diff --git a/apps/opencs/model/tools/reportmodel.cpp b/apps/opencs/model/tools/reportmodel.cpp index ac9dabb25..acd4728c6 100644 --- a/apps/opencs/model/tools/reportmodel.cpp +++ b/apps/opencs/model/tools/reportmodel.cpp @@ -79,3 +79,13 @@ std::string CSMTools::ReportModel::getHint (int row) const { return mRows.at (row).second.second; } + +void CSMTools::ReportModel::clear() +{ + if (!mRows.empty()) + { + beginRemoveRows (QModelIndex(), 0, mRows.size()-1); + mRows.clear(); + endRemoveRows(); + } +} diff --git a/apps/opencs/model/tools/reportmodel.hpp b/apps/opencs/model/tools/reportmodel.hpp index 709e024a7..71f5bdf73 100644 --- a/apps/opencs/model/tools/reportmodel.hpp +++ b/apps/opencs/model/tools/reportmodel.hpp @@ -34,6 +34,8 @@ namespace CSMTools const CSMWorld::UniversalId& getUniversalId (int row) const; std::string getHint (int row) const; + + void clear(); }; } diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index 809a39fa4..5eb375f46 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -134,3 +134,8 @@ void CSVTools::ReportTable::removeSelection() selectionModel()->clear(); } + +void CSVTools::ReportTable::clear() +{ + mModel->clear(); +} diff --git a/apps/opencs/view/tools/reporttable.hpp b/apps/opencs/view/tools/reporttable.hpp index 7a5b232f9..4b686f2d4 100644 --- a/apps/opencs/view/tools/reporttable.hpp +++ b/apps/opencs/view/tools/reporttable.hpp @@ -43,6 +43,8 @@ namespace CSVTools void updateUserSetting (const QString& name, const QStringList& list); + void clear(); + private slots: void showSelection(); diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index b4a0f893a..4afed2c90 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -54,5 +54,6 @@ void CSVTools::SearchSubView::stateChanged (int state, CSMDoc::Document *documen void CSVTools::SearchSubView::startSearch (const CSMTools::Search& search) { + mTable->clear(); mDocument.runSearch (getUniversalId(), search); } From 13a4fb3fdca30bce5cd7d76f7a7c56e55ff7be1a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 28 Mar 2015 13:05:18 +0100 Subject: [PATCH 655/740] make return key press in search input trigger a new search --- apps/opencs/view/tools/searchbox.cpp | 7 +++++-- apps/opencs/view/tools/searchbox.hpp | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/tools/searchbox.cpp b/apps/opencs/view/tools/searchbox.cpp index bfae6f50d..178dd1f04 100644 --- a/apps/opencs/view/tools/searchbox.cpp +++ b/apps/opencs/view/tools/searchbox.cpp @@ -74,7 +74,9 @@ CSVTools::SearchBox::SearchBox (QWidget *parent) this, SLOT (textChanged (const QString&))); connect (&mSearch, SIGNAL (clicked (bool)), this, SLOT (startSearch (bool))); - + + connect (&mText, SIGNAL (returnPressed()), this, SLOT (startSearch())); + modeSelected (0); updateSearchButton(); @@ -141,5 +143,6 @@ void CSVTools::SearchBox::textChanged (const QString& text) void CSVTools::SearchBox::startSearch (bool checked) { - emit startSearch (getSearch()); + if (mSearch.isEnabled()) + emit startSearch (getSearch()); } diff --git a/apps/opencs/view/tools/searchbox.hpp b/apps/opencs/view/tools/searchbox.hpp index dc975cac9..35c656d16 100644 --- a/apps/opencs/view/tools/searchbox.hpp +++ b/apps/opencs/view/tools/searchbox.hpp @@ -46,7 +46,7 @@ namespace CSVTools void textChanged (const QString& text); - void startSearch (bool checked); + void startSearch (bool checked = true); signals: From c5f1c2127d51fc7252e72ccbe5be6e902c8d19c2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 28 Mar 2015 14:36:28 +0100 Subject: [PATCH 656/740] extend global search to all record and reference tables --- apps/opencs/model/tools/searchoperation.cpp | 11 +++++++++-- apps/opencs/model/world/universalid.cpp | 19 +++++++++++++++++++ apps/opencs/model/world/universalid.hpp | 20 +++++++++++--------- 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/apps/opencs/model/tools/searchoperation.cpp b/apps/opencs/model/tools/searchoperation.cpp index 134b83b72..4512de582 100644 --- a/apps/opencs/model/tools/searchoperation.cpp +++ b/apps/opencs/model/tools/searchoperation.cpp @@ -12,8 +12,15 @@ CSMTools::SearchOperation::SearchOperation (CSMDoc::Document& document) : CSMDoc::Operation (CSMDoc::State_Searching, false) { -appendStage (new SearchStage (&dynamic_cast (*document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells)))); - + std::vector types = CSMWorld::UniversalId::listTypes ( + CSMWorld::UniversalId::Class_RecordList | + CSMWorld::UniversalId::Class_ResourceList + ); + + for (std::vector::const_iterator iter (types.begin()); + iter!=types.end(); ++iter) + appendStage (new SearchStage (&dynamic_cast ( + *document.getData().getTableModel (*iter)))); } void CSMTools::SearchOperation::configure (const Search& search) diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 6aa129f25..fbc942f8e 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -348,6 +348,25 @@ std::vector CSMWorld::UniversalId::listReferenceabl return list; } +std::vector CSMWorld::UniversalId::listTypes (int classes) +{ + std::vector list; + + for (int i=0; sNoArg[i].mName; ++i) + if (sNoArg[i].mClass & classes) + list.push_back (sNoArg[i].mType); + + for (int i=0; sIdArg[i].mName; ++i) + if (sIdArg[i].mClass & classes) + list.push_back (sIdArg[i].mType); + + for (int i=0; sIndexArg[i].mName; ++i) + if (sIndexArg[i].mClass & classes) + list.push_back (sIndexArg[i].mType); + + return list; +} + CSMWorld::UniversalId::Type CSMWorld::UniversalId::getParentType (Type type) { for (int i=0; sIdArg[i].mType; ++i) diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index f01e811ca..0a9fa3847 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -16,16 +16,16 @@ namespace CSMWorld enum Class { Class_None = 0, - Class_Record, - Class_RefRecord, // referenceable record - Class_SubRecord, - Class_RecordList, - Class_Collection, // multiple types of records combined - Class_Transient, // not part of the world data or the project data - Class_NonRecord, // record like data that is not part of the world - Class_Resource, ///< \attention Resource IDs are unique only within the + Class_Record = 1, + Class_RefRecord = 2, // referenceable record + Class_SubRecord = 4, + Class_RecordList = 8, + Class_Collection = 16, // multiple types of records combined + Class_Transient = 32, // not part of the world data or the project data + Class_NonRecord = 64, // record like data that is not part of the world + Class_Resource = 128, ///< \attention Resource IDs are unique only within the /// respective collection - Class_ResourceList + Class_ResourceList = 256 }; enum ArgumentType @@ -181,6 +181,8 @@ namespace CSMWorld static std::vector listReferenceableTypes(); + static std::vector listTypes (int classes); + /// If \a type is a SubRecord, RefRecord or Record type return the type of the table /// that contains records of type \a type. /// Otherwise return Type_None. From 1ec0db231c4d824683c8fd63485f3d50073e5b0f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 28 Mar 2015 14:48:06 +0100 Subject: [PATCH 657/740] add a separate display type for ID column --- apps/opencs/model/world/columnbase.cpp | 2 ++ apps/opencs/model/world/columnbase.hpp | 3 ++- apps/opencs/model/world/columnimp.hpp | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index f4f2310b6..a736c0155 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -73,6 +73,8 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_SoundRes, Display_Texture, Display_Video, + + Display_Id, Display_None }; diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index c49785154..38039c27c 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -103,7 +103,8 @@ namespace CSMWorld Display_Colour, Display_ScriptLines, // console context Display_SoundGeneratorType, - Display_School + Display_School, + Display_Id }; int mColumnId; diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index da14bb495..47b744b7f 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -43,7 +43,7 @@ namespace CSMWorld struct StringIdColumn : public Column { StringIdColumn (bool hidden = false) - : Column (Columns::ColumnId_Id, ColumnBase::Display_String, + : Column (Columns::ColumnId_Id, ColumnBase::Display_Id, hidden ? 0 : ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue) {} From 4042b120130a971e234b08a6a9826d4c15b56d0b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 29 Mar 2015 13:43:11 +0200 Subject: [PATCH 658/740] changed data structure for report model --- apps/opencs/model/tools/reportmodel.cpp | 20 +++++++++++++------- apps/opencs/model/tools/reportmodel.hpp | 12 +++++++++++- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/apps/opencs/model/tools/reportmodel.cpp b/apps/opencs/model/tools/reportmodel.cpp index acd4728c6..cc6c5a44c 100644 --- a/apps/opencs/model/tools/reportmodel.cpp +++ b/apps/opencs/model/tools/reportmodel.cpp @@ -3,6 +3,12 @@ #include +CSMTools::ReportModel::Line::Line (const CSMWorld::UniversalId& id, const std::string& message, + const std::string& hint) +: mId (id), mMessage (message), mHint (hint) +{} + + int CSMTools::ReportModel::rowCount (const QModelIndex & parent) const { if (parent.isValid()) @@ -25,12 +31,12 @@ QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const return QVariant(); if (index.column()==0) - return static_cast (mRows.at (index.row()).first.getType()); + return static_cast (mRows.at (index.row()).mId.getType()); if (index.column()==1) - return QString::fromUtf8 (mRows.at (index.row()).second.first.c_str()); + return QString::fromUtf8 (mRows.at (index.row()).mMessage.c_str()); - return QString::fromUtf8 (mRows.at (index.row()).second.second.c_str()); + return QString::fromUtf8 (mRows.at (index.row()).mHint.c_str()); } QVariant CSMTools::ReportModel::headerData (int section, Qt::Orientation orientation, int role) const @@ -64,20 +70,20 @@ void CSMTools::ReportModel::add (const CSMWorld::UniversalId& id, const std::str const std::string& hint) { beginInsertRows (QModelIndex(), mRows.size(), mRows.size()); - - mRows.push_back (std::make_pair (id, std::make_pair (message, hint))); + + mRows.push_back (Line (id, message, hint)); endInsertRows(); } const CSMWorld::UniversalId& CSMTools::ReportModel::getUniversalId (int row) const { - return mRows.at (row).first; + return mRows.at (row).mId; } std::string CSMTools::ReportModel::getHint (int row) const { - return mRows.at (row).second.second; + return mRows.at (row).mHint; } void CSMTools::ReportModel::clear() diff --git a/apps/opencs/model/tools/reportmodel.hpp b/apps/opencs/model/tools/reportmodel.hpp index 71f5bdf73..64a477b6c 100644 --- a/apps/opencs/model/tools/reportmodel.hpp +++ b/apps/opencs/model/tools/reportmodel.hpp @@ -14,7 +14,17 @@ namespace CSMTools { Q_OBJECT - std::vector > > mRows; + struct Line + { + Line (const CSMWorld::UniversalId& id, const std::string& message, + const std::string& hint); + + CSMWorld::UniversalId mId; + std::string mMessage; + std::string mHint; + }; + + std::vector mRows; public: From a8cdd30124669136d360be0c869c9f1182ea8655 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 29 Mar 2015 13:55:31 +0200 Subject: [PATCH 659/740] added ID column to report table --- apps/opencs/model/tools/reportmodel.cpp | 44 ++++++++++++++++++------- apps/opencs/model/tools/reportmodel.hpp | 5 +++ 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/apps/opencs/model/tools/reportmodel.cpp b/apps/opencs/model/tools/reportmodel.cpp index cc6c5a44c..218f391c9 100644 --- a/apps/opencs/model/tools/reportmodel.cpp +++ b/apps/opencs/model/tools/reportmodel.cpp @@ -22,7 +22,7 @@ int CSMTools::ReportModel::columnCount (const QModelIndex & parent) const if (parent.isValid()) return 0; - return 3; + return 4; } QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const @@ -30,13 +30,32 @@ QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const if (role!=Qt::DisplayRole) return QVariant(); - if (index.column()==0) - return static_cast (mRows.at (index.row()).mId.getType()); + switch (index.column()) + { + case Column_Type: + + return static_cast (mRows.at (index.row()).mId.getType()); + + case Column_Id: + { + CSMWorld::UniversalId id = mRows.at (index.row()).mId; + + if (id.getArgumentType()==CSMWorld::UniversalId::ArgumentType_Id) + return QString::fromUtf8 (id.getId().c_str()); - if (index.column()==1) - return QString::fromUtf8 (mRows.at (index.row()).mMessage.c_str()); + return QString ("-"); + } + + case Column_Description: - return QString::fromUtf8 (mRows.at (index.row()).mHint.c_str()); + return QString::fromUtf8 (mRows.at (index.row()).mMessage.c_str()); + + case Column_Hint: + + return QString::fromUtf8 (mRows.at (index.row()).mHint.c_str()); + } + + return QVariant(); } QVariant CSMTools::ReportModel::headerData (int section, Qt::Orientation orientation, int role) const @@ -47,13 +66,14 @@ QVariant CSMTools::ReportModel::headerData (int section, Qt::Orientation orienta if (orientation==Qt::Vertical) return QVariant(); - if (section==0) - return "Type"; - - if (section==1) - return "Description"; + switch (section) + { + case Column_Type: return "Type"; + case Column_Id: return "ID"; + case Column_Description: return "Description"; + } - return "Hint"; + return "-"; } bool CSMTools::ReportModel::removeRows (int row, int count, const QModelIndex& parent) diff --git a/apps/opencs/model/tools/reportmodel.hpp b/apps/opencs/model/tools/reportmodel.hpp index 64a477b6c..5f39316aa 100644 --- a/apps/opencs/model/tools/reportmodel.hpp +++ b/apps/opencs/model/tools/reportmodel.hpp @@ -26,6 +26,11 @@ namespace CSMTools std::vector mRows; + enum Columns + { + Column_Type = 0, Column_Id = 1, Column_Hint = 2, Column_Description = 3 + }; + public: virtual int rowCount (const QModelIndex & parent = QModelIndex()) const; From 416b8165cdbd694a8a6690361ef585a2a5adfa52 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 29 Mar 2015 15:28:11 +0200 Subject: [PATCH 660/740] moved getColumnId function from IdTable to IdTable base and made it virtual --- apps/opencs/model/world/idtable.hpp | 2 +- apps/opencs/model/world/idtablebase.hpp | 2 ++ apps/opencs/model/world/resourcetable.cpp | 11 +++++++++++ apps/opencs/model/world/resourcetable.hpp | 2 ++ 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index ea8ab80f9..6f4be7178 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -82,7 +82,7 @@ namespace CSMWorld /// Is \a id flagged as deleted? virtual bool isDeleted (const std::string& id) const; - int getColumnId(int column) const; + virtual int getColumnId(int column) const; }; } diff --git a/apps/opencs/model/world/idtablebase.hpp b/apps/opencs/model/world/idtablebase.hpp index ef5a9c42e..0d77d48ef 100644 --- a/apps/opencs/model/world/idtablebase.hpp +++ b/apps/opencs/model/world/idtablebase.hpp @@ -60,6 +60,8 @@ namespace CSMWorld /// Is \a id flagged as deleted? 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/resourcetable.cpp b/apps/opencs/model/world/resourcetable.cpp index 9257b9d2a..36e2b3f3d 100644 --- a/apps/opencs/model/world/resourcetable.cpp +++ b/apps/opencs/model/world/resourcetable.cpp @@ -144,3 +144,14 @@ bool CSMWorld::ResourceTable::isDeleted (const std::string& id) const { return false; } + +int CSMWorld::ResourceTable::getColumnId (int column) const +{ + switch (column) + { + case 0: return Columns::ColumnId_Id; + case 1: return Columns::ColumnId_RecordType; + } + + return -1; +} diff --git a/apps/opencs/model/world/resourcetable.hpp b/apps/opencs/model/world/resourcetable.hpp index f5011ab2b..88dcc24b0 100644 --- a/apps/opencs/model/world/resourcetable.hpp +++ b/apps/opencs/model/world/resourcetable.hpp @@ -51,6 +51,8 @@ namespace CSMWorld /// Is \a id flagged as deleted? virtual bool isDeleted (const std::string& id) const; + + virtual int getColumnId (int column) const; }; } From e8091c4e7e21964187d8edd50c5d45685629c7bb Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 29 Mar 2015 15:28:31 +0200 Subject: [PATCH 661/740] added field column to report table --- apps/opencs/model/tools/reportmodel.cpp | 51 ++++++++++++++++++++++--- apps/opencs/model/tools/reportmodel.hpp | 9 ++++- apps/opencs/model/tools/search.cpp | 6 ++- apps/opencs/model/tools/tools.cpp | 2 +- 4 files changed, 59 insertions(+), 9 deletions(-) diff --git a/apps/opencs/model/tools/reportmodel.cpp b/apps/opencs/model/tools/reportmodel.cpp index 218f391c9..627199c22 100644 --- a/apps/opencs/model/tools/reportmodel.cpp +++ b/apps/opencs/model/tools/reportmodel.cpp @@ -2,12 +2,29 @@ #include "reportmodel.hpp" #include +#include + +#include "../world/columns.hpp" CSMTools::ReportModel::Line::Line (const CSMWorld::UniversalId& id, const std::string& message, const std::string& hint) : mId (id), mMessage (message), mHint (hint) {} +CSMTools::ReportModel::ReportModel (bool fieldColumn) +{ + if (fieldColumn) + { + mColumnField = 3; + mColumnDescription = 4; + } + else + { + mColumnDescription = 3; + + mColumnField = -1; + } +} int CSMTools::ReportModel::rowCount (const QModelIndex & parent) const { @@ -22,7 +39,7 @@ int CSMTools::ReportModel::columnCount (const QModelIndex & parent) const if (parent.isValid()) return 0; - return 4; + return mColumnDescription+1; } QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const @@ -46,15 +63,32 @@ QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const return QString ("-"); } - case Column_Description: - - return QString::fromUtf8 (mRows.at (index.row()).mMessage.c_str()); - case Column_Hint: return QString::fromUtf8 (mRows.at (index.row()).mHint.c_str()); } + if (index.column()==mColumnDescription) + return QString::fromUtf8 (mRows.at (index.row()).mMessage.c_str()); + + if (index.column()==mColumnField) + { + std::string field; + + std::istringstream stream (mRows.at (index.row()).mHint); + + char type, ignore; + int fieldIndex; + + if ((stream >> type >> ignore >> fieldIndex) && type=='r') + { + field = CSMWorld::Columns::getName ( + static_cast (fieldIndex)); + } + + return QString::fromUtf8 (field.c_str()); + } + return QVariant(); } @@ -70,9 +104,14 @@ QVariant CSMTools::ReportModel::headerData (int section, Qt::Orientation orienta { case Column_Type: return "Type"; case Column_Id: return "ID"; - case Column_Description: return "Description"; } + if (section==mColumnDescription) + return "Description"; + + if (section==mColumnField) + return "Field"; + return "-"; } diff --git a/apps/opencs/model/tools/reportmodel.hpp b/apps/opencs/model/tools/reportmodel.hpp index 5f39316aa..7e733fab6 100644 --- a/apps/opencs/model/tools/reportmodel.hpp +++ b/apps/opencs/model/tools/reportmodel.hpp @@ -26,13 +26,20 @@ namespace CSMTools std::vector mRows; + // Fixed columns enum Columns { - Column_Type = 0, Column_Id = 1, Column_Hint = 2, Column_Description = 3 + Column_Type = 0, Column_Id = 1, Column_Hint = 2 }; + // Configurable columns + int mColumnDescription; + int mColumnField; + public: + ReportModel (bool fieldColumn = false); + virtual int rowCount (const QModelIndex & parent = QModelIndex()) const; virtual int columnCount (const QModelIndex & parent = QModelIndex()) const; diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index 2d3e4f952..a0eb429b0 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -27,7 +27,11 @@ void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model, message << getLocation (model, index, id) << text.mid (pos).toUtf8().data(); std::ostringstream hint; - hint << "r: " << index.column() << " " << pos << " " << search.length(); + hint + << "r: " + << model->getColumnId (index.column()) + << " " << pos + << " " << search.length(); messages.add (id, message.str(), hint.str()); diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 957e20296..970a8ac4f 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -147,7 +147,7 @@ CSMWorld::UniversalId CSMTools::Tools::runVerifier() CSMWorld::UniversalId CSMTools::Tools::newSearch() { - mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel)); + mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel (true))); return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Search, mNextReportNumber-1); } From 46ccd27a6de028a4e7459a850f26f413289d9011 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 29 Mar 2015 18:16:43 +0200 Subject: [PATCH 662/740] improved find result text --- apps/opencs/model/tools/search.cpp | 48 ++++++++++++++++++------------ apps/opencs/model/tools/search.hpp | 2 +- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index a0eb429b0..9f1beb064 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -23,9 +23,6 @@ void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model, while ((pos = text.indexOf (search, pos, Qt::CaseInsensitive))!=-1) { - std::ostringstream message; - message << getLocation (model, index, id) << text.mid (pos).toUtf8().data(); - std::ostringstream hint; hint << "r: " @@ -33,7 +30,7 @@ void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model, << " " << pos << " " << search.length(); - messages.add (id, message.str(), hint.str()); + messages.add (id, formatDescription (text, pos, search.length()).toUtf8().data(), hint.str()); pos += search.length(); } @@ -49,15 +46,12 @@ void CSMTools::Search::searchRegExCell (const CSMWorld::IdTableBase *model, while ((pos = mRegExp.indexIn (text, pos))!=-1) { - std::ostringstream message; - message << getLocation (model, index, id) << text.mid (pos).toUtf8().data(); - int length = mRegExp.matchedLength(); std::ostringstream hint; - hint << "r: " << index.column() << " " << pos << " " << length; + hint << "r: " << model->getColumnId (index.column()) << " " << pos << " " << length; - messages.add (id, message.str(), hint.str()); + messages.add (id, formatDescription (text, pos, length).toUtf8().data(), hint.str()); pos += length; } @@ -74,26 +68,42 @@ void CSMTools::Search::searchRecordStateCell (const CSMWorld::IdTableBase *model CSMWorld::Columns::getEnums (CSMWorld::Columns::ColumnId_Modification); std::ostringstream message; - message << getLocation (model, index, id) << states.at (data); + message << states.at (data); std::ostringstream hint; - hint << "r: " << index.column(); + hint << "r: " << model->getColumnId (index.column()); messages.add (id, message.str(), hint.str()); } } -std::string CSMTools::Search::getLocation (const CSMWorld::IdTableBase *model, const QModelIndex& index, const CSMWorld::UniversalId& id) const +QString CSMTools::Search::formatDescription (const QString& description, int pos, int length) const { - std::ostringstream stream; + int padding = 10; ///< \todo make this configurable + + if (posheaderData (index.column(), Qt::Horizontal).toString().toUtf8().data() - << ": "; + QString text = description.mid (pos, length); + + // compensate for Windows nonsense + text.remove ('\r'); - return stream.str(); + // improve layout for single line display + text.replace ("\n", ""); + text.replace ('\t', ' '); + + return text; } CSMTools::Search::Search() : mType (Type_None) {} diff --git a/apps/opencs/model/tools/search.hpp b/apps/opencs/model/tools/search.hpp index 81b8840bf..320323f03 100644 --- a/apps/opencs/model/tools/search.hpp +++ b/apps/opencs/model/tools/search.hpp @@ -56,7 +56,7 @@ namespace CSMTools const QModelIndex& index, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) const; - std::string getLocation (const CSMWorld::IdTableBase *model, const QModelIndex& index, const CSMWorld::UniversalId& id) const; + QString formatDescription (const QString& description, int pos, int length) const; public: From 6d165dabb64ab1475cdec15c99435019530b5622 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 29 Mar 2015 18:21:18 +0200 Subject: [PATCH 663/740] improved layout of report table --- apps/opencs/view/tools/reporttable.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index 5eb375f46..5bf1fa848 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -71,6 +71,7 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, : CSVWorld::DragRecordTable (document, parent), mModel (document.getReport (id)) { horizontalHeader()->setResizeMode (QHeaderView::Interactive); + horizontalHeader()->setStretchLastSection (true); verticalHeader()->hide(); setSortingEnabled (true); setSelectionBehavior (QAbstractItemView::SelectRows); From 3d280a6ba54c192ae6a3e9ebaef7621985dc0f3d Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 30 Mar 2015 11:19:37 +1100 Subject: [PATCH 664/740] Fixed the display issues of the nested tables in the dialogue subview. Needs further work but usable for now. --- apps/opencs/model/world/columns.cpp | 32 +++++---- apps/opencs/model/world/columns.hpp | 76 +++++++++++----------- apps/opencs/view/world/dialoguesubview.cpp | 75 ++++++++++++++------- 3 files changed, 109 insertions(+), 74 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index c8bf8ad64..1d3bc7641 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -24,7 +24,6 @@ namespace CSMWorld { ColumnId_ValueType, "Value Type" }, { ColumnId_Description, "Description" }, { ColumnId_Specialisation, "Specialisation" }, - { ColumnId_Skill, "Skill" }, { ColumnId_Attribute, "Attribute" }, { ColumnId_Name, "Name" }, { ColumnId_Playable, "Playable" }, @@ -174,10 +173,11 @@ namespace CSMWorld { ColumnId_Gender, "Gender" }, { ColumnId_PcRank, "PC Rank" }, { ColumnId_ReferenceableId, "Referenceable ID" }, - { ColumnId_NpcDestinations, "Destinations" }, + + { ColumnId_ContainerContent, "Content" }, + { ColumnId_ItemCount, "Count" }, { ColumnId_InventoryItemId, "ID"}, - { ColumnId_SpellId, "ID"}, - { ColumnId_ItemCount, "Count"}, + { ColumnId_CombatState, "Combat" }, { ColumnId_MagicState, "Magic" }, { ColumnId_StealthState, "Stealth" }, @@ -185,6 +185,22 @@ namespace CSMWorld { ColumnId_Vampire, "Vampire" }, { ColumnId_BodyPartType, "Bodypart Type" }, { ColumnId_MeshType, "Mesh Type" }, + + { ColumnId_ActorInventory, "Inventory" }, + { ColumnId_ActorSpells, "Spells" }, + { ColumnId_SpellId, "ID"}, + + { ColumnId_NpcDestinations, "Destinations" }, + { ColumnId_DestinationCell, "Cell"}, + { ColumnId_PosX, "X"}, + { ColumnId_PosY, "Y"}, + { ColumnId_PosZ, "Z"}, + { ColumnId_RotX, "Rotation X"}, + { ColumnId_RotY, "Rotation Y"}, + { ColumnId_RotZ, "Rotation Z"}, + + { ColumnId_Skill, "Skill" }, + { ColumnId_OwnerGlobal, "Owner Global" }, { ColumnId_DefaultProfile, "Default Profile" }, { ColumnId_BypassNewGame, "Bypass New Game" }, @@ -206,14 +222,6 @@ namespace CSMWorld { ColumnId_HitSound, "Hit Sound" }, { ColumnId_AreaSound, "Area Sound" }, { ColumnId_BoltSound, "Bolt Sound" }, - - { ColumnId_NpcDestinations, "Cell"}, - { ColumnId_PosX, "X"}, - { ColumnId_PosY, "Y"}, - { ColumnId_PosZ, "Z"}, - { ColumnId_RotX, "Rotation X"}, - { ColumnId_RotY, "Rotation Y"}, - { ColumnId_RotZ, "Rotation Z"}, { 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 69bbfa39f..1c0af217b 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -167,50 +167,50 @@ namespace CSMWorld ColumnId_Rank = 152, ColumnId_Gender = 153, ColumnId_PcRank = 154, - ColumnId_ReferenceableId = 156, - ColumnId_ContainerContent = 157, - ColumnId_ItemCount = 158, - ColumnId_InventoryItemId = 159, - ColumnId_CombatState = 160, - ColumnId_MagicState = 161, - ColumnId_StealthState = 162, - ColumnId_EnchantmentType = 163, - ColumnId_Vampire = 164, - ColumnId_BodyPartType = 165, - ColumnId_MeshType = 166, - ColumnId_ActorInventory = 167, - ColumnId_ActorSpells = 168, - ColumnId_SpellId = 169, - ColumnId_NpcDestinations = 170, + ColumnId_ReferenceableId = 155, + ColumnId_ContainerContent = 156, + ColumnId_ItemCount = 157, + ColumnId_InventoryItemId = 158, + ColumnId_CombatState = 159, + ColumnId_MagicState = 160, + ColumnId_StealthState = 161, + ColumnId_EnchantmentType = 162, + ColumnId_Vampire = 163, + ColumnId_BodyPartType = 164, + ColumnId_MeshType = 165, + ColumnId_ActorInventory = 166, + ColumnId_ActorSpells = 167, + ColumnId_SpellId = 168, + ColumnId_NpcDestinations = 169, + ColumnId_DestinationCell = 170, ColumnId_PosX = 171, ColumnId_PosY = 172, ColumnId_PosZ = 173, ColumnId_RotX = 174, ColumnId_RotY = 175, ColumnId_RotZ = 176, - ColumnId_DestinationCell = 177, - ColumnId_Skill = 178, - ColumnId_OwnerGlobal = 164, - ColumnId_DefaultProfile = 165, - ColumnId_BypassNewGame = 166, - ColumnId_GlobalProfile = 167, - ColumnId_RefNumCounter = 168, - ColumnId_RefNum = 169, - ColumnId_Creature = 170, - ColumnId_SoundGeneratorType = 171, - ColumnId_AllowSpellmaking = 172, - ColumnId_AllowEnchanting = 173, - ColumnId_BaseCost = 174, - ColumnId_School = 175, - ColumnId_Particle = 176, - ColumnId_CastingObject = 177, - ColumnId_HitObject = 178, - ColumnId_AreaObject = 179, - ColumnId_BoltObject = 180, - ColumnId_CastingSound = 177, - ColumnId_HitSound = 178, - ColumnId_AreaSound = 179, - ColumnId_BoltSound = 180, + ColumnId_Skill = 177, + ColumnId_OwnerGlobal = 178, + ColumnId_DefaultProfile = 179, + ColumnId_BypassNewGame = 180, + ColumnId_GlobalProfile = 181, + ColumnId_RefNumCounter = 182, + ColumnId_RefNum = 183, + ColumnId_Creature = 184, + ColumnId_SoundGeneratorType = 185, + ColumnId_AllowSpellmaking = 186, + ColumnId_AllowEnchanting = 187, + ColumnId_BaseCost = 188, + ColumnId_School = 189, + ColumnId_Particle = 190, + ColumnId_CastingObject = 191, + ColumnId_HitObject = 192, + ColumnId_AreaObject = 193, + ColumnId_BoltObject = 194, + ColumnId_CastingSound = 195, + ColumnId_HitSound = 196, + ColumnId_AreaSound = 197, + ColumnId_BoltSound = 198, // 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/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 8d51bbf7e..421e12c13 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "../../model/world/nestedtablemodel.hpp" @@ -139,26 +140,26 @@ void CSVWorld::DialogueDelegateDispatcherProxy::tableMimeDataDropped(const std:: CSMWorld::UniversalId::Type type = data[i].getType(); if (mDisplay == CSMWorld::ColumnBase::Display_Referenceable) { - if ( type == CSMWorld::UniversalId::Type_Activator - || type == CSMWorld::UniversalId::Type_Potion - || type == CSMWorld::UniversalId::Type_Apparatus - || type == CSMWorld::UniversalId::Type_Armor - || type == CSMWorld::UniversalId::Type_Book - || type == CSMWorld::UniversalId::Type_Clothing - || type == CSMWorld::UniversalId::Type_Container - || type == CSMWorld::UniversalId::Type_Creature - || type == CSMWorld::UniversalId::Type_Door - || type == CSMWorld::UniversalId::Type_Ingredient - || type == CSMWorld::UniversalId::Type_CreatureLevelledList - || type == CSMWorld::UniversalId::Type_ItemLevelledList - || type == CSMWorld::UniversalId::Type_Light - || type == CSMWorld::UniversalId::Type_Lockpick - || type == CSMWorld::UniversalId::Type_Miscellaneous - || type == CSMWorld::UniversalId::Type_Npc - || type == CSMWorld::UniversalId::Type_Probe - || type == CSMWorld::UniversalId::Type_Repair - || type == CSMWorld::UniversalId::Type_Static - || type == CSMWorld::UniversalId::Type_Weapon) + if (type == CSMWorld::UniversalId::Type_Activator + || type == CSMWorld::UniversalId::Type_Potion + || type == CSMWorld::UniversalId::Type_Apparatus + || type == CSMWorld::UniversalId::Type_Armor + || type == CSMWorld::UniversalId::Type_Book + || type == CSMWorld::UniversalId::Type_Clothing + || type == CSMWorld::UniversalId::Type_Container + || type == CSMWorld::UniversalId::Type_Creature + || type == CSMWorld::UniversalId::Type_Door + || type == CSMWorld::UniversalId::Type_Ingredient + || type == CSMWorld::UniversalId::Type_CreatureLevelledList + || type == CSMWorld::UniversalId::Type_ItemLevelledList + || type == CSMWorld::UniversalId::Type_Light + || type == CSMWorld::UniversalId::Type_Lockpick + || type == CSMWorld::UniversalId::Type_Miscellaneous + || type == CSMWorld::UniversalId::Type_Npc + || type == CSMWorld::UniversalId::Type_Probe + || type == CSMWorld::UniversalId::Type_Repair + || type == CSMWorld::UniversalId::Type_Static + || type == CSMWorld::UniversalId::Type_Weapon) { type = CSMWorld::UniversalId::Type_Referenceable; } @@ -388,6 +389,12 @@ void CSVWorld::EditWidget::remake(int row) line->setFrameShape(QFrame::HLine); line->setFrameShadow(QFrame::Sunken); + QFrame* line2 = new QFrame(mMainWidget); + line2->setObjectName(QString::fromUtf8("line2")); + line2->setGeometry(QRect(320, 150, 118, 3)); + line2->setFrameShape(QFrame::HLine); + line2->setFrameShadow(QFrame::Sunken); + QVBoxLayout *mainLayout = new QVBoxLayout(mMainWidget); QGridLayout *unlockedLayout = new QGridLayout(); QGridLayout *lockedLayout = new QGridLayout(); @@ -396,7 +403,8 @@ void CSVWorld::EditWidget::remake(int row) mainLayout->addLayout(lockedLayout, 0); mainLayout->addWidget(line, 1); mainLayout->addLayout(unlockedLayout, 2); - mainLayout->addLayout(tablesLayout, 3); + mainLayout->addWidget(line2, 1); + mainLayout->addLayout(tablesLayout, 0); mainLayout->addStretch(1); int unlocked = 0; @@ -416,10 +424,28 @@ void CSVWorld::EditWidget::remake(int row) { mNestedModels.push_back(new CSMWorld::NestedTableModel (mTable->index(row, i), display, mTable)); - NestedTable* table = new NestedTable(mDocument, *(mNestedModels.rbegin()), this); + NestedTable* table = new NestedTable(mDocument, mNestedModels.back(), this); + + int rows = mNestedModels.back()->rowCount(mTable->index(row, i)); + if (rows == 0) rows = 1; // FIXME: quick hack + int rowHeight = table->rowHeight(0); + int tableHeight = (rows * rowHeight) + + table->horizontalHeader()->height() + 2 * table->frameWidth(); + int tableMaxHeight = (5 * rowHeight) + + table->horizontalHeader()->height() + 2 * table->frameWidth(); + if (rows > 1 && rows < 5) + table->setMinimumHeight(tableHeight); + else if (rows > 1) + table->setMinimumHeight(tableMaxHeight); + + QLabel* label = new QLabel (mTable->headerData (i, Qt::Horizontal, Qt::DisplayRole).toString(), mMainWidget); + label->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed); + + tablesLayout->addWidget(label); tablesLayout->addWidget(table); - } else + } + else { mDispatcher.makeDelegate (display); QWidget* editor = mDispatcher.makeEditor (display, (mTable->index (row, i))); @@ -438,7 +464,8 @@ void CSVWorld::EditWidget::remake(int row) lockedLayout->addWidget (label, locked, 0); lockedLayout->addWidget (editor, locked, 1); ++locked; - } else + } + else { unlockedLayout->addWidget (label, unlocked, 0); unlockedLayout->addWidget (editor, unlocked, 1); From 29ef08bb7545e62f15325ad79abce4ece3e5792c Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 30 Mar 2015 11:53:33 +1100 Subject: [PATCH 665/740] Spelling and other consistencies nit pick. --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/collectionbase.hpp | 23 ------------ apps/opencs/model/world/idtable.cpp | 1 + ...{nestedadaptors.cpp => nestedadapters.cpp} | 2 +- ...{nestedadaptors.hpp => nestedadapters.hpp} | 4 +-- apps/opencs/model/world/nestedcollection.hpp | 35 +++++++++++++++++++ apps/opencs/model/world/refidadapter.hpp | 30 ++++++++-------- apps/opencs/model/world/refidadapterimp.hpp | 8 ++--- apps/opencs/model/world/refidcollection.cpp | 24 ++++++------- apps/opencs/model/world/refidcollection.hpp | 5 +-- 10 files changed, 74 insertions(+), 60 deletions(-) rename apps/opencs/model/world/{nestedadaptors.cpp => nestedadapters.cpp} (81%) rename apps/opencs/model/world/{nestedadaptors.hpp => nestedadapters.hpp} (99%) create mode 100644 apps/opencs/model/world/nestedcollection.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 82d9f6977..c9ca60b33 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -26,7 +26,7 @@ opencs_units (model/world opencs_units_noqt (model/world universalid record commands columnbase scriptcontext cell refidcollection refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope - pathgrid landtexture land nestedtablewrapper nestedadaptors + pathgrid landtexture land nestedtablewrapper nestedadapters ) opencs_hdrs_noqt (model/world diff --git a/apps/opencs/model/world/collectionbase.hpp b/apps/opencs/model/world/collectionbase.hpp index 29ac33bc8..ef826e31c 100644 --- a/apps/opencs/model/world/collectionbase.hpp +++ b/apps/opencs/model/world/collectionbase.hpp @@ -13,7 +13,6 @@ namespace CSMWorld { struct ColumnBase; struct RecordBase; - class NestedTableWrapperBase; /// \brief Base class for record collections /// @@ -105,28 +104,6 @@ namespace CSMWorld ///< Return index of column with the given \a id. If no such column exists, an exception is /// thrown. }; - - class NestedCollection : public CollectionBase - { - public: - virtual void addNestedRow(int row, int col, int position) = 0; - - virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const = 0; - - virtual NestedTableWrapperBase* nestedTable(int row, int column) const = 0; - - virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable) = 0; - - virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn) = 0; - - virtual int getNestedRowsCount(int row, int column) const = 0; - - virtual int getNestedColumnsCount(int row, int column) const = 0; - - virtual void removeNestedRows(int row, int column, int subRow) = 0; - - - }; } #endif diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index fc8ac66b7..964b68cd1 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -6,6 +6,7 @@ #include "nestedtablewrapper.hpp" #include "collectionbase.hpp" +#include "nestedcollection.hpp" #include "columnbase.hpp" CSMWorld::IdTable::IdTable (CollectionBase *idCollection, unsigned int features) diff --git a/apps/opencs/model/world/nestedadaptors.cpp b/apps/opencs/model/world/nestedadapters.cpp similarity index 81% rename from apps/opencs/model/world/nestedadaptors.cpp rename to apps/opencs/model/world/nestedadapters.cpp index 1e8425229..1c8b1eff1 100644 --- a/apps/opencs/model/world/nestedadaptors.cpp +++ b/apps/opencs/model/world/nestedadapters.cpp @@ -1,4 +1,4 @@ -#include "nestedadaptors.hpp" +#include "nestedadapters.hpp" CSMWorld::HelperBase::HelperBase(CSMWorld::UniversalId::Type type) : mType(type) diff --git a/apps/opencs/model/world/nestedadaptors.hpp b/apps/opencs/model/world/nestedadapters.hpp similarity index 99% rename from apps/opencs/model/world/nestedadaptors.hpp rename to apps/opencs/model/world/nestedadapters.hpp index cc062e827..ac2a650d4 100644 --- a/apps/opencs/model/world/nestedadaptors.hpp +++ b/apps/opencs/model/world/nestedadapters.hpp @@ -1,5 +1,5 @@ -#ifndef CSM_WORLD_NESTEDADAPTORS_H -#define CSM_WORLD_NESTEDADAPTORS_H +#ifndef CSM_WORLD_NESTEDADAPTERS_H +#define CSM_WORLD_NESTEDADAPTERS_H #include #include diff --git a/apps/opencs/model/world/nestedcollection.hpp b/apps/opencs/model/world/nestedcollection.hpp new file mode 100644 index 000000000..dffa29573 --- /dev/null +++ b/apps/opencs/model/world/nestedcollection.hpp @@ -0,0 +1,35 @@ +#ifndef CSM_WOLRD_NESTEDCOLLECTION_H +#define CSM_WOLRD_NESTEDCOLLECTION_H + +#include "collectionbase.hpp" + +class QVariant; + +namespace CSMWorld +{ + class NestedTableWrapperBase; + + class NestedCollection : public CollectionBase + { + public: + virtual void addNestedRow(int row, int col, int position) = 0; + + virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const = 0; + + virtual NestedTableWrapperBase* nestedTable(int row, int column) const = 0; + + virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable) = 0; + + virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn) = 0; + + virtual int getNestedRowsCount(int row, int column) const = 0; + + virtual int getNestedColumnsCount(int row, int column) const = 0; + + virtual void removeNestedRows(int row, int column, int subRow) = 0; + + + }; +} + +#endif diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index 387ee8606..af7469637 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -4,10 +4,10 @@ #include #include -#include "nestedadaptors.hpp" +#include "nestedadapters.hpp" /*! \brief - * Adaptors acts as indirection layer, abstracting details of the record types (in the wrappers) from the higher levels of model. + * Adapters acts as indirection layer, abstracting details of the record types (in the wrappers) from the higher levels of model. * Please notice that nested adaptor uses helper classes for actually performing any actions. Different record types require different helpers (needs to be created in the subclass and then fetched via member function). * Important point: don't forget to make sure that getData on the nestedColumn returns true (otherwise code will not treat the index pointing to the column as having childs! */ @@ -79,25 +79,25 @@ namespace CSMWorld public: NestedRefIdAdapter(); - + virtual ~NestedRefIdAdapter(); - + virtual void setNestedData (const RefIdColumn *column, RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const; - + virtual QVariant getNestedData (const RefIdColumn *column, const RefIdData& data, int index, int subRowIndex, int subColIndex) const; - + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const; - + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; - + virtual void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const; - + virtual void addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const; - + virtual void setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable); - + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, const RefIdData& data, int index) const; protected: @@ -105,12 +105,12 @@ namespace CSMWorld ///The ownership of the Helper pointers is transfered. ///The ownership of the column pointers it not transfered (it is not surprising, since columns are created by collection). ///You MUST call this method to setup the nested adaptor! - - void addAssocColumn(const std::pair & assocColumn); + + void addAssocColumn(const std::pair & assocColumn); ///Like setAssocColumn, when it is impossible to set all columns at once - + private: - + HelperBase* getHelper(const RefIdColumn *column) const; }; } diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 11befaeec..acc6c40c1 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -12,7 +12,7 @@ #include "refiddata.hpp" #include "universalid.hpp" #include "refidadapter.hpp" -#include "nestedadaptors.hpp" +#include "nestedadapters.hpp" namespace CSMWorld { @@ -509,7 +509,7 @@ namespace CSMWorld assoCol.push_back(std::make_pair(mActors.mInventory, new InventoryHelper(type))); assoCol.push_back(std::make_pair(mActors.mSpells, new SpellsHelper(type))); - + setAssocColumns(assoCol); } @@ -540,7 +540,7 @@ namespace CSMWorld if (column==mActors.mSpells) return true; - + std::map::const_iterator iter = mActors.mServices.find (column); @@ -666,7 +666,7 @@ namespace CSMWorld const RefIdColumn *mOrganic; const RefIdColumn *mRespawn; const RefIdColumn *mContent; - + public: ContainerRefIdAdapter (const NameColumns& columns, const RefIdColumn *weight, diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index ee09cafa1..c48896435 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -27,7 +27,7 @@ bool CSMWorld::RefIdColumn::isUserEditable() const } -CSMWorld::RefIdAdapter& CSMWorld::RefIdCollection::findAdaptor (UniversalId::Type type) const +CSMWorld::RefIdAdapter& CSMWorld::RefIdCollection::findAdapter (UniversalId::Type type) const { std::map::const_iterator iter = mAdapters.find (type); @@ -452,7 +452,7 @@ QVariant CSMWorld::RefIdCollection::getData (int index, int column) const { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (index); - const RefIdAdapter& adaptor = findAdaptor (localIndex.second); + const RefIdAdapter& adaptor = findAdapter (localIndex.second); return adaptor.getData (&mColumns.at (column), mData, localIndex.first); } @@ -461,7 +461,7 @@ QVariant CSMWorld::RefIdCollection::getNestedData (int row, int column, int subR { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex(row); - const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdaptor (localIndex.second)); + const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); return adaptor.getNestedData (&mColumns.at (column), mData, localIndex.first, subRow, subColumn); } @@ -470,7 +470,7 @@ void CSMWorld::RefIdCollection::setData (int index, int column, const QVariant& { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (index); - const RefIdAdapter& adaptor = findAdaptor (localIndex.second); + const RefIdAdapter& adaptor = findAdapter (localIndex.second); adaptor.setData (&mColumns.at (column), mData, localIndex.first, data); } @@ -479,7 +479,7 @@ void CSMWorld::RefIdCollection::setNestedData(int row, int column, const QVarian { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); - const RefIdAdapter& adaptor = findAdaptor (localIndex.second); + const RefIdAdapter& adaptor = findAdapter (localIndex.second); dynamic_cast(adaptor).setNestedData (&mColumns.at (column), mData, localIndex.first, data, subRow, subColumn); } @@ -493,7 +493,7 @@ void CSMWorld::RefIdCollection::removeNestedRows(int row, int column, int subRow { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); - const RefIdAdapter& adaptor = findAdaptor (localIndex.second); + const RefIdAdapter& adaptor = findAdapter (localIndex.second); dynamic_cast(adaptor).removeNestedRow(&mColumns.at (column), mData, localIndex.first, subRow); } @@ -530,7 +530,7 @@ void CSMWorld::RefIdCollection::cloneRecord(const std::string& origin, void CSMWorld::RefIdCollection::appendRecord (const RecordBase& record, UniversalId::Type type) { - std::string id = findAdaptor (type).getId (record); + std::string id = findAdapter (type).getId (record); int index = mData.getAppendIndex (type); @@ -637,7 +637,7 @@ int CSMWorld::RefIdCollection::getNestedRowsCount(int row, int column) const { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); - const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdaptor (localIndex.second)); + const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); return adaptor.getNestedRowsCount(&mColumns.at(column), mData, localIndex.first); } @@ -646,7 +646,7 @@ int CSMWorld::RefIdCollection::getNestedColumnsCount(int row, int column) const { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); - const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdaptor (localIndex.second)); + const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); return adaptor.getNestedColumnsCount(&mColumns.at(column), mData); } @@ -655,7 +655,7 @@ void CSMWorld::RefIdCollection::addNestedRow(int row, int col, int position) { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); - const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdaptor (localIndex.second)); + const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); adaptor.addNestedRow(&mColumns.at(col), mData, localIndex.first, position); } @@ -664,7 +664,7 @@ void CSMWorld::RefIdCollection::setNestedTable(int row, int column, const CSMWor { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); - CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdaptor (localIndex.second)); + CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); adaptor.setNestedTable(&mColumns.at(column), mData, localIndex.first, nestedTable); } @@ -673,7 +673,7 @@ CSMWorld::NestedTableWrapperBase* CSMWorld::RefIdCollection::nestedTable(int row { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); - const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdaptor (localIndex.second)); + const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); return adaptor.nestedTable(&mColumns.at(column), mData, localIndex.first); } diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index 62616d369..ab25c93fa 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -7,6 +7,7 @@ #include "columnbase.hpp" #include "collectionbase.hpp" +#include "nestedcollection.hpp" #include "refiddata.hpp" namespace ESM @@ -45,7 +46,7 @@ namespace CSMWorld private: - RefIdAdapter& findAdaptor (UniversalId::Type) const; + RefIdAdapter& findAdapter (UniversalId::Type) const; ///< Throws an exception if no adaptor for \a Type can be found. public: @@ -71,7 +72,7 @@ namespace CSMWorld virtual QVariant getData (int index, int column) const; virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const; - + virtual NestedTableWrapperBase* nestedTable(int row, int column) const; virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable); From 619b5206cdedfb75a1ecadf5754de129c46211e2 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 30 Mar 2015 16:41:55 +1100 Subject: [PATCH 666/740] More consistency nit pick. --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/idtable.cpp | 10 ++-- ...blemodel.cpp => nestedtableproxymodel.cpp} | 49 +++++++++---------- ...blemodel.hpp => nestedtableproxymodel.hpp} | 26 +++++----- apps/opencs/view/world/dialoguesubview.cpp | 4 +- apps/opencs/view/world/dialoguesubview.hpp | 4 +- apps/opencs/view/world/nestedtable.cpp | 4 +- apps/opencs/view/world/nestedtable.hpp | 6 +-- 8 files changed, 54 insertions(+), 51 deletions(-) rename apps/opencs/model/world/{nestedtablemodel.cpp => nestedtableproxymodel.cpp} (66%) rename apps/opencs/model/world/{nestedtablemodel.hpp => nestedtableproxymodel.hpp} (89%) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index c9ca60b33..5f9559257 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -19,7 +19,7 @@ opencs_hdrs_noqt (model/doc opencs_units (model/world idtable idtableproxymodel regionmap data commanddispatcher - idtablebase resourcetable nestedtablemodel + idtablebase resourcetable nestedtableproxymodel ) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 964b68cd1..c5061b93d 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -51,7 +51,9 @@ QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const parentAdress.second, index.row(), index.column()); - } else { + } + else + { return mIdCollection->getData (index.row(), index.column()); } } @@ -110,7 +112,8 @@ bool CSMWorld::IdTable::setData (const QModelIndex &index, const QVariant &value CSMWorld::IdTable::index (parentAdress.second, mIdCollection->getColumns()-1)); return true; - } else + } + else { return false; } @@ -149,7 +152,8 @@ bool CSMWorld::IdTable::removeRows (int row, int count, const QModelIndex& paren { dynamic_cast(mIdCollection)->removeNestedRows(parent.row(), parent.column(), row+i); } - } else + } + else { beginRemoveRows (parent, row, row+count-1); diff --git a/apps/opencs/model/world/nestedtablemodel.cpp b/apps/opencs/model/world/nestedtableproxymodel.cpp similarity index 66% rename from apps/opencs/model/world/nestedtablemodel.cpp rename to apps/opencs/model/world/nestedtableproxymodel.cpp index 734047b8d..c098e0316 100644 --- a/apps/opencs/model/world/nestedtablemodel.cpp +++ b/apps/opencs/model/world/nestedtableproxymodel.cpp @@ -1,9 +1,9 @@ -#include "nestedtablemodel.hpp" +#include "nestedtableproxymodel.hpp" #include #include "idtable.hpp" -CSMWorld::NestedTableModel::NestedTableModel(const QModelIndex& parent, +CSMWorld::NestedTableProxyModel::NestedTableProxyModel(const QModelIndex& parent, ColumnBase::Display columnId, CSMWorld::IdTable* parentModel) : mParentColumn(parent.column()), @@ -14,10 +14,10 @@ CSMWorld::NestedTableModel::NestedTableModel(const QModelIndex& parent, mId = std::string(parentModel->index(parentRow, 0).data().toString().toUtf8()); QAbstractProxyModel::setSourceModel(parentModel); - + connect(mMainModel, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)), this, SLOT(forwardRowsAboutToInserted(const QModelIndex &, int, int))); - + connect(mMainModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)), this, SLOT(forwardRowsInserted(const QModelIndex &, int, int))); @@ -26,7 +26,7 @@ CSMWorld::NestedTableModel::NestedTableModel(const QModelIndex& parent, connect(mMainModel, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), this, SLOT(forwardRowsRemoved(const QModelIndex &, int, int))); - + connect(mMainModel, SIGNAL(resetStart(const QString&)), this, SLOT(forwardResetStart(const QString&))); @@ -34,7 +34,7 @@ CSMWorld::NestedTableModel::NestedTableModel(const QModelIndex& parent, this, SLOT(forwardResetEnd(const QString&))); } -QModelIndex CSMWorld::NestedTableModel::mapFromSource(const QModelIndex& sourceIndex) const +QModelIndex CSMWorld::NestedTableProxyModel::mapFromSource(const QModelIndex& sourceIndex) const { const QModelIndex& testedParent = mMainModel->parent(sourceIndex); const QModelIndex& parent = mMainModel->getModelIndex (mId, mParentColumn); @@ -46,30 +46,29 @@ QModelIndex CSMWorld::NestedTableModel::mapFromSource(const QModelIndex& sourceI { return QModelIndex(); } - } -QModelIndex CSMWorld::NestedTableModel::mapToSource(const QModelIndex& proxyIndex) const +QModelIndex CSMWorld::NestedTableProxyModel::mapToSource(const QModelIndex& proxyIndex) const { const QModelIndex& parent = mMainModel->getModelIndex (mId, mParentColumn); return mMainModel->index(proxyIndex.row(), proxyIndex.column(), parent); } -int CSMWorld::NestedTableModel::rowCount(const QModelIndex& index) const +int CSMWorld::NestedTableProxyModel::rowCount(const QModelIndex& index) const { assert (!index.isValid()); return mMainModel->rowCount(mMainModel->getModelIndex(mId, mParentColumn)); } -int CSMWorld::NestedTableModel::columnCount(const QModelIndex& parent) const +int CSMWorld::NestedTableProxyModel::columnCount(const QModelIndex& parent) const { assert (!parent.isValid()); return mMainModel->columnCount(mMainModel->getModelIndex(mId, mParentColumn)); } -QModelIndex CSMWorld::NestedTableModel::index(int row, int column, const QModelIndex& parent) const +QModelIndex CSMWorld::NestedTableProxyModel::index(int row, int column, const QModelIndex& parent) const { assert (!parent.isValid()); @@ -87,12 +86,12 @@ QModelIndex CSMWorld::NestedTableModel::index(int row, int column, const QModelI return createIndex(row, column); } -QModelIndex CSMWorld::NestedTableModel::parent(const QModelIndex& index) const +QModelIndex CSMWorld::NestedTableProxyModel::parent(const QModelIndex& index) const { return QModelIndex(); } -QVariant CSMWorld::NestedTableModel::headerData(int section, +QVariant CSMWorld::NestedTableProxyModel::headerData(int section, Qt::Orientation orientation, int role) const { @@ -100,32 +99,32 @@ QVariant CSMWorld::NestedTableModel::headerData(int section, } -bool CSMWorld::NestedTableModel::setData ( const QModelIndex & index, const QVariant & value, int role) +bool CSMWorld::NestedTableProxyModel::setData ( const QModelIndex & index, const QVariant & value, int role) { return mMainModel->setData(mapToSource(index), value, role); } -Qt::ItemFlags CSMWorld::NestedTableModel::flags(const QModelIndex& index) const +Qt::ItemFlags CSMWorld::NestedTableProxyModel::flags(const QModelIndex& index) const { return mMainModel->flags(mMainModel->index(0, mParentColumn)); } -std::string CSMWorld::NestedTableModel::getParentId() const +std::string CSMWorld::NestedTableProxyModel::getParentId() const { return mId; } -int CSMWorld::NestedTableModel::getParentColumn() const +int CSMWorld::NestedTableProxyModel::getParentColumn() const { return mParentColumn; } -CSMWorld::IdTable* CSMWorld::NestedTableModel::model() const +CSMWorld::IdTable* CSMWorld::NestedTableProxyModel::model() const { return mMainModel; } -void CSMWorld::NestedTableModel::forwardRowsAboutToInserted(const QModelIndex& parent, int first, int last) +void CSMWorld::NestedTableProxyModel::forwardRowsAboutToInserted(const QModelIndex& parent, int first, int last) { if (indexIsParent(parent)) { @@ -133,7 +132,7 @@ void CSMWorld::NestedTableModel::forwardRowsAboutToInserted(const QModelIndex& p } } -void CSMWorld::NestedTableModel::forwardRowsInserted(const QModelIndex& parent, int first, int last) +void CSMWorld::NestedTableProxyModel::forwardRowsInserted(const QModelIndex& parent, int first, int last) { if (indexIsParent(parent)) { @@ -141,14 +140,14 @@ void CSMWorld::NestedTableModel::forwardRowsInserted(const QModelIndex& parent, } } -bool CSMWorld::NestedTableModel::indexIsParent(const QModelIndex& index) +bool CSMWorld::NestedTableProxyModel::indexIsParent(const QModelIndex& index) { return (index.isValid() && index.column() == mParentColumn && mMainModel->data(mMainModel->index(index.row(), 0)).toString().toUtf8().constData() == mId); } -void CSMWorld::NestedTableModel::forwardRowsAboutToRemoved(const QModelIndex& parent, int first, int last) +void CSMWorld::NestedTableProxyModel::forwardRowsAboutToRemoved(const QModelIndex& parent, int first, int last) { if (indexIsParent(parent)) { @@ -156,7 +155,7 @@ void CSMWorld::NestedTableModel::forwardRowsAboutToRemoved(const QModelIndex& pa } } -void CSMWorld::NestedTableModel::forwardRowsRemoved(const QModelIndex& parent, int first, int last) +void CSMWorld::NestedTableProxyModel::forwardRowsRemoved(const QModelIndex& parent, int first, int last) { if (indexIsParent(parent)) { @@ -164,13 +163,13 @@ void CSMWorld::NestedTableModel::forwardRowsRemoved(const QModelIndex& parent, i } } -void CSMWorld::NestedTableModel::forwardResetStart(const QString& id) +void CSMWorld::NestedTableProxyModel::forwardResetStart(const QString& id) { if (id.toUtf8() == mId.c_str()) beginResetModel(); } -void CSMWorld::NestedTableModel::forwardResetEnd(const QString& id) +void CSMWorld::NestedTableProxyModel::forwardResetEnd(const QString& id) { if (id.toUtf8() == mId.c_str()) endResetModel(); diff --git a/apps/opencs/model/world/nestedtablemodel.hpp b/apps/opencs/model/world/nestedtableproxymodel.hpp similarity index 89% rename from apps/opencs/model/world/nestedtablemodel.hpp rename to apps/opencs/model/world/nestedtableproxymodel.hpp index 5fea5c006..7ad8fc0c2 100644 --- a/apps/opencs/model/world/nestedtablemodel.hpp +++ b/apps/opencs/model/world/nestedtableproxymodel.hpp @@ -1,5 +1,5 @@ -#ifndef CSM_WOLRD_NESTEDTABLEMODEL_H -#define CSM_WOLRD_NESTEDTABLEMODEL_H +#ifndef CSM_WOLRD_NESTEDTABLEPROXYMODEL_H +#define CSM_WOLRD_NESTEDTABLEPROXYMODEL_H #include @@ -19,7 +19,7 @@ namespace CSMWorld class RecordBase; class IdTable; - class NestedTableModel : public QAbstractProxyModel + class NestedTableProxyModel : public QAbstractProxyModel { Q_OBJECT @@ -28,15 +28,15 @@ namespace CSMWorld std::string mId; public: - NestedTableModel(const QModelIndex& parent, + NestedTableProxyModel(const QModelIndex& parent, ColumnBase::Display displayType, IdTable* parentModel); //parent is the parent of columns to work with. Columnid provides information about the column std::string getParentId() const; - + int getParentColumn() const; - + CSMWorld::IdTable* model() const; virtual QModelIndex mapFromSource(const QModelIndex& sourceIndex) const; @@ -52,27 +52,27 @@ namespace CSMWorld virtual QModelIndex parent(const QModelIndex& index) const; virtual QVariant headerData ( int section, Qt::Orientation orientation, int role ) const; - + virtual bool setData ( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole ); - + virtual Qt::ItemFlags flags(const QModelIndex& index) const; - + private: void setupHeaderVectors(ColumnBase::Display columnId); bool indexIsParent(const QModelIndex& index); - + private slots: void forwardRowsAboutToInserted(const QModelIndex & parent, int first, int last); - + void forwardRowsInserted(const QModelIndex & parent, int first, int last); void forwardRowsAboutToRemoved(const QModelIndex & parent, int first, int last); void forwardRowsRemoved(const QModelIndex & parent, int first, int last); - + void forwardResetStart(const QString& id); - + void forwardResetEnd(const QString& id); }; } diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 421e12c13..e26dcdc9b 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -23,7 +23,7 @@ #include #include -#include "../../model/world/nestedtablemodel.hpp" +#include "../../model/world/nestedtableproxymodel.hpp" #include "../../model/world/columnbase.hpp" #include "../../model/world/idtable.hpp" #include "../../model/world/columns.hpp" @@ -422,7 +422,7 @@ void CSVWorld::EditWidget::remake(int row) if (mTable->hasChildren(mTable->index(row, i))) { - mNestedModels.push_back(new CSMWorld::NestedTableModel (mTable->index(row, i), display, mTable)); + mNestedModels.push_back(new CSMWorld::NestedTableProxyModel (mTable->index(row, i), display, mTable)); NestedTable* table = new NestedTable(mDocument, mNestedModels.back(), this); diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 6ea79aa95..72acb1966 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -21,7 +21,7 @@ class QVBoxLayout; namespace CSMWorld { class IdTable; - class NestedTableModel; + class NestedTableProxyModel; } namespace CSMDoc @@ -165,7 +165,7 @@ namespace CSVWorld QWidget* mMainWidget; CSMWorld::IdTable* mTable; CSMDoc::Document& mDocument; - std::vector mNestedModels; //Plain, raw C pointers, deleted in the dtor + std::vector mNestedModels; //Plain, raw C pointers, deleted in the dtor public: diff --git a/apps/opencs/view/world/nestedtable.cpp b/apps/opencs/view/world/nestedtable.cpp index 14e079c98..1597c81a3 100644 --- a/apps/opencs/view/world/nestedtable.cpp +++ b/apps/opencs/view/world/nestedtable.cpp @@ -1,5 +1,5 @@ #include "nestedtable.hpp" -#include "../../model/world/nestedtablemodel.hpp" +#include "../../model/world/nestedtableproxymodel.hpp" #include "../../model/world/universalid.hpp" #include "../../model/world/commands.hpp" #include "util.hpp" @@ -10,7 +10,7 @@ #include CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document, - CSMWorld::NestedTableModel* model, + CSMWorld::NestedTableProxyModel* model, QWidget* parent) : QTableView(parent), mUndoStack(document.getUndoStack()), diff --git a/apps/opencs/view/world/nestedtable.hpp b/apps/opencs/view/world/nestedtable.hpp index 6b6b6aaba..f41ba4345 100644 --- a/apps/opencs/view/world/nestedtable.hpp +++ b/apps/opencs/view/world/nestedtable.hpp @@ -10,7 +10,7 @@ class QContextMenuEvent; namespace CSMWorld { - class NestedTableModel; + class NestedTableProxyModel; class UniversalId; } @@ -28,11 +28,11 @@ namespace CSVWorld QAction *mAddNewRowAction; QAction *mRemoveRowAction; QUndoStack& mUndoStack; - CSMWorld::NestedTableModel* mModel; + CSMWorld::NestedTableProxyModel* mModel; public: NestedTable(CSMDoc::Document& document, - CSMWorld::NestedTableModel* model, + CSMWorld::NestedTableProxyModel* model, QWidget* parent = NULL); protected: From ece34a1baa2c963d7f5429126c75891c0addd1b4 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 30 Mar 2015 18:14:07 +1100 Subject: [PATCH 667/740] Workaround for crash while exiting the application. --- apps/opencs/model/world/idtable.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index c5061b93d..1c21e64c3 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -14,7 +14,9 @@ CSMWorld::IdTable::IdTable (CollectionBase *idCollection, unsigned int features) {} CSMWorld::IdTable::~IdTable() -{} +{ + mIdCollection = 0; // FIXME: workaround only, should stop QHideEvent calling after destruction +} int CSMWorld::IdTable::rowCount (const QModelIndex & parent) const { @@ -81,6 +83,10 @@ QVariant CSMWorld::IdTable::headerData (int section, QVariant CSMWorld::IdTable::nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role) const { + // FIXME: workaround only, should stop QHideEvent calling after destruction + if (section < 0 || !mIdCollection || section >= mIdCollection->getColumns()) + return QVariant(); + const NestColumn& parentColumn = dynamic_cast(mIdCollection->getColumn(section)); if (orientation==Qt::Vertical) From 4928e3705f7695199efa18406306e25fa04a9c0e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 30 Mar 2015 12:52:08 +0200 Subject: [PATCH 668/740] highlight (bold) search string in results --- apps/opencs/model/tools/search.cpp | 41 +++++++++++++----------- apps/opencs/model/tools/search.hpp | 4 ++- apps/opencs/view/tools/reportsubview.cpp | 2 +- apps/opencs/view/tools/reporttable.cpp | 39 +++++++++++++++++++++- apps/opencs/view/tools/reporttable.hpp | 3 +- apps/opencs/view/tools/searchsubview.cpp | 2 +- 6 files changed, 68 insertions(+), 23 deletions(-) diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index 9f1beb064..e2bab3866 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -79,31 +79,36 @@ void CSMTools::Search::searchRecordStateCell (const CSMWorld::IdTableBase *model QString CSMTools::Search::formatDescription (const QString& description, int pos, int length) const { - int padding = 10; ///< \todo make this configurable - - if (pos" + highlight + "" + after; + // improve layout for single line display - text.replace ("\n", ""); + text.replace ("\n", "<CR>"); text.replace ('\t', ' '); - return text; + return text; +} + +QString CSMTools::Search::flatten (const QString& text) const +{ + QString flat (text); + + flat.replace ("&", "&"); + flat.replace ("<", "<"); + + return flat; } CSMTools::Search::Search() : mType (Type_None) {} diff --git a/apps/opencs/model/tools/search.hpp b/apps/opencs/model/tools/search.hpp index 320323f03..0148beab3 100644 --- a/apps/opencs/model/tools/search.hpp +++ b/apps/opencs/model/tools/search.hpp @@ -57,7 +57,9 @@ namespace CSMTools CSMDoc::Messages& messages) const; QString formatDescription (const QString& description, int pos, int length) const; - + + QString flatten (const QString& text) const; + public: Search(); diff --git a/apps/opencs/view/tools/reportsubview.cpp b/apps/opencs/view/tools/reportsubview.cpp index df1a5298c..492874c01 100644 --- a/apps/opencs/view/tools/reportsubview.cpp +++ b/apps/opencs/view/tools/reportsubview.cpp @@ -6,7 +6,7 @@ CSVTools::ReportSubView::ReportSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) : CSVDoc::SubView (id) { - setWidget (mTable = new ReportTable (document, id, this)); + setWidget (mTable = new ReportTable (document, id, false, this)); connect (mTable, SIGNAL (editRequest (const CSMWorld::UniversalId&, const std::string&)), SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&))); diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index 5bf1fa848..73fee2362 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -6,11 +6,45 @@ #include #include #include +#include +#include +#include #include "../../model/tools/reportmodel.hpp" #include "../../view/world/idtypedelegate.hpp" +namespace CSVTools +{ + class RichTextDelegate : public QStyledItemDelegate + { + public: + + RichTextDelegate (QObject *parent = 0); + + virtual void paint(QPainter *painter, const QStyleOptionViewItem& option, + const QModelIndex& index) const; + }; +} + +CSVTools::RichTextDelegate::RichTextDelegate (QObject *parent) : QStyledItemDelegate (parent) +{} + +void CSVTools::RichTextDelegate::paint(QPainter *painter, const QStyleOptionViewItem& option, + const QModelIndex& index) const +{ + QTextDocument document; + QVariant value = index.data (Qt::DisplayRole); + if (value.isValid() && !value.isNull()) + { + document.setHtml (value.toString()); + painter->translate (option.rect.topLeft()); + document.drawContents (painter); + painter->translate (-option.rect.topLeft()); + } +} + + void CSVTools::ReportTable::contextMenuEvent (QContextMenuEvent *event) { QModelIndexList selectedRows = selectionModel()->selectedRows(); @@ -67,7 +101,7 @@ void CSVTools::ReportTable::mouseDoubleClickEvent (QMouseEvent *event) } CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, - const CSMWorld::UniversalId& id, QWidget *parent) + const CSMWorld::UniversalId& id, bool richTextDescription, QWidget *parent) : CSVWorld::DragRecordTable (document, parent), mModel (document.getReport (id)) { horizontalHeader()->setResizeMode (QHeaderView::Interactive); @@ -85,6 +119,9 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, setItemDelegateForColumn (0, mIdTypeDelegate); + if (richTextDescription) + setItemDelegateForColumn (mModel->columnCount()-1, new RichTextDelegate (this)); + mShowAction = new QAction (tr ("Show"), this); connect (mShowAction, SIGNAL (triggered()), this, SLOT (showSelection())); addAction (mShowAction); diff --git a/apps/opencs/view/tools/reporttable.hpp b/apps/opencs/view/tools/reporttable.hpp index 4b686f2d4..dde6cc634 100644 --- a/apps/opencs/view/tools/reporttable.hpp +++ b/apps/opencs/view/tools/reporttable.hpp @@ -36,8 +36,9 @@ namespace CSVTools public: + /// \param richTextDescription Use rich text in the description column. ReportTable (CSMDoc::Document& document, const CSMWorld::UniversalId& id, - QWidget *parent = 0); + bool richTextDescription, QWidget *parent = 0); virtual std::vector getDraggedRecords() const; diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index 4afed2c90..146b94ef4 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -17,7 +17,7 @@ CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc: layout->addWidget (&mSearchBox); - layout->addWidget (mTable = new ReportTable (document, id), 2); + layout->addWidget (mTable = new ReportTable (document, id, true), 2); QWidget *widget = new QWidget; From cb6caf5e39da6b42fb46ab25edf58ebe1eb5c704 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 30 Mar 2015 22:30:33 +0200 Subject: [PATCH 669/740] added search-related user settings --- apps/opencs/model/settings/usersettings.cpp | 15 +++++++++++++++ apps/opencs/model/tools/search.cpp | 21 +++++++++++++-------- apps/opencs/model/tools/search.hpp | 4 ++++ apps/opencs/view/tools/searchsubview.cpp | 16 ++++++++++++++-- apps/opencs/view/tools/searchsubview.hpp | 2 ++ 5 files changed, 48 insertions(+), 10 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 7dac660c3..7a975c99c 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -208,6 +208,21 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() shiftCtrlDoubleClick->setToolTip ("Action on shift control double click in table:

" + toolTip); } + declareSection ("search", "Search & Replace"); + { + Setting *before = createSetting (Type_SpinBox, "char-before", + "Characters before search string"); + before->setDefaultValue (10); + before->setRange (0, 1000); + before->setToolTip ("Maximum number of character to display in search result before the searched text"); + + Setting *after = createSetting (Type_SpinBox, "char-after", + "Characters after search string"); + after->setDefaultValue (10); + after->setRange (0, 1000); + after->setToolTip ("Maximum number of character to display in search result after the searched text"); + } + { /****************************************************************** * There are three types of values: diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index e2bab3866..28d92f06a 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -85,11 +85,10 @@ QString CSMTools::Search::formatDescription (const QString& description, int pos text.remove ('\r'); // split - int padding = 10; ///< \todo make this configurable - QString highlight = flatten (text.mid (pos, length)); - QString before = flatten (padding<=pos ? text.mid (0, pos) : text.mid (pos-padding, padding)); - QString after = flatten (text.mid (pos+length, padding)); + QString before = flatten (mPaddingBefore<=pos ? + text.mid (0, pos) : text.mid (pos-mPaddingBefore, mPaddingBefore)); + QString after = flatten (text.mid (pos+length, mPaddingAfter)); // join text = before + "" + highlight + "" + after; @@ -111,24 +110,24 @@ QString CSMTools::Search::flatten (const QString& text) const return flat; } -CSMTools::Search::Search() : mType (Type_None) {} +CSMTools::Search::Search() : mType (Type_None), mPaddingBefore (10), mPaddingAfter (10) {} CSMTools::Search::Search (Type type, const std::string& value) -: mType (type), mText (value) +: mType (type), mText (value), mPaddingBefore (10), mPaddingAfter (10) { if (type!=Type_Text && type!=Type_Id) throw std::logic_error ("Invalid search parameter (string)"); } CSMTools::Search::Search (Type type, const QRegExp& value) -: mType (type), mRegExp (value) +: mType (type), mRegExp (value), mPaddingBefore (10), mPaddingAfter (10) { if (type!=Type_TextRegEx && type!=Type_IdRegEx) throw std::logic_error ("Invalid search parameter (RegExp)"); } CSMTools::Search::Search (Type type, int value) -: mType (type), mValue (value) +: mType (type), mValue (value), mPaddingBefore (10), mPaddingAfter (10) { if (type!=Type_RecordState) throw std::logic_error ("invalid search parameter (int)"); @@ -230,3 +229,9 @@ void CSMTools::Search::searchRow (const CSMWorld::IdTableBase *model, int row, } } } + +void CSMTools::Search::setPadding (int before, int after) +{ + mPaddingBefore = before; + mPaddingAfter = after; +} diff --git a/apps/opencs/model/tools/search.hpp b/apps/opencs/model/tools/search.hpp index 0148beab3..452b3cad2 100644 --- a/apps/opencs/model/tools/search.hpp +++ b/apps/opencs/model/tools/search.hpp @@ -45,6 +45,8 @@ namespace CSMTools std::set mColumns; int mIdColumn; int mTypeColumn; + int mPaddingBefore; + int mPaddingAfter; void searchTextCell (const CSMWorld::IdTableBase *model, const QModelIndex& index, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) const; @@ -78,6 +80,8 @@ namespace CSMTools // \attention *this needs to be configured for \a model. void searchRow (const CSMWorld::IdTableBase *model, int row, CSMDoc::Messages& messages) const; + + void setPadding (int before, int after); }; } diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index 146b94ef4..36fd65a2b 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -4,12 +4,13 @@ #include #include "../../model/doc/document.hpp" +#include "../../model/tools/search.hpp" #include "reporttable.hpp" #include "searchbox.hpp" CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) -: CSVDoc::SubView (id), mDocument (document) +: CSVDoc::SubView (id), mDocument (document), mPaddingBefore (10), mPaddingAfter (10) { QVBoxLayout *layout = new QVBoxLayout; @@ -45,6 +46,14 @@ void CSVTools::SearchSubView::setEditLock (bool locked) void CSVTools::SearchSubView::updateUserSetting (const QString &name, const QStringList &list) { mTable->updateUserSetting (name, list); + + if (!list.empty()) + { + if (name=="search/char-before") + mPaddingBefore = list.at (0).toInt(); + else if (name=="search/char-after") + mPaddingAfter = list.at (0).toInt(); + } } void CSVTools::SearchSubView::stateChanged (int state, CSMDoc::Document *document) @@ -54,6 +63,9 @@ void CSVTools::SearchSubView::stateChanged (int state, CSMDoc::Document *documen void CSVTools::SearchSubView::startSearch (const CSMTools::Search& search) { + CSMTools::Search search2 (search); + search2.setPadding (mPaddingBefore, mPaddingAfter); + mTable->clear(); - mDocument.runSearch (getUniversalId(), search); + mDocument.runSearch (getUniversalId(), search2); } diff --git a/apps/opencs/view/tools/searchsubview.hpp b/apps/opencs/view/tools/searchsubview.hpp index d17f7a340..b9b24f774 100644 --- a/apps/opencs/view/tools/searchsubview.hpp +++ b/apps/opencs/view/tools/searchsubview.hpp @@ -24,6 +24,8 @@ namespace CSVTools ReportTable *mTable; SearchBox mSearchBox; CSMDoc::Document& mDocument; + int mPaddingBefore; + int mPaddingAfter; public: From 66c866aec945b0c74939d1c1a317407e9c0bff11 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 31 Mar 2015 13:02:12 +0200 Subject: [PATCH 670/740] fixed search result formatting --- apps/opencs/model/tools/search.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index 28d92f06a..db495be11 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -81,15 +81,15 @@ QString CSMTools::Search::formatDescription (const QString& description, int pos { QString text (description); - // compensate for Windows nonsense - text.remove ('\r'); - // split QString highlight = flatten (text.mid (pos, length)); - QString before = flatten (mPaddingBefore<=pos ? + QString before = flatten (mPaddingBefore>=pos ? text.mid (0, pos) : text.mid (pos-mPaddingBefore, mPaddingBefore)); QString after = flatten (text.mid (pos+length, mPaddingAfter)); + // compensate for Windows nonsense + text.remove ('\r'); + // join text = before + "" + highlight + "" + after; From a9a8b5ad475bfbd80e0f5a390f849083d8507168 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 31 Mar 2015 14:25:27 +0200 Subject: [PATCH 671/740] improved performance of CSVRender::Cell::addObjects by bypassing Qt model --- apps/opencs/view/render/cell.cpp | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index ae2fad95a..a030ea11f 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -10,6 +10,7 @@ #include "../../model/world/idtable.hpp" #include "../../model/world/columns.hpp" #include "../../model/world/data.hpp" +#include "../../model/world/refcollection.hpp" #include "../world/physicssystem.hpp" #include "elements.hpp" @@ -30,26 +31,19 @@ bool CSVRender::Cell::removeObject (const std::string& id) bool CSVRender::Cell::addObjects (int start, int end) { - CSMWorld::IdTable& references = dynamic_cast ( - *mData.getTableModel (CSMWorld::UniversalId::Type_References)); - - int idColumn = references.findColumnIndex (CSMWorld::Columns::ColumnId_Id); - int cellColumn = references.findColumnIndex (CSMWorld::Columns::ColumnId_Cell); - int stateColumn = references.findColumnIndex (CSMWorld::Columns::ColumnId_Modification); - bool modified = false; + const CSMWorld::RefCollection& collection = mData.getReferences(); + for (int i=start; i<=end; ++i) { - std::string cell = Misc::StringUtils::lowerCase (references.data ( - references.index (i, cellColumn)).toString().toUtf8().constData()); + std::string cell = Misc::StringUtils::lowerCase (collection.getRecord (i).get().mCell); - int state = references.data (references.index (i, stateColumn)).toInt(); + CSMWorld::RecordBase::State state = collection.getRecord (i).mState; if (cell==mId && state!=CSMWorld::RecordBase::State_Deleted) { - std::string id = Misc::StringUtils::lowerCase (references.data ( - references.index (i, idColumn)).toString().toUtf8().constData()); + std::string id = Misc::StringUtils::lowerCase (collection.getRecord (i).get().mId); mObjects.insert (std::make_pair (id, new Object (mData, mCellNode, id, false, mPhysics))); modified = true; From 7c9104a29123a428138b7315ac2db3ef43f6d1f7 Mon Sep 17 00:00:00 2001 From: Scott Howard Date: Tue, 31 Mar 2015 22:02:08 -0400 Subject: [PATCH 672/740] fix -Wnewline-eof --- libs/openengine/misc/rng.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/openengine/misc/rng.cpp b/libs/openengine/misc/rng.cpp index 140aa337e..3d50400df 100644 --- a/libs/openengine/misc/rng.cpp +++ b/libs/openengine/misc/rng.cpp @@ -26,4 +26,4 @@ namespace Misc { } } -} \ No newline at end of file +} From d646836cddf54624fa14ce7ace4b1b050b3f2a23 Mon Sep 17 00:00:00 2001 From: Scott Howard Date: Wed, 1 Apr 2015 21:44:41 -0400 Subject: [PATCH 673/740] turn on -Wno-potentially-evaluated-expression on clang --- CMakeLists.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 342fb7e39..07fffd577 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -353,6 +353,14 @@ endif() if (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++98 -pedantic -Wno-long-long") + if (CMAKE_CXX_COMPILER_ID STREQUAL Clang AND NOT APPLE) + execute_process(COMMAND ${CMAKE_C_COMPILER} --version OUTPUT_VARIABLE CLANG_VERSION) + string(REGEX REPLACE ".*version ([0-9\\.]*).*" "\\1" CLANG_VERSION ${CLANG_VERSION}) + if ("${CLANG_VERSION}" VERSION_GREATER 3.6 OR "${CLANG_VERSION}" VERSION_EQUAL 3.6) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-potentially-evaluated-expression") + endif ("${CLANG_VERSION}" VERSION_GREATER 3.6 OR "${CLANG_VERSION}" VERSION_EQUAL 3.6) + endif(CMAKE_CXX_COMPILER_ID STREQUAL Clang AND NOT APPLE) + execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) if (CMAKE_CXX_COMPILER_ID STREQUAL GNU AND "${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6) From 83bcc8d4512c4571421d9602fb0e367c440dc9f1 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 2 Apr 2015 20:19:15 +1100 Subject: [PATCH 674/740] Reorganised class inheritance structure of collections, columns and idtable model. --- apps/opencs/CMakeLists.txt | 5 +- apps/opencs/model/world/columnbase.cpp | 45 +-- apps/opencs/model/world/columnbase.hpp | 39 +-- apps/opencs/model/world/commands.cpp | 13 +- apps/opencs/model/world/commands.hpp | 21 +- apps/opencs/model/world/data.cpp | 3 +- apps/opencs/model/world/idtable.cpp | 206 +----------- apps/opencs/model/world/idtable.hpp | 27 -- apps/opencs/model/world/idtree.cpp | 296 ++++++++++++++++++ apps/opencs/model/world/idtree.hpp | 88 ++++++ apps/opencs/model/world/nestablecolumn.cpp | 44 +++ apps/opencs/model/world/nestablecolumn.hpp | 33 ++ apps/opencs/model/world/nestedcollection.hpp | 10 + .../model/world/nestedtableproxymodel.cpp | 6 +- .../model/world/nestedtableproxymodel.hpp | 8 +- apps/opencs/model/world/refidcollection.cpp | 62 ++-- apps/opencs/model/world/refidcollection.hpp | 45 +-- apps/opencs/model/world/refiddata.hpp | 6 +- apps/opencs/view/world/dialoguesubview.cpp | 3 +- 19 files changed, 589 insertions(+), 371 deletions(-) create mode 100644 apps/opencs/model/world/idtree.cpp create mode 100644 apps/opencs/model/world/idtree.hpp create mode 100644 apps/opencs/model/world/nestablecolumn.cpp create mode 100644 apps/opencs/model/world/nestablecolumn.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 5f9559257..39b4c486b 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -18,15 +18,14 @@ opencs_hdrs_noqt (model/doc opencs_units (model/world - idtable idtableproxymodel regionmap data commanddispatcher - idtablebase resourcetable nestedtableproxymodel + idtable idtableproxymodel regionmap data commanddispatcher idtablebase resourcetable nestedtableproxymodel idtree ) opencs_units_noqt (model/world universalid record commands columnbase scriptcontext cell refidcollection refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope - pathgrid landtexture land nestedtablewrapper nestedadapters + pathgrid landtexture land nestedtablewrapper nestedadapters nestedcollection nestablecolumn ) opencs_hdrs_noqt (model/world diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 60e201ba4..665ab9354 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -1,9 +1,10 @@ + #include "columnbase.hpp" #include "columns.hpp" -CSMWorld::ColumnBase::ColumnBase (int columnId, Display displayType, int flags, bool canNest) - : mColumnId (columnId), mDisplayType (displayType), mFlags (flags), mCanNest(canNest) +CSMWorld::ColumnBase::ColumnBase (int columnId, Display displayType, int flags) +: mColumnId (columnId), mDisplayType (displayType), mFlags (flags) {} CSMWorld::ColumnBase::~ColumnBase() {} @@ -22,43 +23,3 @@ int CSMWorld::ColumnBase::getId() const { return mColumnId; } - -bool CSMWorld::NestColumn::canHaveNestedColumns() const -{ - return mCanNest; -} - -void CSMWorld::NestColumn::addNestedColumn(int columnId, Display displayType) -{ - if (!mCanNest) - throw std::logic_error("Tried to nest inside of the non-nest column"); - - mNestedColumns.push_back(CSMWorld::NestedColumn(columnId, displayType, mFlags, this)); -} - -const CSMWorld::ColumnBase& CSMWorld::NestColumn::nestedColumn(int subColumn) const -{ - if (!mCanNest) - throw std::logic_error("Tried to access nested column of the non-nest column"); - - return mNestedColumns.at(subColumn); -} - -int CSMWorld::NestColumn::nestedColumnCount() const -{ - if (!mCanNest) - throw std::logic_error("Tried to access number of the subcolumns in the non-nest column"); - - return mNestedColumns.size(); -} - -CSMWorld::NestColumn::NestColumn(int columnId, Display displayType, int flags, bool canNest) - : CSMWorld::ColumnBase(columnId, displayType, flags, canNest) {} - -CSMWorld::NestedColumn::NestedColumn(int columnId, Display displayType, int flag, const CSMWorld::NestColumn* parent) - : mParent(parent), CSMWorld::ColumnBase(columnId, displayType, flag) {} - -bool CSMWorld::NestedColumn::isEditable() const -{ - return mParent->isEditable(); -} diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 607f585b7..b717f3a52 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include @@ -117,9 +117,8 @@ namespace CSMWorld int mColumnId; int mFlags; Display mDisplayType; - bool mCanNest; - ColumnBase (int columnId, Display displayType, int flag, bool canNest = false); + ColumnBase (int columnId, Display displayType, int flag); virtual ~ColumnBase(); @@ -133,39 +132,11 @@ namespace CSMWorld virtual int getId() const; }; - class NestedColumn; - - class NestColumn : public ColumnBase - { - std::vector mNestedColumns; - - public: - NestColumn(int columnId, Display displayType, int flags, bool canNest); - - void addNestedColumn(int columnId, Display displayType); - - bool canHaveNestedColumns() const; - - const ColumnBase& nestedColumn(int subColumn) const; - - int nestedColumnCount() const; - }; - - class NestedColumn : public ColumnBase - { - const ColumnBase* mParent; - - public: - NestedColumn(int columnId, Display displayType, int flag, const NestColumn* parent); - - virtual bool isEditable() const; - }; - template - struct Column : public NestColumn + struct Column : public ColumnBase { - Column (int columnId, Display displayType, int flags = Flag_Table | Flag_Dialogue, bool canNest = false) - : NestColumn (columnId, displayType, flags, canNest) {} + Column (int columnId, Display displayType, int flags = Flag_Table | Flag_Dialogue) + : ColumnBase (columnId, displayType, flags) {} virtual QVariant get (const Record& record) const = 0; diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 959f6b345..7acc6058e 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -3,6 +3,7 @@ #include #include "idtable.hpp" +#include "idtree.hpp" #include #include "nestedtablewrapper.hpp" @@ -172,10 +173,10 @@ void CSMWorld::CloneCommand::undo() mModel.removeRow (mModel.getModelIndex (mId, 0).row()); } -CSMWorld::DeleteNestedCommand::DeleteNestedCommand (IdTable& model, +CSMWorld::DeleteNestedCommand::DeleteNestedCommand (IdTree& model, const std::string& id, - int nestedRow, - int parentColumn, + int nestedRow, + int parentColumn, QUndoCommand* parent) : mId(id), mModel(model), @@ -192,7 +193,7 @@ void CSMWorld::DeleteNestedCommand::redo() const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); mModel.removeRows (mNestedRow, 1, parentIndex); -} +} void CSMWorld::DeleteNestedCommand::undo() @@ -202,7 +203,7 @@ void CSMWorld::DeleteNestedCommand::undo() mModel.setNestedTable(parentIndex, getOld()); } -CSMWorld::AddNestedCommand::AddNestedCommand(IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent) +CSMWorld::AddNestedCommand::AddNestedCommand(IdTree& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent) : mModel(model), mId(id), mNewRow(nestedRow), @@ -227,7 +228,7 @@ void CSMWorld::AddNestedCommand::undo() mModel.setNestedTable(parentIndex, getOld()); } -CSMWorld::NestedTableStoring::NestedTableStoring(const IdTable& model, const std::string& id, int parentColumn) +CSMWorld::NestedTableStoring::NestedTableStoring(const IdTree& model, const std::string& id, int parentColumn) : mOld(model.nestedTable(model.getModelIndex(id, parentColumn))) {} CSMWorld::NestedTableStoring::~NestedTableStoring() diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index c194e2779..42405a2f9 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -10,7 +10,6 @@ #include #include #include -#include #include "universalid.hpp" #include "nestedtablewrapper.hpp" @@ -21,7 +20,7 @@ class QAbstractItemModel; namespace CSMWorld { class IdTable; - class IdTable; + class IdTree; struct RecordBase; class NestedTableWrapperBase; @@ -148,18 +147,18 @@ namespace CSMWorld NestedTableWrapperBase* mOld; public: - NestedTableStoring(const IdTable& model, const std::string& id, int parentColumn); - + NestedTableStoring(const IdTree& model, const std::string& id, int parentColumn); + ~NestedTableStoring(); - + protected: const NestedTableWrapperBase& getOld() const; }; - + class DeleteNestedCommand : public QUndoCommand, private NestedTableStoring { - IdTable& mModel; + IdTree& mModel; std::string mId; @@ -169,16 +168,16 @@ namespace CSMWorld public: - DeleteNestedCommand (IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0); + DeleteNestedCommand (IdTree& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0); virtual void redo(); virtual void undo(); }; - + class AddNestedCommand : public QUndoCommand, private NestedTableStoring { - IdTable& mModel; + IdTree& mModel; std::string mId; @@ -188,7 +187,7 @@ namespace CSMWorld public: - AddNestedCommand(IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0); + AddNestedCommand(IdTree& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0); virtual void redo(); diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 39cff3db6..a5ef439a7 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -12,6 +12,7 @@ #include #include "idtable.hpp" +#include "idtree.hpp" #include "columnimp.hpp" #include "regionmap.hpp" #include "columns.hpp" @@ -332,7 +333,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc addModel (new IdTable (&mMagicEffects), UniversalId::Type_MagicEffect); addModel (new IdTable (&mPathgrids), UniversalId::Type_Pathgrid); addModel (new IdTable (&mStartScripts), UniversalId::Type_StartScript); - addModel (new IdTable (&mReferenceables, IdTable::Feature_Preview), + addModel (new IdTree (&mReferenceables, IdTable::Feature_Preview), UniversalId::Type_Referenceable); addModel (new IdTable (&mRefs, IdTable::Feature_ViewCell | IdTable::Feature_Preview), UniversalId::Type_Reference); addModel (new IdTable (&mFilters), UniversalId::Type_Filter); diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 1c21e64c3..7618a073a 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -1,12 +1,6 @@ #include "idtable.hpp" -#include - -#include -#include -#include "nestedtablewrapper.hpp" #include "collectionbase.hpp" -#include "nestedcollection.hpp" #include "columnbase.hpp" CSMWorld::IdTable::IdTable (CollectionBase *idCollection, unsigned int features) @@ -14,26 +8,20 @@ CSMWorld::IdTable::IdTable (CollectionBase *idCollection, unsigned int features) {} CSMWorld::IdTable::~IdTable() -{ - mIdCollection = 0; // FIXME: workaround only, should stop QHideEvent calling after destruction -} +{} int CSMWorld::IdTable::rowCount (const QModelIndex & parent) const { - if (hasChildren(parent)) - { - return dynamic_cast(mIdCollection)->getNestedRowsCount(parent.row(), parent.column()); - } + if (parent.isValid()) + return 0; return mIdCollection->getSize(); } int CSMWorld::IdTable::columnCount (const QModelIndex & parent) const { - if (hasChildren(parent)) - { - return dynamic_cast(mIdCollection)->getNestedColumnsCount(parent.row(), parent.column()); - } + if (parent.isValid()) + return 0; return mIdCollection->getColumns(); } @@ -46,23 +34,10 @@ QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const if (role==Qt::EditRole && !mIdCollection->getColumn (index.column()).isEditable()) return QVariant(); - if (index.internalId() != 0) - { - std::pair parentAdress(unfoldIndexAdress(index.internalId())); - return dynamic_cast(mIdCollection)->getNestedData(parentAdress.first, - parentAdress.second, - index.row(), - index.column()); - } - else - { - return mIdCollection->getData (index.row(), index.column()); - } + return mIdCollection->getData (index.row(), index.column()); } -QVariant CSMWorld::IdTable::headerData (int section, - Qt::Orientation orientation, - int role) const +QVariant CSMWorld::IdTable::headerData (int section, Qt::Orientation orientation, int role) const { if (orientation==Qt::Vertical) return QVariant(); @@ -74,63 +49,19 @@ QVariant CSMWorld::IdTable::headerData (int section, return mIdCollection->getColumn (section).mFlags; if (role==ColumnBase::Role_Display) - { return mIdCollection->getColumn (section).mDisplayType; - } - - return QVariant(); -} - -QVariant CSMWorld::IdTable::nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role) const -{ - // FIXME: workaround only, should stop QHideEvent calling after destruction - if (section < 0 || !mIdCollection || section >= mIdCollection->getColumns()) - return QVariant(); - - const NestColumn& parentColumn = dynamic_cast(mIdCollection->getColumn(section)); - - if (orientation==Qt::Vertical) - return QVariant(); - - if (role==Qt::DisplayRole) - return tr(parentColumn.nestedColumn(subSection).getTitle().c_str()); - - if (role==ColumnBase::Role_Flags) - return mIdCollection->getColumn (section).mFlags; - - if (role==ColumnBase::Role_Display) - return parentColumn.nestedColumn(subSection).mDisplayType; return QVariant(); } bool CSMWorld::IdTable::setData (const QModelIndex &index, const QVariant &value, int role) { - if (index.internalId() != 0) - { - if (mIdCollection->getColumn(parent(index).column()).isEditable() && role==Qt::EditRole) - { - const std::pair& parentAdress(unfoldIndexAdress(index.internalId())); - - dynamic_cast(mIdCollection)->setNestedData(parentAdress.first, parentAdress.second, value, index.row(), index.column()); - - emit dataChanged (CSMWorld::IdTable::index (parentAdress.first, 0), - CSMWorld::IdTable::index (parentAdress.second, mIdCollection->getColumns()-1)); - - return true; - } - else - { - return false; - } - } - if (mIdCollection->getColumn (index.column()).isEditable() && role==Qt::EditRole) { mIdCollection->setData (index.row(), index.column(), value); emit dataChanged (CSMWorld::IdTable::index (index.row(), 0), - CSMWorld::IdTable::index (index.row(), mIdCollection->getColumns()-1)); + CSMWorld::IdTable::index (index.row(), mIdCollection->getColumns()-1)); return true; } @@ -150,56 +81,22 @@ Qt::ItemFlags CSMWorld::IdTable::flags (const QModelIndex & index) const bool CSMWorld::IdTable::removeRows (int row, int count, const QModelIndex& parent) { - beginRemoveRows (parent, row, row+count-1); - if (parent.isValid()) - { - for (int i = 0; i < count; ++i) - { - dynamic_cast(mIdCollection)->removeNestedRows(parent.row(), parent.column(), row+i); - } - } - else - { + return false; - beginRemoveRows (parent, row, row+count-1); + beginRemoveRows (parent, row, row+count-1); - mIdCollection->removeRows (row, count); - } + mIdCollection->removeRows (row, count); endRemoveRows(); - emit dataChanged (CSMWorld::IdTable::index (parent.row(), 0), - CSMWorld::IdTable::index (parent.row(), mIdCollection->getColumns()-1)); - return true; } -void CSMWorld::IdTable::addNestedRow(const QModelIndex& parent, int position) -{ - if (!hasChildren(parent)) - { - throw std::logic_error("Tried to set nested table, but index has no children"); - } - - int row = parent.row(); - - beginInsertRows(parent, position, position); - dynamic_cast(mIdCollection)->addNestedRow(row, parent.column(), position); - - endInsertRows(); - - emit dataChanged (CSMWorld::IdTable::index (row, 0), - CSMWorld::IdTable::index (row, mIdCollection->getColumns()-1)); -} - QModelIndex CSMWorld::IdTable::index (int row, int column, const QModelIndex& parent) const { - unsigned int encodedId = 0; if (parent.isValid()) - { - encodedId = this->foldIndexAdress(parent); - } + return QModelIndex(); if (row<0 || row>=mIdCollection->getSize()) return QModelIndex(); @@ -207,24 +104,12 @@ QModelIndex CSMWorld::IdTable::index (int row, int column, const QModelIndex& pa if (column<0 || column>=mIdCollection->getColumns()) return QModelIndex(); - return createIndex(row, column, encodedId); + return createIndex (row, column); } QModelIndex CSMWorld::IdTable::parent (const QModelIndex& index) const { - if (index.internalId() == 0) //0 is used for indexs with invalid parent (top level data) - { - return QModelIndex(); - } - - unsigned int id = index.internalId(); - const std::pair& adress(unfoldIndexAdress(id)); - - if (adress.first >= this->rowCount() || adress.second >= this->columnCount()) - { - throw "Parent index is not present in the model"; - } - return createIndex(adress.first, adress.second); + return QModelIndex(); } void CSMWorld::IdTable::addRecord (const std::string& id, UniversalId::Type type) @@ -346,66 +231,3 @@ int CSMWorld::IdTable::getColumnId(int column) const { return mIdCollection->getColumn(column).getId(); } - -unsigned int CSMWorld::IdTable::foldIndexAdress (const QModelIndex& index) const -{ - unsigned int out = index.row() * this->columnCount(); - out += index.column(); - return ++out; -} - -std::pair< int, int > CSMWorld::IdTable::unfoldIndexAdress (unsigned int id) const -{ - if (id == 0) - { - throw "Attempt to unfold index id of the top level data cell"; - } - - --id; - int row = id / this->columnCount(); - int column = id - row * this->columnCount(); - return std::make_pair (row, column); -} - -bool CSMWorld::IdTable::hasChildren(const QModelIndex& index) const -{ - return (index.isValid() && - index.internalId() == 0 && - mIdCollection->getColumn(index.column()).mCanNest && - index.data().isValid()); -} - -void CSMWorld::IdTable::setNestedTable(const QModelIndex& index, const CSMWorld::NestedTableWrapperBase& nestedTable) -{ - if (!hasChildren(index)) - { - throw std::logic_error("Tried to set nested table, but index has no children"); - } - - bool removeRowsMode = false; - if (nestedTable.size() != this->nestedTable(index)->size()) - { - emit resetStart(this->index(index.row(), 0).data().toString()); - removeRowsMode = true; - } - - dynamic_cast(mIdCollection)->setNestedTable(index.row(), index.column(), nestedTable); - - emit dataChanged (CSMWorld::IdTable::index (index.row(), 0), - CSMWorld::IdTable::index (index.row(), mIdCollection->getColumns()-1)); - - if (removeRowsMode) - { - emit resetEnd(this->index(index.row(), 0).data().toString()); - } -} - -CSMWorld::NestedTableWrapperBase* CSMWorld::IdTable::nestedTable(const QModelIndex& index) const -{ - if (!hasChildren(index)) - { - throw std::logic_error("Tried to retrive nested table, but index has no children"); - } - - return dynamic_cast(mIdCollection)->nestedTable(index.row(), index.column()); -} diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index 05c523ccb..ea8ab80f9 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -7,20 +7,10 @@ #include "universalid.hpp" #include "columns.hpp" -/*! \brief - * Clas for holding the model. Uses typical qt table abstraction/interface for granting access to the individiual fields of the records, - * Some records are holding nested data (for instance inventory list of the npc). In casses like this, table model offers interface - * to access nested data in the qt way – that is specify parent. Since some of those nested data require multiple columns to - * represent informations, single int (default way to index model in the qmodelindex) is not sufficiant. Therefore tablemodelindex class - * can hold two ints for the sake of indexing two dimensions of the table. This model does not support multiple levels of the nested - * data. Vast majority of methods makes sense only for the top level data. - */ - namespace CSMWorld { class CollectionBase; struct RecordBase; - class NestedTableWrapperBase; class IdTable : public IdTableBase { @@ -33,8 +23,6 @@ namespace CSMWorld // not implemented IdTable (const IdTable&); IdTable& operator= (const IdTable&); - unsigned int foldIndexAdress(const QModelIndex& index) const; - std::pair unfoldIndexAdress(unsigned int id) const; public: @@ -51,27 +39,17 @@ namespace CSMWorld virtual QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; - QVariant nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role = Qt::DisplayRole) const; - - NestedTableWrapperBase* nestedTable(const QModelIndex &index) const; - - void setNestedTable(const QModelIndex &index, const NestedTableWrapperBase& nestedTable); - virtual bool setData ( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); virtual Qt::ItemFlags flags (const QModelIndex & index) const; virtual bool removeRows (int row, int count, const QModelIndex& parent = QModelIndex()); - void addNestedRow (const QModelIndex& parent, int position); - virtual QModelIndex index (int row, int column, const QModelIndex& parent = QModelIndex()) const; virtual QModelIndex parent (const QModelIndex& index) const; - virtual bool hasChildren (const QModelIndex& index) const; - void addRecord (const std::string& id, UniversalId::Type type = UniversalId::Type_None); ///< \param type Will be ignored, unless the collection supports multiple record types @@ -105,11 +83,6 @@ namespace CSMWorld virtual bool isDeleted (const std::string& id) const; int getColumnId(int column) const; - - signals: - void resetStart(const QString& id); - - void resetEnd(const QString& id); }; } diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp new file mode 100644 index 000000000..595b0ac51 --- /dev/null +++ b/apps/opencs/model/world/idtree.cpp @@ -0,0 +1,296 @@ +#include "idtree.hpp" + +#include "nestedtablewrapper.hpp" // FIXME: is this necessary? + +#include "nestedcollection.hpp" +#include "nestablecolumn.hpp" + +CSMWorld::IdTree::IdTree (NestedCollection *idCollection, unsigned int features) +: IdTable (idCollection, features), mIdCollection (idCollection) +{} + +CSMWorld::IdTree::~IdTree() +{ + // FIXME: workaround only, a proper fix should stop QHideEvent calls after destruction + mIdCollection = 0; +} + +int CSMWorld::IdTree::rowCount (const QModelIndex & parent) const +{ + if (hasChildren(parent)) + return mIdCollection->getNestedRowsCount(parent.row(), parent.column()); + + return mIdCollection->getSize(); +} + +int CSMWorld::IdTree::columnCount (const QModelIndex & parent) const +{ + if (hasChildren(parent)) + return mIdCollection->getNestedColumnsCount(parent.row(), parent.column()); + + return mIdCollection->getColumns(); +} + +QVariant CSMWorld::IdTree::data (const QModelIndex & index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if ((role!=Qt::DisplayRole && role!=Qt::EditRole) || index.row() < 0 || index.column() < 0) + return QVariant(); + + if (role==Qt::EditRole && !mIdCollection->getColumn (index.column()).isEditable()) + return QVariant(); + + if (index.internalId() != 0) + { + std::pair parentAdress(unfoldIndexAdress(index.internalId())); + + return mIdCollection->getNestedData(parentAdress.first, + parentAdress.second, index.row(), index.column()); + } + else + return mIdCollection->getData (index.row(), index.column()); +} + +QVariant CSMWorld::IdTree::headerData (int section, Qt::Orientation orientation, int role) const +{ + if (orientation==Qt::Vertical) + return QVariant(); + + if (orientation != Qt::Horizontal) + throw std::logic_error("Unknown header orientation specified"); + + if (role == Qt::DisplayRole) + return tr (mIdCollection->getColumn (section).getTitle().c_str()); + + if (role == ColumnBase::Role_Flags) + return mIdCollection->getColumn (section).mFlags; + + if (role == ColumnBase::Role_Display) + return mIdCollection->getColumn (section).mDisplayType; + + return QVariant(); +} + +QVariant CSMWorld::IdTree::nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role) const +{ + // FIXME: workaround only, a proper fix should stop QHideEvent calls after destruction + if (section < 0 || !mIdCollection || section >= mIdCollection->getColumns()) + return QVariant(); + + // FIXME: dynamic cast + const NestableColumn& parentColumn = dynamic_cast(mIdCollection->getColumn(section)); + + if (orientation==Qt::Vertical) + return QVariant(); + + if (role==Qt::DisplayRole) + return tr(parentColumn.nestedColumn(subSection).getTitle().c_str()); + + if (role==ColumnBase::Role_Flags) + return mIdCollection->getColumn (section).mFlags; + + if (role==ColumnBase::Role_Display) + return parentColumn.nestedColumn(subSection).mDisplayType; + + return QVariant(); +} + +bool CSMWorld::IdTree::setData (const QModelIndex &index, const QVariant &value, int role) +{ + if (index.internalId() != 0) + { + if (mIdCollection->getColumn(parent(index).column()).isEditable() && role==Qt::EditRole) + { + const std::pair& parentAdress(unfoldIndexAdress(index.internalId())); + + mIdCollection->setNestedData(parentAdress.first, parentAdress.second, value, index.row(), index.column()); + + emit dataChanged (CSMWorld::IdTree::index (parentAdress.first, 0), + CSMWorld::IdTree::index (parentAdress.second, mIdCollection->getColumns()-1)); + + return true; + } + else + return false; + } + + if (mIdCollection->getColumn (index.column()).isEditable() && role==Qt::EditRole) + { + mIdCollection->setData (index.row(), index.column(), value); + + emit dataChanged (CSMWorld::IdTree::index (index.row(), 0), + CSMWorld::IdTree::index (index.row(), mIdCollection->getColumns()-1)); + + return true; + } + + return false; +} + +Qt::ItemFlags CSMWorld::IdTree::flags (const QModelIndex & index) const +{ + if (!index.isValid()) + return 0; + + Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; + + if (mIdCollection->getColumn (index.column()).isUserEditable()) + flags |= Qt::ItemIsEditable; + + return flags; +} + +bool CSMWorld::IdTree::removeRows (int row, int count, const QModelIndex& parent) +{ + beginRemoveRows (parent, row, row+count-1); + + if (parent.isValid()) + { + for (int i = 0; i < count; ++i) + { + mIdCollection->removeNestedRows(parent.row(), parent.column(), row+i); + } + } + else + { + + beginRemoveRows (parent, row, row+count-1); + + mIdCollection->removeRows (row, count); + } + + endRemoveRows(); + + emit dataChanged (CSMWorld::IdTree::index (parent.row(), 0), + CSMWorld::IdTree::index (parent.row(), mIdCollection->getColumns()-1)); + + return true; +} + +void CSMWorld::IdTree::addNestedRow(const QModelIndex& parent, int position) +{ + if (!hasChildren(parent)) + throw std::logic_error("Tried to set nested table, but index has no children"); + + int row = parent.row(); + + beginInsertRows(parent, position, position); + mIdCollection->addNestedRow(row, parent.column(), position); + endInsertRows(); + + emit dataChanged (CSMWorld::IdTree::index (row, 0), + CSMWorld::IdTree::index (row, mIdCollection->getColumns()-1)); +} + +QModelIndex CSMWorld::IdTree::index (int row, int column, const QModelIndex& parent) const +{ + unsigned int encodedId = 0; + if (parent.isValid()) + { + encodedId = this->foldIndexAdress(parent); + } + + if (row<0 || row>=mIdCollection->getSize()) + return QModelIndex(); + + if (column<0 || column>=mIdCollection->getColumns()) + return QModelIndex(); + + return createIndex(row, column, encodedId); // store internal id +} + +QModelIndex CSMWorld::IdTree::parent (const QModelIndex& index) const +{ + if (index.internalId() == 0) // 0 is used for indexs with invalid parent (top level data) + return QModelIndex(); + + unsigned int id = index.internalId(); + const std::pair& adress(unfoldIndexAdress(id)); + + if (adress.first >= this->rowCount() || adress.second >= this->columnCount()) + throw "Parent index is not present in the model"; + + return createIndex(adress.first, adress.second); +} + +void CSMWorld::IdTree::setRecord (const std::string& id, const RecordBase& record) +{ + int index = mIdCollection->searchId (id); + + if (index==-1) + { + int index = mIdCollection->getAppendIndex (id); + + beginInsertRows (QModelIndex(), index, index); + + mIdCollection->appendRecord (record); + + endInsertRows(); + } + else + { + mIdCollection->replace (index, record); + emit dataChanged (CSMWorld::IdTree::index (index, 0), + CSMWorld::IdTree::index (index, mIdCollection->getColumns()-1)); + } +} + +unsigned int CSMWorld::IdTree::foldIndexAdress (const QModelIndex& index) const +{ + unsigned int out = index.row() * this->columnCount(); + out += index.column(); + return ++out; +} + +std::pair< int, int > CSMWorld::IdTree::unfoldIndexAdress (unsigned int id) const +{ + if (id == 0) + throw "Attempt to unfold index id of the top level data cell"; + + --id; + int row = id / this->columnCount(); + int column = id - row * this->columnCount(); + return std::make_pair (row, column); +} + +bool CSMWorld::IdTree::hasChildren(const QModelIndex& index) const +{ + // FIXME: dynamic cast + return (index.isValid() && + index.internalId() == 0 && + dynamic_cast(mIdCollection->getColumn(index.column())).hasChildren() && + index.data().isValid()); +} + +void CSMWorld::IdTree::setNestedTable(const QModelIndex& index, const CSMWorld::NestedTableWrapperBase& nestedTable) +{ + if (!hasChildren(index)) + throw std::logic_error("Tried to set nested table, but index has no children"); + + bool removeRowsMode = false; + if (nestedTable.size() != this->nestedTable(index)->size()) + { + emit resetStart(this->index(index.row(), 0).data().toString()); + removeRowsMode = true; + } + + mIdCollection->setNestedTable(index.row(), index.column(), nestedTable); + + emit dataChanged (CSMWorld::IdTree::index (index.row(), 0), + CSMWorld::IdTree::index (index.row(), mIdCollection->getColumns()-1)); + + if (removeRowsMode) + { + emit resetEnd(this->index(index.row(), 0).data().toString()); + } +} + +CSMWorld::NestedTableWrapperBase* CSMWorld::IdTree::nestedTable(const QModelIndex& index) const +{ + if (!hasChildren(index)) + throw std::logic_error("Tried to retrive nested table, but index has no children"); + + return mIdCollection->nestedTable(index.row(), index.column()); +} diff --git a/apps/opencs/model/world/idtree.hpp b/apps/opencs/model/world/idtree.hpp new file mode 100644 index 000000000..6a3d7423c --- /dev/null +++ b/apps/opencs/model/world/idtree.hpp @@ -0,0 +1,88 @@ +#ifndef CSM_WOLRD_IDTREE_H +#define CSM_WOLRD_IDTREE_H + +#include "idtable.hpp" +#include "universalid.hpp" +#include "columns.hpp" + +/*! \brief + * Class for holding the model. Uses typical qt table abstraction/interface for granting access + * to the individiual fields of the records, Some records are holding nested data (for instance + * inventory list of the npc). In casses like this, table model offers interface to access + * nested data in the qt way - that is specify parent. Since some of those nested data require + * multiple columns to represent informations, single int (default way to index model in the + * qmodelindex) is not sufficiant. Therefore tablemodelindex class can hold two ints for the + * sake of indexing two dimensions of the table. This model does not support multiple levels of + * the nested data. Vast majority of methods makes sense only for the top level data. + */ + +namespace CSMWorld +{ + class NestedCollection; + struct RecordBase; + class NestedTableWrapperBase; // FIXME: is this necessary? + + class IdTree : public IdTable // IdTable is derived from QAbstractItemModel + { + Q_OBJECT + + private: + + NestedCollection *mIdCollection; + + // not implemented + IdTree (const IdTree&); + IdTree& operator= (const IdTree&); + + unsigned int foldIndexAdress(const QModelIndex& index) const; + std::pair unfoldIndexAdress(unsigned int id) const; + + public: + + IdTree (NestedCollection *idCollection, unsigned int features = 0); + ///< The ownership of \a idCollection is not transferred. + + virtual ~IdTree(); + + virtual int rowCount (const QModelIndex & parent = QModelIndex()) const; + + virtual int columnCount (const QModelIndex & parent = QModelIndex()) const; + + virtual QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const; + + virtual QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + + virtual bool setData ( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + + virtual Qt::ItemFlags flags (const QModelIndex & index) const; + + virtual bool removeRows (int row, int count, const QModelIndex& parent = QModelIndex()); + + virtual QModelIndex index (int row, int column, const QModelIndex& parent = QModelIndex()) + const; + + virtual QModelIndex parent (const QModelIndex& index) const; + + void setRecord (const std::string& id, const RecordBase& record); + ///< Add record or overwrite existing recrod. + + // TODO: check if below methods are really needed + QVariant nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + + NestedTableWrapperBase* nestedTable(const QModelIndex &index) const; + + void setNestedTable(const QModelIndex &index, const NestedTableWrapperBase& nestedTable); + + void addNestedRow (const QModelIndex& parent, int position); + + virtual bool hasChildren (const QModelIndex& index) const; + + signals: + + void resetStart(const QString& id); + + void resetEnd(const QString& id); + }; +} + +#endif diff --git a/apps/opencs/model/world/nestablecolumn.cpp b/apps/opencs/model/world/nestablecolumn.cpp new file mode 100644 index 000000000..4ade75b33 --- /dev/null +++ b/apps/opencs/model/world/nestablecolumn.cpp @@ -0,0 +1,44 @@ +#include "nestablecolumn.hpp" + +#include + +void CSMWorld::NestableColumn::addColumn(CSMWorld::NestableColumn *column) +{ + mNestedColumns.push_back(column); + mHasChildren = true; +} + +const CSMWorld::ColumnBase& CSMWorld::NestableColumn::nestedColumn(int subColumn) const +{ + if (!mHasChildren) + throw std::logic_error("Tried to access nested column of the non-nest column"); + + return *mNestedColumns.at(subColumn); +} + +int CSMWorld::NestableColumn::nestedColumnCount() const +{ + if (!mHasChildren) + throw std::logic_error("Tried to access number of the subcolumns in the non-nest column"); + + return mNestedColumns.size(); +} + +CSMWorld::NestableColumn::NestableColumn(int columnId, CSMWorld::ColumnBase::Display displayType, + int flag, const CSMWorld::NestableColumn* parent) + : mParent(parent), mHasChildren(false), CSMWorld::ColumnBase(columnId, displayType, flag) +{ +} + +CSMWorld::NestableColumn::~NestableColumn() +{ + for (unsigned int i = 0; i < mNestedColumns.size(); ++i) + { + delete mNestedColumns[i]; + } +} + +bool CSMWorld::NestableColumn::hasChildren() const +{ + return mHasChildren; +} diff --git a/apps/opencs/model/world/nestablecolumn.hpp b/apps/opencs/model/world/nestablecolumn.hpp new file mode 100644 index 000000000..28ced85e9 --- /dev/null +++ b/apps/opencs/model/world/nestablecolumn.hpp @@ -0,0 +1,33 @@ +#ifndef CSM_WOLRD_NESTABLECOLUMN_H +#define CSM_WOLRD_NESTABLECOLUMN_H + +#include + +#include "columnbase.hpp" + +namespace CSMWorld +{ + class NestableColumn : public ColumnBase + { + std::vector mNestedColumns; + const NestableColumn* mParent; + bool mHasChildren; // cached + + public: + + NestableColumn(int columnId, + Display displayType, int flag, const NestableColumn* parent = 0); + + ~NestableColumn(); + + void addColumn(CSMWorld::NestableColumn *column); + + const ColumnBase& nestedColumn(int subColumn) const; + + int nestedColumnCount() const; + + bool hasChildren() const; + }; +} + +#endif diff --git a/apps/opencs/model/world/nestedcollection.hpp b/apps/opencs/model/world/nestedcollection.hpp index dffa29573..5ec50b423 100644 --- a/apps/opencs/model/world/nestedcollection.hpp +++ b/apps/opencs/model/world/nestedcollection.hpp @@ -1,6 +1,8 @@ #ifndef CSM_WOLRD_NESTEDCOLLECTION_H #define CSM_WOLRD_NESTEDCOLLECTION_H +#include + #include "collectionbase.hpp" class QVariant; @@ -11,7 +13,12 @@ namespace CSMWorld class NestedCollection : public CollectionBase { + public: + + NestedCollection(); + virtual ~NestedCollection(); + virtual void addNestedRow(int row, int col, int position) = 0; virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const = 0; @@ -28,7 +35,10 @@ namespace CSMWorld virtual void removeNestedRows(int row, int column, int subRow) = 0; + private: + std::vector mChildren; + NestedCollection *mParent; // currently unused }; } diff --git a/apps/opencs/model/world/nestedtableproxymodel.cpp b/apps/opencs/model/world/nestedtableproxymodel.cpp index c098e0316..fede8383b 100644 --- a/apps/opencs/model/world/nestedtableproxymodel.cpp +++ b/apps/opencs/model/world/nestedtableproxymodel.cpp @@ -1,11 +1,11 @@ #include "nestedtableproxymodel.hpp" #include -#include "idtable.hpp" +#include "idtree.hpp" CSMWorld::NestedTableProxyModel::NestedTableProxyModel(const QModelIndex& parent, ColumnBase::Display columnId, - CSMWorld::IdTable* parentModel) + CSMWorld::IdTree* parentModel) : mParentColumn(parent.column()), mMainModel(parentModel) { @@ -119,7 +119,7 @@ int CSMWorld::NestedTableProxyModel::getParentColumn() const return mParentColumn; } -CSMWorld::IdTable* CSMWorld::NestedTableProxyModel::model() const +CSMWorld::IdTree* CSMWorld::NestedTableProxyModel::model() const { return mMainModel; } diff --git a/apps/opencs/model/world/nestedtableproxymodel.hpp b/apps/opencs/model/world/nestedtableproxymodel.hpp index 7ad8fc0c2..7dc66989c 100644 --- a/apps/opencs/model/world/nestedtableproxymodel.hpp +++ b/apps/opencs/model/world/nestedtableproxymodel.hpp @@ -17,27 +17,27 @@ namespace CSMWorld { class CollectionBase; class RecordBase; - class IdTable; + class IdTree; class NestedTableProxyModel : public QAbstractProxyModel { Q_OBJECT const int mParentColumn; - IdTable* mMainModel; + IdTree* mMainModel; std::string mId; public: NestedTableProxyModel(const QModelIndex& parent, ColumnBase::Display displayType, - IdTable* parentModel); + IdTree* parentModel); //parent is the parent of columns to work with. Columnid provides information about the column std::string getParentId() const; int getParentColumn() const; - CSMWorld::IdTable* model() const; + CSMWorld::IdTree* model() const; virtual QModelIndex mapFromSource(const QModelIndex& sourceIndex) const; diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index c48896435..ca5efcdd9 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -2,18 +2,17 @@ #include #include -#include #include #include "refidadapter.hpp" #include "refidadapterimp.hpp" #include "columns.hpp" -#include "nestedtablewrapper.hpp" +#include "nestedtablewrapper.hpp" // FIXME: is this really necessary? CSMWorld::RefIdColumn::RefIdColumn (int columnId, Display displayType, int flag, - bool editable, bool userEditable, bool canNest) - : NestColumn (columnId, displayType, flag, canNest), mEditable (editable), mUserEditable (userEditable) + bool editable, bool userEditable) + : NestableColumn (columnId, displayType, flag), mEditable (editable), mUserEditable (userEditable) {} bool CSMWorld::RefIdColumn::isEditable() const @@ -27,7 +26,8 @@ bool CSMWorld::RefIdColumn::isUserEditable() const } -CSMWorld::RefIdAdapter& CSMWorld::RefIdCollection::findAdapter (UniversalId::Type type) const +// FIXME: const problem +/*const*/ CSMWorld::RefIdAdapter& CSMWorld::RefIdCollection::findAdapter (UniversalId::Type type) const { std::map::const_iterator iter = mAdapters.find (type); @@ -99,14 +99,19 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.push_back (RefIdColumn (Columns::ColumnId_AiAlarm, ColumnBase::Display_Integer)); actorsColumns.mAlarm = &mColumns.back(); - mColumns.push_back(RefIdColumn (Columns::ColumnId_ActorInventory, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue, true, true, true)); + // Nested table + mColumns.push_back(RefIdColumn (Columns::ColumnId_ActorInventory, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue)); actorsColumns.mInventory = &mColumns.back(); - mColumns.back().addNestedColumn(Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String); - mColumns.back().addNestedColumn(Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer)); - mColumns.push_back(RefIdColumn (Columns::ColumnId_ActorSpells, ColumnBase::Display_NestedSpellList, ColumnBase::Flag_Dialogue, true, true, true)); + // Nested table + mColumns.push_back(RefIdColumn (Columns::ColumnId_ActorSpells, ColumnBase::Display_NestedSpellList, ColumnBase::Flag_Dialogue)); actorsColumns.mSpells = &mColumns.back(); - mColumns.back().addNestedColumn(Columns::ColumnId_SpellId, CSMWorld::ColumnBase::Display_String); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_SpellId, CSMWorld::ColumnBase::Display_String)); static const struct { @@ -175,10 +180,13 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.push_back (RefIdColumn (Columns::ColumnId_Respawn, ColumnBase::Display_Boolean)); const RefIdColumn *respawn = &mColumns.back(); - mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue, true, true, true)); + // Nested table + mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue)); const RefIdColumn *content = &mColumns.back(); - mColumns.back().addNestedColumn(Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String); - mColumns.back().addNestedColumn(Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer)); CreatureColumns creatureColumns (actorsColumns); @@ -315,16 +323,24 @@ CSMWorld::RefIdCollection::RefIdCollection() npcColumns.mFlags.insert (std::make_pair (metalBlood, ESM::NPC::Metal)); - mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcDestinations, ColumnBase::Display_NestedDestinationsList, ColumnBase::Flag_Dialogue, true, true, true)); + // Nested table + mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcDestinations, ColumnBase::Display_NestedDestinationsList, ColumnBase::Flag_Dialogue)); npcColumns.mDestinations = &mColumns.back(); - mColumns.back().addNestedColumn(Columns::ColumnId_DestinationCell, CSMWorld::ColumnBase::Display_String); - mColumns.back().addNestedColumn(Columns::ColumnId_PosX, CSMWorld::ColumnBase::Display_Float); - mColumns.back().addNestedColumn(Columns::ColumnId_PosY, CSMWorld::ColumnBase::Display_Float); - mColumns.back().addNestedColumn(Columns::ColumnId_PosZ, CSMWorld::ColumnBase::Display_Float); - mColumns.back().addNestedColumn(Columns::ColumnId_RotX, CSMWorld::ColumnBase::Display_Float); - mColumns.back().addNestedColumn(Columns::ColumnId_RotY, CSMWorld::ColumnBase::Display_Float); - mColumns.back().addNestedColumn(Columns::ColumnId_RotZ, CSMWorld::ColumnBase::Display_Float); - + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_DestinationCell, CSMWorld::ColumnBase::Display_String)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_PosX, CSMWorld::ColumnBase::Display_Float)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_PosY, CSMWorld::ColumnBase::Display_Float)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_PosZ, CSMWorld::ColumnBase::Display_Float)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_RotX, CSMWorld::ColumnBase::Display_Float)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_RotY, CSMWorld::ColumnBase::Display_Float)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_RotZ, CSMWorld::ColumnBase::Display_Float)); + WeaponColumns weaponColumns (enchantableColumns); mColumns.push_back (RefIdColumn (Columns::ColumnId_WeaponType, ColumnBase::Display_WeaponType)); @@ -664,8 +680,10 @@ void CSMWorld::RefIdCollection::setNestedTable(int row, int column, const CSMWor { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + // FIXME: const problem CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); + // FIXME: const problem adaptor.setNestedTable(&mColumns.at(column), mData, localIndex.first, nestedTable); } diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index ab25c93fa..dd432c5a9 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -5,8 +5,7 @@ #include #include -#include "columnbase.hpp" -#include "collectionbase.hpp" +#include "nestablecolumn.hpp" #include "nestedcollection.hpp" #include "refiddata.hpp" @@ -18,9 +17,9 @@ namespace ESM namespace CSMWorld { class RefIdAdapter; - class NestedTableWrapperBase; + class NestedTableWrapperBase; // FIXME: is this really needed? - class RefIdColumn : public NestColumn + class RefIdColumn : public NestableColumn { bool mEditable; bool mUserEditable; @@ -29,7 +28,7 @@ namespace CSMWorld RefIdColumn (int columnId, Display displayType, int flag = Flag_Table | Flag_Dialogue, bool editable = true, - bool userEditable = true, bool canNest = false); + bool userEditable = true); virtual bool isEditable() const; @@ -46,7 +45,7 @@ namespace CSMWorld private: - RefIdAdapter& findAdapter (UniversalId::Type) const; + /*const*/ RefIdAdapter& findAdapter (UniversalId::Type) const; ///< Throws an exception if no adaptor for \a Type can be found. public: @@ -57,10 +56,6 @@ namespace CSMWorld virtual int getSize() const; - virtual int getNestedRowsCount(int row, int column) const; - - virtual int getNestedColumnsCount(int row, int column) const; - virtual std::string getId (int index) const; virtual int getIndex (const std::string& id) const; @@ -71,22 +66,10 @@ namespace CSMWorld virtual QVariant getData (int index, int column) const; - virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const; - - virtual NestedTableWrapperBase* nestedTable(int row, int column) const; - - virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable); - virtual void setData (int index, int column, const QVariant& data); - virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn); - virtual void removeRows (int index, int count); - virtual void removeNestedRows(int row, int column, int subRow); - - virtual void addNestedRow(int row, int col, int position); - virtual void cloneRecord(const std::string& origin, const std::string& destination, const UniversalId::Type type); @@ -128,6 +111,24 @@ namespace CSMWorld /// /// \return Success? + virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const; + + virtual NestedTableWrapperBase* nestedTable(int row, int column) const; + + virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable); + + // FIXME + virtual int getNestedRowsCount(int row, int column) const; + + // FIXME + virtual int getNestedColumnsCount(int row, int column) const; + + virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn); + + virtual void removeNestedRows(int row, int column, int subRow); + + virtual void addNestedRow(int row, int col, int position); + void save (int index, ESM::ESMWriter& writer) const; const RefIdData& getDataSet() const; //I can't figure out a better name for this one :( diff --git a/apps/opencs/model/world/refiddata.hpp b/apps/opencs/model/world/refiddata.hpp index bfdd4f9ee..eaa7b115d 100644 --- a/apps/opencs/model/world/refiddata.hpp +++ b/apps/opencs/model/world/refiddata.hpp @@ -52,7 +52,7 @@ namespace CSMWorld virtual void load (int index, ESM::ESMReader& reader, bool base) = 0; virtual void erase (int index, int count) = 0; - + virtual std::string getId (int index) const = 0; virtual void save (int index, ESM::ESMWriter& writer) const = 0; @@ -134,7 +134,7 @@ namespace CSMWorld throw std::runtime_error ("invalid RefIdDataContainer index"); mContainer.erase (mContainer.begin()+index, mContainer.begin()+index+count); - } + } template std::string RefIdDataContainer::getId (int index) const @@ -231,7 +231,7 @@ namespace CSMWorld void save (int index, ESM::ESMWriter& writer) const; - //RECORD CONTAINERS ACCESS METHODS + //RECORD CONTAINERS ACCESS METHODS const RefIdDataContainer& getBooks() const; const RefIdDataContainer& getActivators() const; const RefIdDataContainer& getPotions() const; diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index e26dcdc9b..0aa83eb92 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -26,6 +26,7 @@ #include "../../model/world/nestedtableproxymodel.hpp" #include "../../model/world/columnbase.hpp" #include "../../model/world/idtable.hpp" +#include "../../model/world/idtree.hpp" #include "../../model/world/columns.hpp" #include "../../model/world/record.hpp" #include "../../model/world/tablemimedata.hpp" @@ -422,7 +423,7 @@ void CSVWorld::EditWidget::remake(int row) if (mTable->hasChildren(mTable->index(row, i))) { - mNestedModels.push_back(new CSMWorld::NestedTableProxyModel (mTable->index(row, i), display, mTable)); + mNestedModels.push_back(new CSMWorld::NestedTableProxyModel (mTable->index(row, i), display, dynamic_cast(mTable))); NestedTable* table = new NestedTable(mDocument, mNestedModels.back(), this); From 8eaf6b068cf6f91e0493a0e1673c691e0fbd7b55 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 2 Apr 2015 21:02:17 +1100 Subject: [PATCH 675/740] Adding missing file. --- apps/opencs/model/world/nestedcollection.cpp | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 apps/opencs/model/world/nestedcollection.cpp diff --git a/apps/opencs/model/world/nestedcollection.cpp b/apps/opencs/model/world/nestedcollection.cpp new file mode 100644 index 000000000..f557c3ba1 --- /dev/null +++ b/apps/opencs/model/world/nestedcollection.cpp @@ -0,0 +1,7 @@ +#include "nestedcollection.hpp" + +CSMWorld::NestedCollection::NestedCollection() : mParent(0) +{} + +CSMWorld::NestedCollection::~NestedCollection() +{} From 6b6bed520d82061c1b401e9aabf617db9d17d309 Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 3 Apr 2015 13:45:13 +1300 Subject: [PATCH 676/740] removed redundant calls. --- apps/openmw/mwgui/quickkeysmenu.cpp | 1 - apps/openmw/mwgui/spellwindow.cpp | 2 -- 2 files changed, 3 deletions(-) diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 8f595df80..834c156f9 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -548,7 +548,6 @@ namespace MWGui WindowModal::open(); mMagicList->setModel(new SpellModel(MWBase::Environment::get().getWorld()->getPlayerPtr())); - mMagicList->update(); } void MagicSelectionDialog::onModelIndexSelected(SpellModel::ModelIndex index) diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index cc032691e..4fdeb91cf 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -65,7 +65,6 @@ namespace MWGui mSpellIcons->updateWidgets(mEffectBox, false); mSpellView->setModel(new SpellModel(MWBase::Environment::get().getWorld()->getPlayerPtr())); - mSpellView->update(); } void SpellWindow::onEnchantedItemSelected(MWWorld::Ptr item, bool alreadyEquipped) @@ -170,7 +169,6 @@ namespace MWGui void SpellWindow::cycle(bool next) { mSpellView->setModel(new SpellModel(MWBase::Environment::get().getWorld()->getPlayerPtr())); - mSpellView->getModel()->update(); SpellModel::ModelIndex selected = 0; for (SpellModel::ModelIndex i = 0; igetModel()->getItemCount()); ++i) From 745eae9c10b01885a6245df2f87f366867123b96 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 3 Apr 2015 12:44:32 +1100 Subject: [PATCH 677/740] Tweak DialogueSubView layout for nested tables. --- apps/opencs/view/world/dialoguesubview.cpp | 39 ++++++---------------- 1 file changed, 10 insertions(+), 29 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 0aa83eb92..d0b53a206 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -17,11 +17,9 @@ #include #include #include -#include #include #include #include -#include #include "../../model/world/nestedtableproxymodel.hpp" #include "../../model/world/columnbase.hpp" @@ -384,27 +382,17 @@ void CSVWorld::EditWidget::remake(int row) mWidgetMapper->setModel(mTable); mWidgetMapper->setItemDelegate(&mDispatcher); - QFrame* line = new QFrame(mMainWidget); - line->setObjectName(QString::fromUtf8("line")); - line->setGeometry(QRect(320, 150, 118, 3)); - line->setFrameShape(QFrame::HLine); - line->setFrameShadow(QFrame::Sunken); - - QFrame* line2 = new QFrame(mMainWidget); - line2->setObjectName(QString::fromUtf8("line2")); - line2->setGeometry(QRect(320, 150, 118, 3)); - line2->setFrameShape(QFrame::HLine); - line2->setFrameShadow(QFrame::Sunken); - QVBoxLayout *mainLayout = new QVBoxLayout(mMainWidget); - QGridLayout *unlockedLayout = new QGridLayout(); + QScrollArea *scroll = new QScrollArea(mMainWidget); + QWidget *unlockedWidget = new QWidget(scroll); + QGridLayout *unlockedLayout = new QGridLayout(unlockedWidget); QGridLayout *lockedLayout = new QGridLayout(); QVBoxLayout *tablesLayout = new QVBoxLayout(); mainLayout->addLayout(lockedLayout, 0); - mainLayout->addWidget(line, 1); - mainLayout->addLayout(unlockedLayout, 2); - mainLayout->addWidget(line2, 1); + mainLayout->addSpacing(5); // FIXME: arbitrary number + mainLayout->addWidget(scroll, 2); + mainLayout->addSpacing(5); // FIXME: arbitrary number mainLayout->addLayout(tablesLayout, 0); mainLayout->addStretch(1); @@ -426,18 +414,8 @@ void CSVWorld::EditWidget::remake(int row) mNestedModels.push_back(new CSMWorld::NestedTableProxyModel (mTable->index(row, i), display, dynamic_cast(mTable))); NestedTable* table = new NestedTable(mDocument, mNestedModels.back(), this); + table->resizeColumnsToContents(); - int rows = mNestedModels.back()->rowCount(mTable->index(row, i)); - if (rows == 0) rows = 1; // FIXME: quick hack - int rowHeight = table->rowHeight(0); - int tableHeight = (rows * rowHeight) - + table->horizontalHeader()->height() + 2 * table->frameWidth(); - int tableMaxHeight = (5 * rowHeight) - + table->horizontalHeader()->height() + 2 * table->frameWidth(); - if (rows > 1 && rows < 5) - table->setMinimumHeight(tableHeight); - else if (rows > 1) - table->setMinimumHeight(tableMaxHeight); QLabel* label = new QLabel (mTable->headerData (i, Qt::Horizontal, Qt::DisplayRole).toString(), mMainWidget); @@ -479,6 +457,9 @@ void CSVWorld::EditWidget::remake(int row) mWidgetMapper->setCurrentModelIndex(mTable->index(row, 0)); + scroll->setWidget(unlockedWidget); + scroll->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Fixed); + scroll->setWidgetResizable(true); this->setWidget(mMainWidget); this->setWidgetResizable(true); } From 52de622e9732d6dd3c36e22f0cd3562f52221f2d Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 3 Apr 2015 17:59:13 +1300 Subject: [PATCH 678/740] provide incremental update of SpellWindow (Fixes #2411) When SpellWindow is visible, every 0.5 seconds update the cost/changes for spells/enchanted items shown. Also, check to see if more substantial update of the window is required. --- apps/openmw/mwgui/spellview.cpp | 95 +++++++++++++++++++++++++------ apps/openmw/mwgui/spellview.hpp | 17 +++++- apps/openmw/mwgui/spellwindow.cpp | 15 +++++ apps/openmw/mwgui/spellwindow.hpp | 5 +- 4 files changed, 113 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index 668b239bc..eeadc1d81 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -10,6 +10,8 @@ namespace MWGui { + const char* SpellView::sSpellModelIndex = "SpellModelIndex"; + SpellView::SpellView() : mShowCostColumn(true) , mHighlightSelected(true) @@ -113,10 +115,10 @@ namespace MWGui group.push_back(costChance); Gui::SharedStateButton::createButtonGroup(group); - mLines.push_back(std::make_pair(t, costChance)); + mLines.push_back(boost::make_tuple(t, costChance, true)); } else - mLines.push_back(std::make_pair(t, (MyGUI::Widget*)NULL)); + mLines.push_back(boost::make_tuple(t, (MyGUI::Widget*)NULL, true)); t->setStateSelected(spell.mSelected); } @@ -124,30 +126,85 @@ namespace MWGui layoutWidgets(); } + void SpellView::incrementalUpdate() + { + if (!mModel.get()) + { + return; + } + + mModel->update(); + bool fullUpdateRequired = false; + SpellModel::ModelIndex maxSpellIndexFound = -1; + for (std::vector< LineInfo >::iterator it = mLines.begin(); it != mLines.end(); ++it) + { + // only update the lines that are "updateable" + if (it->get<2>()) + { + Gui::SharedStateButton* nameButton = reinterpret_cast(it->get<0>()); + + // match model against line + // if don't match, then major change has happened, so do a full update + SpellModel::ModelIndex spellIndex = getSpellModelIndex(nameButton); + if (mModel->getItemCount() <= static_cast(spellIndex)) + { + fullUpdateRequired = true; + break; + } + + // more checking for major change. + const Spell& spell = mModel->getItem(spellIndex); + if (nameButton->getCaption() != spell.mName) + { + fullUpdateRequired = true; + break; + } + else + { + maxSpellIndexFound = spellIndex; + Gui::SharedStateButton* costButton = reinterpret_cast(it->get<1>()); + if ((costButton != NULL) && (costButton->getCaption() != spell.mCostColumn)) + { + costButton->setCaption(spell.mCostColumn); + } + } + } + } + + // special case, look for spells added to model that are beyond last updatable item + SpellModel::ModelIndex topSpellIndex = mModel->getItemCount() - 1; + if (fullUpdateRequired || + ((0 <= topSpellIndex) && (maxSpellIndexFound < topSpellIndex))) + { + update(); + } + } + + void SpellView::layoutWidgets() { int height = 0; - for (std::vector< std::pair >::iterator it = mLines.begin(); + for (std::vector< LineInfo >::iterator it = mLines.begin(); it != mLines.end(); ++it) { - height += (it->first)->getHeight(); + height += (it->get<0>())->getHeight(); } bool scrollVisible = height > mScrollView->getHeight(); int width = mScrollView->getWidth() - (scrollVisible ? 18 : 0); height = 0; - for (std::vector< std::pair >::iterator it = mLines.begin(); + for (std::vector< LineInfo >::iterator it = mLines.begin(); it != mLines.end(); ++it) { - int lineHeight = (it->first)->getHeight(); - (it->first)->setCoord(4, height, width-8, lineHeight); - if (it->second) + int lineHeight = (it->get<0>())->getHeight(); + (it->get<0>())->setCoord(4, height, width - 8, lineHeight); + if (it->get<1>()) { - (it->second)->setCoord(4, height, width-8, lineHeight); - MyGUI::TextBox* second = (it->second)->castType(false); + (it->get<1>())->setCoord(4, height, width - 8, lineHeight); + MyGUI::TextBox* second = (it->get<1>())->castType(false); if (second) - (it->first)->setSize(width-8-second->getTextSize().width, lineHeight); + (it->get<0>())->setSize(width - 8 - second->getTextSize().width, lineHeight); } height += lineHeight; @@ -167,7 +224,7 @@ namespace MWGui MyGUI::IntCoord(0, 0, mScrollView->getWidth(), 18), MyGUI::Align::Left | MyGUI::Align::Top); separator->setNeedMouseFocus(false); - mLines.push_back(std::make_pair(separator, (MyGUI::Widget*)NULL)); + mLines.push_back(boost::make_tuple(separator, (MyGUI::Widget*)NULL, false)); } MyGUI::TextBox* groupWidget = mScrollView->createWidget("SandBrightText", @@ -186,10 +243,10 @@ namespace MWGui groupWidget2->setTextAlign(MyGUI::Align::Right); groupWidget2->setNeedMouseFocus(false); - mLines.push_back(std::make_pair(groupWidget, groupWidget2)); + mLines.push_back(boost::make_tuple(groupWidget, groupWidget2, false)); } else - mLines.push_back(std::make_pair(groupWidget, (MyGUI::Widget*)NULL)); + mLines.push_back(boost::make_tuple(groupWidget, (MyGUI::Widget*)NULL, false)); } @@ -222,16 +279,20 @@ namespace MWGui widget->setUserString("Spell", spell.mId); } - widget->setUserString("SpellModelIndex", MyGUI::utility::toString(index)); + widget->setUserString(sSpellModelIndex, MyGUI::utility::toString(index)); widget->eventMouseWheel += MyGUI::newDelegate(this, &SpellView::onMouseWheel); widget->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellView::onSpellSelected); } + SpellModel::ModelIndex SpellView::getSpellModelIndex(MyGUI::Widget* widget) + { + return MyGUI::utility::parseInt(widget->getUserString(sSpellModelIndex)); + } + void SpellView::onSpellSelected(MyGUI::Widget* _sender) { - SpellModel::ModelIndex i = MyGUI::utility::parseInt(_sender->getUserString("SpellModelIndex")); - eventSpellClicked(i); + eventSpellClicked(getSpellModelIndex(_sender)); } void SpellView::onMouseWheel(MyGUI::Widget* _sender, int _rel) diff --git a/apps/openmw/mwgui/spellview.hpp b/apps/openmw/mwgui/spellview.hpp index 005d206f4..2f6ff2624 100644 --- a/apps/openmw/mwgui/spellview.hpp +++ b/apps/openmw/mwgui/spellview.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_GUI_SPELLVIEW_H #define OPENMW_GUI_SPELLVIEW_H +#include + #include #include "spellmodel.hpp" @@ -37,6 +39,9 @@ namespace MWGui void update(); + /// simplified update called each frame + void incrementalUpdate(); + typedef MyGUI::delegates::CMultiDelegate1 EventHandle_ModelIndex; /// Fired when a spell was clicked EventHandle_ModelIndex eventSpellClicked; @@ -51,7 +56,13 @@ namespace MWGui std::auto_ptr mModel; - std::vector< std::pair > mLines; + /// tracks an item in the spell view + /// element<0> is the left column GUI object (usually holds the name) + /// element<1> is the right column (charge or cost info) + /// element<2> is if line needs to be checked during incremental update + typedef boost::tuple LineInfo; + + std::vector< LineInfo > mLines; bool mShowCostColumn; bool mHighlightSelected; @@ -62,6 +73,10 @@ namespace MWGui void onSpellSelected(MyGUI::Widget* _sender); void onMouseWheel(MyGUI::Widget* _sender, int _rel); + + SpellModel::ModelIndex getSpellModelIndex(MyGUI::Widget* _sender); + + static const char* sSpellModelIndex; }; } diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 4fdeb91cf..ca5ec20bd 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -28,6 +28,7 @@ namespace MWGui : WindowPinnableBase("openmw_spell_window.layout") , NoDrop(drag, mMainWidget) , mSpellView(NULL) + , mUpdateTimer(0.0f) { mSpellIcons = new SpellIcons(); @@ -60,6 +61,20 @@ namespace MWGui updateSpells(); } + void SpellWindow::onFrame(float dt) + { + if (mMainWidget->getVisible()) + { + NoDrop::onFrame(dt); + mUpdateTimer += dt; + if (0.5f < mUpdateTimer) + { + mUpdateTimer = 0; + mSpellView->incrementalUpdate(); + } + } + } + void SpellWindow::updateSpells() { mSpellIcons->updateWidgets(mEffectBox, false); diff --git a/apps/openmw/mwgui/spellwindow.hpp b/apps/openmw/mwgui/spellwindow.hpp index 8b5474f58..dcce10f9d 100644 --- a/apps/openmw/mwgui/spellwindow.hpp +++ b/apps/openmw/mwgui/spellwindow.hpp @@ -19,7 +19,7 @@ namespace MWGui void updateSpells(); - void onFrame(float dt) { NoDrop::onFrame(dt); } + void onFrame(float dt); /// Cycle to next/previous spell void cycle(bool next); @@ -41,6 +41,9 @@ namespace MWGui SpellView* mSpellView; SpellIcons* mSpellIcons; + + private: + float mUpdateTimer; }; } From 3b408b64276ffdb1dcad81112d3c8fe17b0da710 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 4 Apr 2015 19:55:53 +0200 Subject: [PATCH 679/740] sorting out some Display enum mixup --- apps/opencs/model/world/columnbase.cpp | 5 ++--- apps/opencs/model/world/columnbase.hpp | 1 + apps/opencs/model/world/columnimp.hpp | 2 +- apps/opencs/model/world/refidcollection.cpp | 2 +- apps/opencs/model/world/resourcetable.cpp | 2 +- apps/opencs/view/world/scriptsubview.cpp | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index a736c0155..4f51fcad6 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -66,6 +66,7 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_JournalInfo, Display_Scene, Display_GlobalVariable, + Display_Script, Display_Mesh, Display_Icon, @@ -74,8 +75,6 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_Texture, Display_Video, - Display_Id, - Display_None }; @@ -93,5 +92,5 @@ bool CSMWorld::ColumnBase::isText (Display display) bool CSMWorld::ColumnBase::isScript (Display display) { - return display==Display_Script || display==Display_ScriptLines; + return display==Display_ScriptFile || display==Display_ScriptLines; } diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 38039c27c..6f67898f6 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -101,6 +101,7 @@ namespace CSMWorld Display_Texture, Display_Video, Display_Colour, + Display_ScriptFile, Display_ScriptLines, // console context Display_SoundGeneratorType, Display_School, diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 47b744b7f..e67fdd59c 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -818,7 +818,7 @@ namespace CSMWorld ScriptColumn (Type type) : Column (Columns::ColumnId_ScriptText, - type==Type_File ? ColumnBase::Display_Script : ColumnBase::Display_ScriptLines, + type==Type_File ? ColumnBase::Display_ScriptFile : ColumnBase::Display_ScriptLines, type==Type_File ? 0 : ColumnBase::Flag_Dialogue) {} diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 14a8890ad..6963c1331 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -40,7 +40,7 @@ CSMWorld::RefIdCollection::RefIdCollection() { BaseColumns baseColumns; - mColumns.push_back (RefIdColumn (Columns::ColumnId_Id, ColumnBase::Display_String, + mColumns.push_back (RefIdColumn (Columns::ColumnId_Id, ColumnBase::Display_Id, ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, false, false)); baseColumns.mId = &mColumns.back(); mColumns.push_back (RefIdColumn (Columns::ColumnId_Modification, ColumnBase::Display_RecordState, diff --git a/apps/opencs/model/world/resourcetable.cpp b/apps/opencs/model/world/resourcetable.cpp index 36e2b3f3d..2cd44781a 100644 --- a/apps/opencs/model/world/resourcetable.cpp +++ b/apps/opencs/model/world/resourcetable.cpp @@ -60,7 +60,7 @@ QVariant CSMWorld::ResourceTable::headerData (int section, Qt::Orientation orien return Columns::getName (Columns::ColumnId_Id).c_str(); if (role==ColumnBase::Role_Display) - return ColumnBase::Display_String; + return ColumnBase::Display_Id; break; diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 9b50a61f8..d0c3c2559 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -22,7 +22,7 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: for (int i=0; icolumnCount(); ++i) if (mModel->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display)== - CSMWorld::ColumnBase::Display_Script) + CSMWorld::ColumnBase::Display_ScriptFile) { mColumn = i; break; From fe69dc28637e0cc2e61f6bbcbaba5b5c82a1d912 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 5 Apr 2015 14:56:29 +1200 Subject: [PATCH 680/740] Made LineInfo a struct, as requested by Scrawl. --- apps/openmw/mwgui/spellview.cpp | 40 ++++++++++++++++++++------------- apps/openmw/mwgui/spellview.hpp | 22 +++++++++++++----- 2 files changed, 41 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index eeadc1d81..a7c1d781b 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -12,6 +12,14 @@ namespace MWGui const char* SpellView::sSpellModelIndex = "SpellModelIndex"; + SpellView::LineInfo::LineInfo(MyGUI::Widget* leftWidget, MyGUI::Widget* rightWidget, SpellModel::ModelIndex spellIndex) + : mLeftWidget(leftWidget) + , mRightWidget(rightWidget) + , mSpellIndex(spellIndex) + { + + } + SpellView::SpellView() : mShowCostColumn(true) , mHighlightSelected(true) @@ -115,10 +123,10 @@ namespace MWGui group.push_back(costChance); Gui::SharedStateButton::createButtonGroup(group); - mLines.push_back(boost::make_tuple(t, costChance, true)); + mLines.push_back(LineInfo(t, costChance, i)); } else - mLines.push_back(boost::make_tuple(t, (MyGUI::Widget*)NULL, true)); + mLines.push_back(LineInfo(t, (MyGUI::Widget*)NULL, i)); t->setStateSelected(spell.mSelected); } @@ -139,13 +147,13 @@ namespace MWGui for (std::vector< LineInfo >::iterator it = mLines.begin(); it != mLines.end(); ++it) { // only update the lines that are "updateable" - if (it->get<2>()) + SpellModel::ModelIndex spellIndex(it->mSpellIndex); + if (spellIndex != NoSpellIndex) { - Gui::SharedStateButton* nameButton = reinterpret_cast(it->get<0>()); + Gui::SharedStateButton* nameButton = reinterpret_cast(it->mLeftWidget); // match model against line // if don't match, then major change has happened, so do a full update - SpellModel::ModelIndex spellIndex = getSpellModelIndex(nameButton); if (mModel->getItemCount() <= static_cast(spellIndex)) { fullUpdateRequired = true; @@ -162,7 +170,7 @@ namespace MWGui else { maxSpellIndexFound = spellIndex; - Gui::SharedStateButton* costButton = reinterpret_cast(it->get<1>()); + Gui::SharedStateButton* costButton = reinterpret_cast(it->mRightWidget); if ((costButton != NULL) && (costButton->getCaption() != spell.mCostColumn)) { costButton->setCaption(spell.mCostColumn); @@ -187,7 +195,7 @@ namespace MWGui for (std::vector< LineInfo >::iterator it = mLines.begin(); it != mLines.end(); ++it) { - height += (it->get<0>())->getHeight(); + height += (it->mLeftWidget)->getHeight(); } bool scrollVisible = height > mScrollView->getHeight(); @@ -197,14 +205,14 @@ namespace MWGui for (std::vector< LineInfo >::iterator it = mLines.begin(); it != mLines.end(); ++it) { - int lineHeight = (it->get<0>())->getHeight(); - (it->get<0>())->setCoord(4, height, width - 8, lineHeight); - if (it->get<1>()) + int lineHeight = (it->mLeftWidget)->getHeight(); + (it->mLeftWidget)->setCoord(4, height, width - 8, lineHeight); + if (it->mRightWidget) { - (it->get<1>())->setCoord(4, height, width - 8, lineHeight); - MyGUI::TextBox* second = (it->get<1>())->castType(false); + (it->mRightWidget)->setCoord(4, height, width - 8, lineHeight); + MyGUI::TextBox* second = (it->mRightWidget)->castType(false); if (second) - (it->get<0>())->setSize(width - 8 - second->getTextSize().width, lineHeight); + (it->mLeftWidget)->setSize(width - 8 - second->getTextSize().width, lineHeight); } height += lineHeight; @@ -224,7 +232,7 @@ namespace MWGui MyGUI::IntCoord(0, 0, mScrollView->getWidth(), 18), MyGUI::Align::Left | MyGUI::Align::Top); separator->setNeedMouseFocus(false); - mLines.push_back(boost::make_tuple(separator, (MyGUI::Widget*)NULL, false)); + mLines.push_back(LineInfo(separator, (MyGUI::Widget*)NULL, NoSpellIndex)); } MyGUI::TextBox* groupWidget = mScrollView->createWidget("SandBrightText", @@ -243,10 +251,10 @@ namespace MWGui groupWidget2->setTextAlign(MyGUI::Align::Right); groupWidget2->setNeedMouseFocus(false); - mLines.push_back(boost::make_tuple(groupWidget, groupWidget2, false)); + mLines.push_back(LineInfo(groupWidget, groupWidget2, NoSpellIndex)); } else - mLines.push_back(boost::make_tuple(groupWidget, (MyGUI::Widget*)NULL, false)); + mLines.push_back(LineInfo(groupWidget, (MyGUI::Widget*)NULL, NoSpellIndex)); } diff --git a/apps/openmw/mwgui/spellview.hpp b/apps/openmw/mwgui/spellview.hpp index 2f6ff2624..7af1bda7a 100644 --- a/apps/openmw/mwgui/spellview.hpp +++ b/apps/openmw/mwgui/spellview.hpp @@ -56,11 +56,23 @@ namespace MWGui std::auto_ptr mModel; - /// tracks an item in the spell view - /// element<0> is the left column GUI object (usually holds the name) - /// element<1> is the right column (charge or cost info) - /// element<2> is if line needs to be checked during incremental update - typedef boost::tuple LineInfo; + /// tracks a row in the spell view + struct LineInfo + { + /// the widget on the left side of the row + MyGUI::Widget* mLeftWidget; + + /// the widget on the left side of the row (if there is one) + MyGUI::Widget* mRightWidget; + + /// index to item in mModel that row is showing information for + SpellModel::ModelIndex mSpellIndex; + + LineInfo(MyGUI::Widget* leftWidget, MyGUI::Widget* rightWidget, SpellModel::ModelIndex spellIndex); + }; + + /// magic number indicating LineInfo does not correspond to an item in mModel + enum { NoSpellIndex = -1 }; std::vector< LineInfo > mLines; From 0a5de33a1a6e7bd2ddd0848677e7f9827a2fe60b Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 6 Apr 2015 15:13:09 +1200 Subject: [PATCH 681/740] fireEquipmentChangedEvent() updates the InventoryWindow. (Fixes #2424) --- apps/openmw/mwworld/inventorystore.cpp | 19 ++++++++++++++----- apps/openmw/mwworld/inventorystore.hpp | 2 +- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 4503e66f5..2de3abc75 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -10,6 +10,9 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/windowmanager.hpp" + +#include "../mwgui/inventorywindow.hpp" #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/spellcasting.hpp" @@ -175,7 +178,7 @@ void MWWorld::InventoryStore::equip (int slot, const ContainerStoreIterator& ite flagAsModified(); - fireEquipmentChangedEvent(); + fireEquipmentChangedEvent(actor); updateMagicEffects(actor); } @@ -188,7 +191,7 @@ void MWWorld::InventoryStore::unequipAll(const MWWorld::Ptr& actor) mUpdatesEnabled = true; - fireEquipmentChangedEvent(); + fireEquipmentChangedEvent(actor); updateMagicEffects(actor); } @@ -318,7 +321,7 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) if (changed) { mSlots.swap (slots_); - fireEquipmentChangedEvent(); + fireEquipmentChangedEvent(actor); updateMagicEffects(actor); flagAsModified(); } @@ -549,7 +552,7 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipSlot(int slot, c } } - fireEquipmentChangedEvent(); + fireEquipmentChangedEvent(actor); updateMagicEffects(actor); return retval; @@ -576,12 +579,18 @@ void MWWorld::InventoryStore::setListener(InventoryStoreListener *listener, cons updateMagicEffects(actor); } -void MWWorld::InventoryStore::fireEquipmentChangedEvent() +void MWWorld::InventoryStore::fireEquipmentChangedEvent(const Ptr& actor) { if (!mUpdatesEnabled) return; if (mListener) mListener->equipmentChanged(); + + // if player, update inventory window + if (actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + { + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView(); + } } void MWWorld::InventoryStore::visitEffectSources(MWMechanics::EffectSourceVisitor &visitor) diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 9a154373a..6b906207e 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -111,7 +111,7 @@ namespace MWWorld void updateMagicEffects(const Ptr& actor); void updateRechargingItems(); - void fireEquipmentChangedEvent(); + void fireEquipmentChangedEvent(const Ptr& actor); virtual void storeEquipmentState (const MWWorld::LiveCellRefBase& ref, int index, ESM::InventoryState& inventory) const; virtual void readEquipmentState (const MWWorld::ContainerStoreIterator& iter, int index, const ESM::InventoryState& inventory); From bdf0d8db22c2a766e1774b2649b1e91cc69da24b Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 9 Apr 2015 19:11:19 +1000 Subject: [PATCH 682/740] Re-organise the inheritance structure once more in preparation for adding Pathgrid tables. --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/collection.hpp | 11 ++ apps/opencs/model/world/columnbase.cpp | 33 ++++ apps/opencs/model/world/columnbase.hpp | 24 ++- apps/opencs/model/world/data.cpp | 2 +- apps/opencs/model/world/idtable.cpp | 10 ++ apps/opencs/model/world/idtable.hpp | 4 + apps/opencs/model/world/idtree.cpp | 156 ++++++------------- apps/opencs/model/world/idtree.hpp | 13 +- apps/opencs/model/world/nestablecolumn.cpp | 44 ------ apps/opencs/model/world/nestablecolumn.hpp | 33 ---- apps/opencs/model/world/nestedcollection.cpp | 12 +- apps/opencs/model/world/nestedcollection.hpp | 26 ++-- apps/opencs/model/world/refidcollection.cpp | 8 +- apps/opencs/model/world/refidcollection.hpp | 11 +- 15 files changed, 165 insertions(+), 224 deletions(-) delete mode 100644 apps/opencs/model/world/nestablecolumn.cpp delete mode 100644 apps/opencs/model/world/nestablecolumn.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 39b4c486b..8cf37da1d 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -25,7 +25,7 @@ opencs_units (model/world opencs_units_noqt (model/world universalid record commands columnbase scriptcontext cell refidcollection refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope - pathgrid landtexture land nestedtablewrapper nestedadapters nestedcollection nestablecolumn + pathgrid landtexture land nestedtablewrapper nestedadapters nestedcollection ) opencs_hdrs_noqt (model/world diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 1fb3e1f1d..dc52ae663 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -148,6 +148,8 @@ namespace CSMWorld void setRecord (int index, const Record& record); ///< \attention This function must not change the ID. + + NestableColumn *getNestableColumn (int column); }; template @@ -289,6 +291,15 @@ namespace CSMWorld return *mColumns.at (column); } + template + NestableColumn *Collection::getNestableColumn (int column) + { + if (column < 0 || column >= static_cast(mColumns.size())) + throw std::runtime_error("column index out of range"); + + return mColumns.at (column); + } + template void Collection::addColumn (Column *column) { diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 665ab9354..94c5afb83 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -23,3 +23,36 @@ int CSMWorld::ColumnBase::getId() const { return mColumnId; } + +void CSMWorld::NestableColumn::addColumn(CSMWorld::NestableColumn *column) +{ + mNestedColumns.push_back(column); + mHasChildren = true; +} + +const CSMWorld::ColumnBase& CSMWorld::NestableColumn::nestedColumn(int subColumn) const +{ + if (!mHasChildren) + throw std::logic_error("Tried to access nested column of the non-nest column"); + + return *mNestedColumns.at(subColumn); +} + +CSMWorld::NestableColumn::NestableColumn(int columnId, CSMWorld::ColumnBase::Display displayType, + int flag) + : mHasChildren(false), CSMWorld::ColumnBase(columnId, displayType, flag) +{ +} + +CSMWorld::NestableColumn::~NestableColumn() +{ + for (unsigned int i = 0; i < mNestedColumns.size(); ++i) + { + delete mNestedColumns[i]; + } +} + +bool CSMWorld::NestableColumn::hasChildren() const +{ + return mHasChildren; +} diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index b717f3a52..da1d8f0df 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -129,14 +129,32 @@ namespace CSMWorld virtual std::string getTitle() const; - virtual int getId() const; + virtual int getId() const; // FIXME: why have an accessor for a public member? + }; + + class NestableColumn : public ColumnBase + { + std::vector mNestedColumns; + bool mHasChildren; + + public: + + NestableColumn(int columnId, Display displayType, int flag); + + ~NestableColumn(); + + void addColumn(CSMWorld::NestableColumn *column); + + const ColumnBase& nestedColumn(int subColumn) const; + + bool hasChildren() const; }; template - struct Column : public ColumnBase + struct Column : public NestableColumn { Column (int columnId, Display displayType, int flags = Flag_Table | Flag_Dialogue) - : ColumnBase (columnId, displayType, flags) {} + : NestableColumn (columnId, displayType, flags) {} virtual QVariant get (const Record& record) const = 0; diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index a5ef439a7..0cfc890ea 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -333,7 +333,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc addModel (new IdTable (&mMagicEffects), UniversalId::Type_MagicEffect); addModel (new IdTable (&mPathgrids), UniversalId::Type_Pathgrid); addModel (new IdTable (&mStartScripts), UniversalId::Type_StartScript); - addModel (new IdTree (&mReferenceables, IdTable::Feature_Preview), + addModel (new IdTree (&mReferenceables, &mReferenceables, IdTable::Feature_Preview), UniversalId::Type_Referenceable); addModel (new IdTable (&mRefs, IdTable::Feature_ViewCell | IdTable::Feature_Preview), UniversalId::Type_Reference); addModel (new IdTable (&mFilters), UniversalId::Type_Filter); diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 7618a073a..28742c8f2 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -1,5 +1,7 @@ #include "idtable.hpp" +#include + #include "collectionbase.hpp" #include "columnbase.hpp" @@ -42,6 +44,9 @@ QVariant CSMWorld::IdTable::headerData (int section, Qt::Orientation orientation if (orientation==Qt::Vertical) return QVariant(); + if (orientation != Qt::Horizontal) + throw std::logic_error("Unknown header orientation specified"); + if (role==Qt::DisplayRole) return tr (mIdCollection->getColumn (section).getTitle().c_str()); @@ -231,3 +236,8 @@ int CSMWorld::IdTable::getColumnId(int column) const { return mIdCollection->getColumn(column).getId(); } + +CSMWorld::CollectionBase *CSMWorld::IdTable::idCollection() const +{ + return mIdCollection; +} diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index ea8ab80f9..914b01cf9 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -83,6 +83,10 @@ namespace CSMWorld virtual bool isDeleted (const std::string& id) const; int getColumnId(int column) const; + + protected: + + virtual CollectionBase *idCollection() const; }; } diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp index 595b0ac51..4befd1eee 100644 --- a/apps/opencs/model/world/idtree.cpp +++ b/apps/opencs/model/world/idtree.cpp @@ -1,34 +1,33 @@ #include "idtree.hpp" -#include "nestedtablewrapper.hpp" // FIXME: is this necessary? +#include "nestedtablewrapper.hpp" +#include "collectionbase.hpp" #include "nestedcollection.hpp" -#include "nestablecolumn.hpp" +#include "columnbase.hpp" -CSMWorld::IdTree::IdTree (NestedCollection *idCollection, unsigned int features) -: IdTable (idCollection, features), mIdCollection (idCollection) +// NOTE: parent class still needs idCollection +CSMWorld::IdTree::IdTree (NestedCollection *nestedCollection, CollectionBase *idCollection, unsigned int features) +: IdTable (idCollection, features), mNestedCollection (nestedCollection) {} CSMWorld::IdTree::~IdTree() -{ - // FIXME: workaround only, a proper fix should stop QHideEvent calls after destruction - mIdCollection = 0; -} +{} int CSMWorld::IdTree::rowCount (const QModelIndex & parent) const { if (hasChildren(parent)) - return mIdCollection->getNestedRowsCount(parent.row(), parent.column()); + return mNestedCollection->getNestedRowsCount(parent.row(), parent.column()); - return mIdCollection->getSize(); + return IdTable::rowCount(parent); } int CSMWorld::IdTree::columnCount (const QModelIndex & parent) const { if (hasChildren(parent)) - return mIdCollection->getNestedColumnsCount(parent.row(), parent.column()); + return mNestedCollection->getNestedColumnsCount(parent.row(), parent.column()); - return mIdCollection->getColumns(); + return IdTable::columnCount(parent); } QVariant CSMWorld::IdTree::data (const QModelIndex & index, int role) const @@ -39,60 +38,39 @@ QVariant CSMWorld::IdTree::data (const QModelIndex & index, int role) const if ((role!=Qt::DisplayRole && role!=Qt::EditRole) || index.row() < 0 || index.column() < 0) return QVariant(); - if (role==Qt::EditRole && !mIdCollection->getColumn (index.column()).isEditable()) + if (role==Qt::EditRole && !idCollection()->getColumn (index.column()).isEditable()) return QVariant(); if (index.internalId() != 0) { std::pair parentAdress(unfoldIndexAdress(index.internalId())); - return mIdCollection->getNestedData(parentAdress.first, + return mNestedCollection->getNestedData(parentAdress.first, parentAdress.second, index.row(), index.column()); } else - return mIdCollection->getData (index.row(), index.column()); -} - -QVariant CSMWorld::IdTree::headerData (int section, Qt::Orientation orientation, int role) const -{ - if (orientation==Qt::Vertical) - return QVariant(); - - if (orientation != Qt::Horizontal) - throw std::logic_error("Unknown header orientation specified"); - - if (role == Qt::DisplayRole) - return tr (mIdCollection->getColumn (section).getTitle().c_str()); - - if (role == ColumnBase::Role_Flags) - return mIdCollection->getColumn (section).mFlags; - - if (role == ColumnBase::Role_Display) - return mIdCollection->getColumn (section).mDisplayType; - - return QVariant(); + return idCollection()->getData (index.row(), index.column()); } QVariant CSMWorld::IdTree::nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role) const { // FIXME: workaround only, a proper fix should stop QHideEvent calls after destruction - if (section < 0 || !mIdCollection || section >= mIdCollection->getColumns()) + if (section < 0 || !idCollection() || section >= idCollection()->getColumns()) return QVariant(); - // FIXME: dynamic cast - const NestableColumn& parentColumn = dynamic_cast(mIdCollection->getColumn(section)); + const NestableColumn *parentColumn = mNestedCollection->getNestableColumn(section); if (orientation==Qt::Vertical) return QVariant(); if (role==Qt::DisplayRole) - return tr(parentColumn.nestedColumn(subSection).getTitle().c_str()); + return tr(parentColumn->nestedColumn(subSection).getTitle().c_str()); if (role==ColumnBase::Role_Flags) - return mIdCollection->getColumn (section).mFlags; + return idCollection()->getColumn (section).mFlags; if (role==ColumnBase::Role_Display) - return parentColumn.nestedColumn(subSection).mDisplayType; + return parentColumn->nestedColumn(subSection).mDisplayType; return QVariant(); } @@ -101,32 +79,21 @@ bool CSMWorld::IdTree::setData (const QModelIndex &index, const QVariant &value, { if (index.internalId() != 0) { - if (mIdCollection->getColumn(parent(index).column()).isEditable() && role==Qt::EditRole) + if (idCollection()->getColumn(parent(index).column()).isEditable() && role==Qt::EditRole) { const std::pair& parentAdress(unfoldIndexAdress(index.internalId())); - mIdCollection->setNestedData(parentAdress.first, parentAdress.second, value, index.row(), index.column()); + mNestedCollection->setNestedData(parentAdress.first, parentAdress.second, value, index.row(), index.column()); emit dataChanged (CSMWorld::IdTree::index (parentAdress.first, 0), - CSMWorld::IdTree::index (parentAdress.second, mIdCollection->getColumns()-1)); + CSMWorld::IdTree::index (parentAdress.second, idCollection()->getColumns()-1)); return true; } else return false; } - - if (mIdCollection->getColumn (index.column()).isEditable() && role==Qt::EditRole) - { - mIdCollection->setData (index.row(), index.column(), value); - - emit dataChanged (CSMWorld::IdTree::index (index.row(), 0), - CSMWorld::IdTree::index (index.row(), mIdCollection->getColumns()-1)); - - return true; - } - - return false; + return IdTable::setData(index, value, role); } Qt::ItemFlags CSMWorld::IdTree::flags (const QModelIndex & index) const @@ -134,39 +101,29 @@ Qt::ItemFlags CSMWorld::IdTree::flags (const QModelIndex & index) const if (!index.isValid()) return 0; - Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; - - if (mIdCollection->getColumn (index.column()).isUserEditable()) - flags |= Qt::ItemIsEditable; - - return flags; + return IdTable::flags(index); } bool CSMWorld::IdTree::removeRows (int row, int count, const QModelIndex& parent) { - beginRemoveRows (parent, row, row+count-1); - if (parent.isValid()) { + beginRemoveRows (parent, row, row+count-1); + for (int i = 0; i < count; ++i) { - mIdCollection->removeNestedRows(parent.row(), parent.column(), row+i); + mNestedCollection->removeNestedRows(parent.row(), parent.column(), row+i); } - } - else - { - - beginRemoveRows (parent, row, row+count-1); - - mIdCollection->removeRows (row, count); - } - endRemoveRows(); + endRemoveRows(); - emit dataChanged (CSMWorld::IdTree::index (parent.row(), 0), - CSMWorld::IdTree::index (parent.row(), mIdCollection->getColumns()-1)); + emit dataChanged (CSMWorld::IdTree::index (parent.row(), 0), + CSMWorld::IdTree::index (parent.row(), idCollection()->getColumns()-1)); - return true; + return true; + } + else + return IdTable::removeRows(row, count, parent); } void CSMWorld::IdTree::addNestedRow(const QModelIndex& parent, int position) @@ -177,11 +134,11 @@ void CSMWorld::IdTree::addNestedRow(const QModelIndex& parent, int position) int row = parent.row(); beginInsertRows(parent, position, position); - mIdCollection->addNestedRow(row, parent.column(), position); + mNestedCollection->addNestedRow(row, parent.column(), position); endInsertRows(); emit dataChanged (CSMWorld::IdTree::index (row, 0), - CSMWorld::IdTree::index (row, mIdCollection->getColumns()-1)); + CSMWorld::IdTree::index (row, idCollection()->getColumns()-1)); } QModelIndex CSMWorld::IdTree::index (int row, int column, const QModelIndex& parent) const @@ -192,10 +149,10 @@ QModelIndex CSMWorld::IdTree::index (int row, int column, const QModelIndex& par encodedId = this->foldIndexAdress(parent); } - if (row<0 || row>=mIdCollection->getSize()) + if (row<0 || row>=idCollection()->getSize()) return QModelIndex(); - if (column<0 || column>=mIdCollection->getColumns()) + if (column<0 || column>=idCollection()->getColumns()) return QModelIndex(); return createIndex(row, column, encodedId); // store internal id @@ -215,28 +172,6 @@ QModelIndex CSMWorld::IdTree::parent (const QModelIndex& index) const return createIndex(adress.first, adress.second); } -void CSMWorld::IdTree::setRecord (const std::string& id, const RecordBase& record) -{ - int index = mIdCollection->searchId (id); - - if (index==-1) - { - int index = mIdCollection->getAppendIndex (id); - - beginInsertRows (QModelIndex(), index, index); - - mIdCollection->appendRecord (record); - - endInsertRows(); - } - else - { - mIdCollection->replace (index, record); - emit dataChanged (CSMWorld::IdTree::index (index, 0), - CSMWorld::IdTree::index (index, mIdCollection->getColumns()-1)); - } -} - unsigned int CSMWorld::IdTree::foldIndexAdress (const QModelIndex& index) const { unsigned int out = index.row() * this->columnCount(); @@ -255,13 +190,16 @@ std::pair< int, int > CSMWorld::IdTree::unfoldIndexAdress (unsigned int id) cons return std::make_pair (row, column); } +// index.data().isValid() requires RefIdAdapter::getData() to return a valid QVariant for +// nested columns (refidadapterimp.hpp) +// +// Also see comments in refidadapter.hpp and refidadapterimp.hpp. bool CSMWorld::IdTree::hasChildren(const QModelIndex& index) const { - // FIXME: dynamic cast return (index.isValid() && index.internalId() == 0 && - dynamic_cast(mIdCollection->getColumn(index.column())).hasChildren() && - index.data().isValid()); + mNestedCollection->getNestableColumn(index.column())->hasChildren() && + index.data().isValid()); // FIXME: not sure why this check is also needed } void CSMWorld::IdTree::setNestedTable(const QModelIndex& index, const CSMWorld::NestedTableWrapperBase& nestedTable) @@ -276,10 +214,10 @@ void CSMWorld::IdTree::setNestedTable(const QModelIndex& index, const CSMWorld:: removeRowsMode = true; } - mIdCollection->setNestedTable(index.row(), index.column(), nestedTable); + mNestedCollection->setNestedTable(index.row(), index.column(), nestedTable); emit dataChanged (CSMWorld::IdTree::index (index.row(), 0), - CSMWorld::IdTree::index (index.row(), mIdCollection->getColumns()-1)); + CSMWorld::IdTree::index (index.row(), idCollection()->getColumns()-1)); if (removeRowsMode) { @@ -292,5 +230,5 @@ CSMWorld::NestedTableWrapperBase* CSMWorld::IdTree::nestedTable(const QModelInde if (!hasChildren(index)) throw std::logic_error("Tried to retrive nested table, but index has no children"); - return mIdCollection->nestedTable(index.row(), index.column()); + return mNestedCollection->nestedTable(index.row(), index.column()); } diff --git a/apps/opencs/model/world/idtree.hpp b/apps/opencs/model/world/idtree.hpp index 6a3d7423c..80b44d241 100644 --- a/apps/opencs/model/world/idtree.hpp +++ b/apps/opencs/model/world/idtree.hpp @@ -22,13 +22,13 @@ namespace CSMWorld struct RecordBase; class NestedTableWrapperBase; // FIXME: is this necessary? - class IdTree : public IdTable // IdTable is derived from QAbstractItemModel + class IdTree : public IdTable { Q_OBJECT private: - NestedCollection *mIdCollection; + NestedCollection *mNestedCollection; // not implemented IdTree (const IdTree&); @@ -39,8 +39,8 @@ namespace CSMWorld public: - IdTree (NestedCollection *idCollection, unsigned int features = 0); - ///< The ownership of \a idCollection is not transferred. + IdTree (NestedCollection *nestedCollection, CollectionBase *idCollection, unsigned int features = 0); + ///< The ownerships of \a nestedCollecton and \a idCollection are not transferred. virtual ~IdTree(); @@ -50,8 +50,6 @@ namespace CSMWorld virtual QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const; - virtual QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; - virtual bool setData ( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); virtual Qt::ItemFlags flags (const QModelIndex & index) const; @@ -63,9 +61,6 @@ namespace CSMWorld virtual QModelIndex parent (const QModelIndex& index) const; - void setRecord (const std::string& id, const RecordBase& record); - ///< Add record or overwrite existing recrod. - // TODO: check if below methods are really needed QVariant nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role = Qt::DisplayRole) const; diff --git a/apps/opencs/model/world/nestablecolumn.cpp b/apps/opencs/model/world/nestablecolumn.cpp deleted file mode 100644 index 4ade75b33..000000000 --- a/apps/opencs/model/world/nestablecolumn.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "nestablecolumn.hpp" - -#include - -void CSMWorld::NestableColumn::addColumn(CSMWorld::NestableColumn *column) -{ - mNestedColumns.push_back(column); - mHasChildren = true; -} - -const CSMWorld::ColumnBase& CSMWorld::NestableColumn::nestedColumn(int subColumn) const -{ - if (!mHasChildren) - throw std::logic_error("Tried to access nested column of the non-nest column"); - - return *mNestedColumns.at(subColumn); -} - -int CSMWorld::NestableColumn::nestedColumnCount() const -{ - if (!mHasChildren) - throw std::logic_error("Tried to access number of the subcolumns in the non-nest column"); - - return mNestedColumns.size(); -} - -CSMWorld::NestableColumn::NestableColumn(int columnId, CSMWorld::ColumnBase::Display displayType, - int flag, const CSMWorld::NestableColumn* parent) - : mParent(parent), mHasChildren(false), CSMWorld::ColumnBase(columnId, displayType, flag) -{ -} - -CSMWorld::NestableColumn::~NestableColumn() -{ - for (unsigned int i = 0; i < mNestedColumns.size(); ++i) - { - delete mNestedColumns[i]; - } -} - -bool CSMWorld::NestableColumn::hasChildren() const -{ - return mHasChildren; -} diff --git a/apps/opencs/model/world/nestablecolumn.hpp b/apps/opencs/model/world/nestablecolumn.hpp deleted file mode 100644 index 28ced85e9..000000000 --- a/apps/opencs/model/world/nestablecolumn.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef CSM_WOLRD_NESTABLECOLUMN_H -#define CSM_WOLRD_NESTABLECOLUMN_H - -#include - -#include "columnbase.hpp" - -namespace CSMWorld -{ - class NestableColumn : public ColumnBase - { - std::vector mNestedColumns; - const NestableColumn* mParent; - bool mHasChildren; // cached - - public: - - NestableColumn(int columnId, - Display displayType, int flag, const NestableColumn* parent = 0); - - ~NestableColumn(); - - void addColumn(CSMWorld::NestableColumn *column); - - const ColumnBase& nestedColumn(int subColumn) const; - - int nestedColumnCount() const; - - bool hasChildren() const; - }; -} - -#endif diff --git a/apps/opencs/model/world/nestedcollection.cpp b/apps/opencs/model/world/nestedcollection.cpp index f557c3ba1..937ad6ad6 100644 --- a/apps/opencs/model/world/nestedcollection.cpp +++ b/apps/opencs/model/world/nestedcollection.cpp @@ -1,7 +1,17 @@ #include "nestedcollection.hpp" -CSMWorld::NestedCollection::NestedCollection() : mParent(0) +CSMWorld::NestedCollection::NestedCollection() {} CSMWorld::NestedCollection::~NestedCollection() {} + +int CSMWorld::NestedCollection::getNestedRowsCount(int row, int column) const +{ + return 0; +} + +int CSMWorld::NestedCollection::getNestedColumnsCount(int row, int column) const +{ + return 0; +} diff --git a/apps/opencs/model/world/nestedcollection.hpp b/apps/opencs/model/world/nestedcollection.hpp index 5ec50b423..8046f9a09 100644 --- a/apps/opencs/model/world/nestedcollection.hpp +++ b/apps/opencs/model/world/nestedcollection.hpp @@ -1,17 +1,14 @@ #ifndef CSM_WOLRD_NESTEDCOLLECTION_H #define CSM_WOLRD_NESTEDCOLLECTION_H -#include - -#include "collectionbase.hpp" - class QVariant; namespace CSMWorld { + class NestableColumn; class NestedTableWrapperBase; - class NestedCollection : public CollectionBase + class NestedCollection { public: @@ -21,25 +18,22 @@ namespace CSMWorld virtual void addNestedRow(int row, int col, int position) = 0; - virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const = 0; - - virtual NestedTableWrapperBase* nestedTable(int row, int column) const = 0; + virtual void removeNestedRows(int row, int column, int subRow) = 0; - virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable) = 0; + virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const = 0; virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn) = 0; - virtual int getNestedRowsCount(int row, int column) const = 0; + virtual NestedTableWrapperBase* nestedTable(int row, int column) const = 0; - virtual int getNestedColumnsCount(int row, int column) const = 0; + virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable) = 0; - virtual void removeNestedRows(int row, int column, int subRow) = 0; + virtual int getNestedRowsCount(int row, int column) const; - private: + virtual int getNestedColumnsCount(int row, int column) const; - std::vector mChildren; - NestedCollection *mParent; // currently unused + virtual NestableColumn *getNestableColumn(int column) = 0; }; } -#endif +#endif // CSM_WOLRD_NESTEDCOLLECTION_H diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index ca5efcdd9..41ca7e440 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -8,7 +8,7 @@ #include "refidadapter.hpp" #include "refidadapterimp.hpp" #include "columns.hpp" -#include "nestedtablewrapper.hpp" // FIXME: is this really necessary? +#include "nestedtablewrapper.hpp" CSMWorld::RefIdColumn::RefIdColumn (int columnId, Display displayType, int flag, bool editable, bool userEditable) @@ -25,7 +25,6 @@ bool CSMWorld::RefIdColumn::isUserEditable() const return mUserEditable; } - // FIXME: const problem /*const*/ CSMWorld::RefIdAdapter& CSMWorld::RefIdCollection::findAdapter (UniversalId::Type type) const { @@ -667,6 +666,11 @@ int CSMWorld::RefIdCollection::getNestedColumnsCount(int row, int column) const return adaptor.getNestedColumnsCount(&mColumns.at(column), mData); } +CSMWorld::NestableColumn *CSMWorld::RefIdCollection::getNestableColumn(int column) +{ + return &mColumns.at(column); +} + void CSMWorld::RefIdCollection::addNestedRow(int row, int col, int position) { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index dd432c5a9..2a271a846 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -5,7 +5,8 @@ #include #include -#include "nestablecolumn.hpp" +#include "columnbase.hpp" +#include "collectionbase.hpp" #include "nestedcollection.hpp" #include "refiddata.hpp" @@ -17,7 +18,7 @@ namespace ESM namespace CSMWorld { class RefIdAdapter; - class NestedTableWrapperBase; // FIXME: is this really needed? + class NestedTableWrapperBase; class RefIdColumn : public NestableColumn { @@ -35,7 +36,7 @@ namespace CSMWorld virtual bool isUserEditable() const; }; - class RefIdCollection : public NestedCollection + class RefIdCollection : public CollectionBase, public NestedCollection { private: @@ -117,12 +118,12 @@ namespace CSMWorld virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable); - // FIXME virtual int getNestedRowsCount(int row, int column) const; - // FIXME virtual int getNestedColumnsCount(int row, int column) const; + NestableColumn *getNestableColumn(int column); + virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn); virtual void removeNestedRows(int row, int column, int subRow); From 05210d7f2133387cdd8b581c1ea30dba3b15449a Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 9 Apr 2015 19:29:03 +1000 Subject: [PATCH 683/740] Nested table support for Pathgrids. --- apps/opencs/model/world/collection.hpp | 8 + apps/opencs/model/world/columnbase.cpp | 1 - apps/opencs/model/world/columnbase.hpp | 2 + apps/opencs/model/world/columnimp.hpp | 99 ++++++++- apps/opencs/model/world/columns.cpp | 8 + apps/opencs/model/world/columns.hpp | 9 + apps/opencs/model/world/data.cpp | 19 +- apps/opencs/model/world/idadapter.hpp | 39 ++++ apps/opencs/model/world/idadapterimp.hpp | 202 ++++++++++++++++++ apps/opencs/model/world/subcellcollection.hpp | 122 ++++++++++- 10 files changed, 503 insertions(+), 6 deletions(-) create mode 100644 apps/opencs/model/world/idadapter.hpp create mode 100644 apps/opencs/model/world/idadapterimp.hpp diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index dc52ae663..4bc9632a8 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -120,6 +120,8 @@ namespace CSMWorld virtual const Record& getRecord (int index) const; + virtual Record& getRecord (int index); + virtual int getAppendIndex (const std::string& id, UniversalId::Type type = UniversalId::Type_None) const; ///< \param type Will be ignored, unless the collection supports multiple record types @@ -433,6 +435,12 @@ namespace CSMWorld return mRecords.at (index); } + template + Record& Collection::getRecord (int index) + { + return mRecords.at (index); + } + template void Collection::insertRecord (const RecordBase& record, int index, UniversalId::Type type) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 94c5afb83..e4d2195be 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -1,4 +1,3 @@ - #include "columnbase.hpp" #include "columns.hpp" diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index da1d8f0df..aef68fdbd 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -97,6 +97,8 @@ namespace CSMWorld Display_NestedItemList, Display_NestedSpellList, Display_NestedDestinationsList, + Display_PathgridPointList, + Display_PathgridEdgeList, Display_EnchantmentType, Display_BodyPartType, diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index da14bb495..27fc3ad04 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -1277,7 +1277,6 @@ namespace CSMWorld } }; - template struct PosColumn : public Column { @@ -2265,6 +2264,104 @@ namespace CSMWorld return true; } }; + + template + struct PathgridPointListColumn : public Column + { + PathgridPointListColumn () + : Column (Columns::ColumnId_PathgridPoints, + ColumnBase::Display_PathgridPointList, ColumnBase::Flag_Dialogue) + { + } + + virtual QVariant get (const Record& record) const + { + return true; // required by IdTree::hasChildren() + } + + virtual void set (Record& record, const QVariant& data) + { + } + + virtual bool isEditable() const + { + return true; + } + }; + + template + struct PathgridPointColumn : public Column + { + int mIndex; // 0=PosX, 1=PosY, 2=PosZ + + PathgridPointColumn(int index) + : Column (Columns::ColumnId_PathgridPosX+index, ColumnBase::Display_Integer), mIndex(index) + {} + + virtual QVariant get (const Record& record) const + { + return QVariant(); // FIXME + } + + virtual void set (Record& record, const QVariant& data) + { + } + + virtual bool isEditable() const + { + return true; + } + }; + + template + struct PathgridEdgeListColumn : public Column + { + PathgridEdgeListColumn () + : Column (Columns::ColumnId_PathgridEdges, + ColumnBase::Display_PathgridEdgeList, ColumnBase::Flag_Dialogue) + { + } + + virtual QVariant get (const Record& record) const + { + return true; // required by IdTree::hasChildren() + } + + virtual void set (Record& record, const QVariant& data) + { + } + + virtual bool isEditable() const + { + return true; + } + + }; + + template + struct PathgridEdgeColumn : public Column + { + int mIndex; + + PathgridEdgeColumn (int index) + : Column (Columns::ColumnId_PathgridEdge0+index, ColumnBase::Display_Integer), mIndex(index) + { + } + + virtual QVariant get (const Record& record) const + { + return QVariant(); // FIXME + } + + virtual void set (Record& record, const QVariant& data) + { + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 1d3bc7641..db0ebfd86 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -223,6 +223,14 @@ namespace CSMWorld { ColumnId_AreaSound, "Area Sound" }, { ColumnId_BoltSound, "Bolt Sound" }, + { ColumnId_PathgridPoints, "Points"}, + { ColumnId_PathgridPosX, "X"}, + { ColumnId_PathgridPosY, "Y"}, + { ColumnId_PathgridPosZ, "Z"}, + { ColumnId_PathgridEdges, "Edges"}, + { ColumnId_PathgridEdge0, "Edge 0"}, + { ColumnId_PathgridEdge1, "Edge 1"}, + { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue3, "Use value 3" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 1c0af217b..e36e29b3b 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -211,6 +211,15 @@ namespace CSMWorld ColumnId_HitSound = 196, ColumnId_AreaSound = 197, ColumnId_BoltSound = 198, + + ColumnId_PathgridPoints = 199, + ColumnId_PathgridPosX = 200, + ColumnId_PathgridPosY = 201, + ColumnId_PathgridPosZ = 202, + ColumnId_PathgridEdges = 203, + ColumnId_PathgridEdge0 = 204, + ColumnId_PathgridEdge1 = 205, + // 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 0cfc890ea..ea94fe905 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -18,6 +18,7 @@ #include "columns.hpp" #include "resourcesmanager.hpp" #include "resourcetable.hpp" +#include "idadapterimp.hpp" void CSMWorld::Data::addModel (QAbstractItemModel *model, UniversalId::Type type, bool update) { @@ -255,6 +256,22 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mPathgrids.addColumn (new RecordStateColumn); mPathgrids.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Pathgrid)); + // new object deleted in dtor of Collection + PathgridPointListColumn *pointList = new PathgridPointListColumn (); + mPathgrids.addColumn (pointList); + // new object deleted in dtor of SubCellCollection + mPathgrids.addAdapter (std::make_pair(pointList, new PathgridPointListAdapter ())); + // new objects deleted in dtor of NestableColumn + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridPointColumn (0)); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridPointColumn (1)); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridPointColumn (2)); + + PathgridEdgeListColumn *edgeList = new PathgridEdgeListColumn (); + mPathgrids.addColumn (edgeList); + mPathgrids.addAdapter (std::make_pair(edgeList, new PathgridEdgeListAdapter ())); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridEdgeColumn (0)); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridEdgeColumn (1)); + mStartScripts.addColumn (new StringIdColumn); mStartScripts.addColumn (new RecordStateColumn); mStartScripts.addColumn (new FixedRecordTypeColumn (UniversalId::Type_StartScript)); @@ -331,7 +348,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc addModel (new IdTable (&mBodyParts), UniversalId::Type_BodyPart); addModel (new IdTable (&mSoundGens), UniversalId::Type_SoundGen); addModel (new IdTable (&mMagicEffects), UniversalId::Type_MagicEffect); - addModel (new IdTable (&mPathgrids), UniversalId::Type_Pathgrid); + addModel (new IdTree (&mPathgrids, &mPathgrids), UniversalId::Type_Pathgrid); addModel (new IdTable (&mStartScripts), UniversalId::Type_StartScript); addModel (new IdTree (&mReferenceables, &mReferenceables, IdTable::Feature_Preview), UniversalId::Type_Referenceable); diff --git a/apps/opencs/model/world/idadapter.hpp b/apps/opencs/model/world/idadapter.hpp new file mode 100644 index 000000000..bec21a0f3 --- /dev/null +++ b/apps/opencs/model/world/idadapter.hpp @@ -0,0 +1,39 @@ +#ifndef CSM_WOLRD_IDADAPTER_H +#define CSM_WOLRD_IDADAPTER_H + +#include "record.hpp" + +class QVariant; + +namespace CSMWorld +{ + class NestedTableWrapperBase; + + template + class NestedIdAdapter + { + public: + + NestedIdAdapter() {} + + virtual ~NestedIdAdapter() {} + + virtual void addNestedRow(Record& record, int position) const = 0; + + virtual void removeNestedRow(Record& record, int rowToRemove) const = 0; + + virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) = 0; + + virtual NestedTableWrapperBase* nestedTable(const Record& record) const = 0; + + virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const = 0; + + virtual void setNestedData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const = 0; + + virtual int getNestedColumnsCount(const Record& record) const = 0; + + virtual int getNestedRowsCount(const Record& record) const = 0; + }; +} + +#endif // CSM_WOLRD_IDADAPTER_H diff --git a/apps/opencs/model/world/idadapterimp.hpp b/apps/opencs/model/world/idadapterimp.hpp new file mode 100644 index 000000000..fa7c55bd3 --- /dev/null +++ b/apps/opencs/model/world/idadapterimp.hpp @@ -0,0 +1,202 @@ +#ifndef CSM_WOLRD_IDADAPTERIMP_H +#define CSM_WOLRD_IDADAPTERIMP_H + +#include + +#include + +#include "idadapter.hpp" + +namespace CSMWorld +{ + class NestedTableWrapperBase; + + template + class PathgridPointListAdapter : public NestedIdAdapter + { + public: + PathgridPointListAdapter () {} + + virtual void addNestedRow(Record& record, int position) const + { + ESXRecordT pathgrid = record.get(); + + ESXRecordT::PointList& points = pathgrid.mPoints; + + // blank row + ESM::Pathgrid::Point point; + point.mX = 0; + point.mY = 0; + point.mZ = 0; + point.mAutogenerated = 0; + point.mConnectionNum = 0; + point.mUnknown = 0; + + // FIXME: inserting a point should trigger re-indexing of the edges + points.insert(points.begin()+position, point); + pathgrid.mData.mS2 += 1; // increment the number of points + + record.setModified (pathgrid); + } + + virtual void removeNestedRow(Record& record, int rowToRemove) const + { + ESXRecordT pathgrid = record.get(); + + ESXRecordT::PointList& points = pathgrid.mPoints; + + if (rowToRemove < 0 || rowToRemove >= static_cast (points.size())) + throw std::runtime_error ("index out of range"); + + // FIXME: deleting a point should trigger re-indexing of the edges + points.erase(points.begin()+rowToRemove); + pathgrid.mData.mS2 -= 1; // decrement the number of points + + record.setModified (pathgrid); + } + + virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) + { + record.get().mPoints = + static_cast &>(nestedTable).mNestedTable; + } + + virtual NestedTableWrapperBase* nestedTable(const Record& record) const + { + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper(record.get().mPoints); + } + + virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const + { + ESM::Pathgrid::Point point = record.get().mPoints[subRowIndex]; + switch (subColIndex) + { + case 0: return point.mX; + case 1: return point.mY; + case 2: return point.mZ; + default: throw std::logic_error("Pathgrid point subcolumn index out of range"); + } + } + + virtual void setNestedData(Record& record, const QVariant& value, + int subRowIndex, int subColIndex) const + { + ESXRecordT pathgrid = record.get(); + ESM::Pathgrid::Point point = pathgrid.mPoints[subRowIndex]; + switch (subColIndex) + { + case 0: point.mX = value.toInt(); break; + case 1: point.mY = value.toInt(); break; + case 2: point.mZ = value.toInt(); break; + default: throw std::logic_error("Pathgrid point subcolumn index out of range"); + } + + pathgrid.mPoints[subRowIndex] = point; + + record.setModified (pathgrid); + } + + virtual int getNestedColumnsCount(const Record& record) const + { + return 3; + } + + virtual int getNestedRowsCount(const Record& record) const + { + return static_cast(record.get().mPoints.size()); + } + }; + + template + class PathgridEdgeListAdapter : public NestedIdAdapter + { + public: + PathgridEdgeListAdapter () {} + + // FIXME: seems to be auto-sorted in the dialog table display after insertion + virtual void addNestedRow(Record& record, int position) const + { + ESXRecordT pathgrid = record.get(); + + ESXRecordT::EdgeList& edges = pathgrid.mEdges; + + // blank row + ESM::Pathgrid::Edge edge; + edge.mV0 = 0; + edge.mV1 = 0; + + // FIXME: inserting a blank edge does not really make sense, perhaps this should be a + // logic_error exception + edges.insert(edges.begin()+position, edge); + + record.setModified (pathgrid); + } + + virtual void removeNestedRow(Record& record, int rowToRemove) const + { + ESXRecordT pathgrid = record.get(); + + ESXRecordT::EdgeList& edges = pathgrid.mEdges; + + if (rowToRemove < 0 || rowToRemove >= static_cast (edges.size())) + throw std::runtime_error ("index out of range"); + + edges.erase(edges.begin()+rowToRemove); + + record.setModified (pathgrid); + } + + virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) + { + record.get().mEdges = + static_cast &>(nestedTable).mNestedTable; + } + + virtual NestedTableWrapperBase* nestedTable(const Record& record) const + { + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper(record.get().mEdges); + } + + virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const + { + ESM::Pathgrid::Edge edge = record.get().mEdges[subRowIndex]; + switch (subColIndex) + { + case 0: return edge.mV0; + case 1: return edge.mV1; + default: throw std::logic_error("Pathgrid edge subcolumn index out of range"); + } + } + + virtual void setNestedData(Record& record, const QVariant& value, + int subRowIndex, int subColIndex) const + { + ESXRecordT pathgrid = record.get(); + ESM::Pathgrid::Edge edge = pathgrid.mEdges[subRowIndex]; + switch (subColIndex) + { + case 0: edge.mV0 = value.toInt(); break; + case 1: edge.mV1 = value.toInt(); break; + default: throw std::logic_error("Pathgrid edge subcolumn index out of range"); + } + + pathgrid.mEdges[subRowIndex] = edge; + + record.setModified (pathgrid); + } + + virtual int getNestedColumnsCount(const Record& record) const + { + return 2; + } + + virtual int getNestedRowsCount(const Record& record) const + { + return static_cast(record.get().mEdges.size()); + } + }; +} + +#endif // CSM_WOLRD_IDADAPTERIMP_H diff --git a/apps/opencs/model/world/subcellcollection.hpp b/apps/opencs/model/world/subcellcollection.hpp index 74bb6c955..f2aeb5aaf 100644 --- a/apps/opencs/model/world/subcellcollection.hpp +++ b/apps/opencs/model/world/subcellcollection.hpp @@ -1,6 +1,17 @@ #ifndef CSM_WOLRD_SUBCOLLECTION_H #define CSM_WOLRD_SUBCOLLECTION_H +#include +#include + +#include + +#include "columnimp.hpp" +#include "idcollection.hpp" +#include "nestedcollection.hpp" +#include "nestedtablewrapper.hpp" +#include "idadapterimp.hpp" + namespace ESM { class ESMReader; @@ -14,17 +25,40 @@ namespace CSMWorld /// \brief Single type collection of top level records that are associated with cells template > - class SubCellCollection : public IdCollection + class SubCellCollection : public IdCollection, public NestedCollection { const IdCollection& mCells; + std::map* > mAdapters; virtual void loadRecord (ESXRecordT& record, ESM::ESMReader& reader); + NestedIdAdapter* getAdapter(const ColumnBase &column) const; + public: SubCellCollection (const IdCollection& cells); + ~SubCellCollection(); + + virtual void addNestedRow(int row, int column, int position); + + virtual void removeNestedRows(int row, int column, int subRow); + + virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const; + + virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn); + virtual NestedTableWrapperBase* nestedTable(int row, int column) const; + virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable); + + virtual int getNestedRowsCount(int row, int column) const; + + virtual int getNestedColumnsCount(int row, int column) const; + + // this method is inherited from NestedCollection, not from Collection + virtual NestableColumn *getNestableColumn(int column); + + void addAdapter(std::pair* > adapter); }; template @@ -35,11 +69,93 @@ namespace CSMWorld } template - SubCellCollection::SubCellCollection ( - const IdCollection& cells) + SubCellCollection::SubCellCollection (const IdCollection& cells) : mCells (cells) {} + template + SubCellCollection::~SubCellCollection() + { + for (std::map* >::iterator iter (mAdapters.begin()); + iter!=mAdapters.end(); ++iter) + delete (*iter).second; + } + + template + void SubCellCollection::addAdapter(std::pair* > adapter) + { + mAdapters.insert(adapter); + } + + template + NestedIdAdapter* SubCellCollection::getAdapter(const ColumnBase &column) const + { + std::map* >::const_iterator iter = + mAdapters.find (&column); + + if (iter==mAdapters.end()) + throw std::logic_error("No such column in the nestedidadapter"); + + return iter->second; + } + + template + void SubCellCollection::addNestedRow(int row, int column, int position) + { + getAdapter(getColumn(column))->addNestedRow(getRecord(row), position); + } + + template + void SubCellCollection::removeNestedRows(int row, int column, int subRow) + { + getAdapter(getColumn(column))->removeNestedRow(getRecord(row), subRow); + } + + template + QVariant SubCellCollection::getNestedData (int row, + int column, int subRow, int subColumn) const + { + return getAdapter(getColumn(column))->getNestedData(getRecord(row), subRow, subColumn); + } + + template + void SubCellCollection::setNestedData(int row, + int column, const QVariant& data, int subRow, int subColumn) + { + getAdapter(getColumn(column))->setNestedData(getRecord(row), data, subRow, subColumn); + } + + template + CSMWorld::NestedTableWrapperBase* SubCellCollection::nestedTable(int row, + int column) const + { + return getAdapter(getColumn(column))->nestedTable(getRecord(row)); + } + + template + void SubCellCollection::setNestedTable(int row, + int column, const CSMWorld::NestedTableWrapperBase& nestedTable) + { + getAdapter(getColumn(column))->setNestedTable(getRecord(row), nestedTable); + } + + template + int SubCellCollection::getNestedRowsCount(int row, int column) const + { + return getAdapter(getColumn(column))->getNestedRowsCount(getRecord(row)); + } + + template + int SubCellCollection::getNestedColumnsCount(int row, int column) const + { + return getAdapter(getColumn(column))->getNestedColumnsCount(getRecord(row)); + } + + template + CSMWorld::NestableColumn *SubCellCollection::getNestableColumn(int column) + { + return Collection::getNestableColumn(column); + } } #endif From 860754e460523abad2a865d99b0e8ab68ada65cb Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 9 Apr 2015 19:33:42 +1000 Subject: [PATCH 684/740] Minor formatting cleanup and comments. --- apps/opencs/model/world/nestedadapters.hpp | 123 ------------------ .../model/world/nestedtableproxymodel.cpp | 2 +- .../model/world/nestedtableproxymodel.hpp | 6 +- apps/opencs/model/world/refidadapter.hpp | 5 +- apps/opencs/model/world/refidadapterimp.cpp | 13 +- apps/opencs/model/world/refidadapterimp.hpp | 4 +- 6 files changed, 15 insertions(+), 138 deletions(-) diff --git a/apps/opencs/model/world/nestedadapters.hpp b/apps/opencs/model/world/nestedadapters.hpp index ac2a650d4..a2cbea1a6 100644 --- a/apps/opencs/model/world/nestedadapters.hpp +++ b/apps/opencs/model/world/nestedadapters.hpp @@ -177,129 +177,6 @@ namespace CSMWorld }; - /* - template - class MagicEffectsHelper : public CastableHelper - { - public: - - MagicEffectsHelper(CSMWorld::UniversalId::Type type) - : CastableHelper(type) {} - - virtual void setNestedTable(RefIdData& data, - int index, - const NestedTableWrapperBase& nestedTable) - { - CastableHelper::getRecord(data, index).get().mEffects = - (static_cast&>(nestedTable)).mNestedTable; - } - - virtual NestedTableWrapperBase* nestedTable(const RefIdData& data, - int index) const - { - return new NestedTableWrapper(CastableHelper::getRecord(data, index).get().mEffects); - } - - virtual QVariant getNestedData(const CSMWorld::RefIdData& data, - int index, - int subRowIndex, - int subColIndex) const - { - const ESM::EffectList& content = CastableHelper::getRecord(data, index).get().mEffects; - - switch (subColIndex) - { - case 0: - return content.at(subRowIndex).mEffectID; - - case 1: - return content.at(subRowIndex).mRange; - - case 2: - return content.at(subRowIndex).mDuration; - - case 3: - return content.at(subRowIndex).mArea; - - case 4: - return content.at(subRowIndex).mMagMin; - - case 5: - return content.at(subRowIndex).mMagMax; - - case 6: - return (int)content.at(rubRowIndex).mSkill; - - case 7: - return (int)content.at(subRowIndex).mAttribute; - - default: - throw std::logic_error("Trying to access non-existing column in the nested table!"); - } - } - - virtual void removeNestedRow (RefIdData& data, int index, int rowToRemove) const - { - ESM::EffectList& list = CastableHelper::getRecord(data, index).get().mEffects; - - list.erase (list.begin () + rowToRemove); - } - - void setNestedData (RefIdData& data, - int index, - const QVariant& value, - int subRowIndex, - int subColIndex) const - { - switch(subColIndex) - { - case 0: - CastableHelper::getRecord(data, index).get().mEffects.at(subRowIndex).mEffectID = value.toInt(); - break; - - default: - throw std::logic_error("Trying to access non-existing column in the nested table!"); - } - } - - virtual void addNestedRow (RefIdData& data, int index, int position) const - { - std::vector& list = CastableHelper::getRecord(data, index).get().mTransport.mList; - - ESM::Position newPos; - for (unsigned i = 0; i < 3; ++i) - { - newPos.pos[i] = 0; - newPos.rot[i] = 0; - } - - ESM::Transport::Dest newRow; - newRow.mPos = newPos; - newRow.mCellName = ""; - - if (position >= (int)list.size()) - { - list.push_back(newRow); - return; - } - - list.insert(list.begin()+position, newRow); - } - - virtual int getNestedColumnsCount(const RefIdData& data) const - { - return 7; - } - - - virtual int getNestedRowsCount(const RefIdData& data, - int index) const - { - return CastableHelper::getRecord(data, index).get().mTransport.mList.size(); - } - - }; - */ template class DestinationsHelper : public CastableHelper { diff --git a/apps/opencs/model/world/nestedtableproxymodel.cpp b/apps/opencs/model/world/nestedtableproxymodel.cpp index fede8383b..182ed11ab 100644 --- a/apps/opencs/model/world/nestedtableproxymodel.cpp +++ b/apps/opencs/model/world/nestedtableproxymodel.cpp @@ -99,7 +99,7 @@ QVariant CSMWorld::NestedTableProxyModel::headerData(int section, } -bool CSMWorld::NestedTableProxyModel::setData ( const QModelIndex & index, const QVariant & value, int role) +bool CSMWorld::NestedTableProxyModel::setData (const QModelIndex & index, const QVariant & value, int role) { return mMainModel->setData(mapToSource(index), value, role); } diff --git a/apps/opencs/model/world/nestedtableproxymodel.hpp b/apps/opencs/model/world/nestedtableproxymodel.hpp index 7dc66989c..177a25d28 100644 --- a/apps/opencs/model/world/nestedtableproxymodel.hpp +++ b/apps/opencs/model/world/nestedtableproxymodel.hpp @@ -27,7 +27,7 @@ namespace CSMWorld IdTree* mMainModel; std::string mId; - public: + public: NestedTableProxyModel(const QModelIndex& parent, ColumnBase::Display displayType, IdTree* parentModel); @@ -51,9 +51,9 @@ namespace CSMWorld virtual QModelIndex parent(const QModelIndex& index) const; - virtual QVariant headerData ( int section, Qt::Orientation orientation, int role ) const; + virtual QVariant headerData (int section, Qt::Orientation orientation, int role) const; - virtual bool setData ( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole ); + virtual bool setData (const QModelIndex & index, const QVariant & value, int role = Qt::EditRole); virtual Qt::ItemFlags flags(const QModelIndex& index) const; diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index af7469637..7f7d00413 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -9,6 +9,7 @@ /*! \brief * Adapters acts as indirection layer, abstracting details of the record types (in the wrappers) from the higher levels of model. * Please notice that nested adaptor uses helper classes for actually performing any actions. Different record types require different helpers (needs to be created in the subclass and then fetched via member function). + * * Important point: don't forget to make sure that getData on the nestedColumn returns true (otherwise code will not treat the index pointing to the column as having childs! */ @@ -44,7 +45,7 @@ namespace CSMWorld virtual std::string getId (const RecordBase& record) const = 0; - virtual void setId(RecordBase& record, const std::string& id) = 0; + virtual void setId(RecordBase& record, const std::string& id) = 0; // FIXME: used by RefIdCollection::cloneRecord() }; class NestedRefIdAdapterBase @@ -75,7 +76,7 @@ namespace CSMWorld class NestedRefIdAdapter : public NestedRefIdAdapterBase { - std::vector > mAssociatedColumns; //basicly, i wanted map, but with pointer key + std::vector > mAssociatedColumns; //basically, i wanted a map, but with pointer key public: NestedRefIdAdapter(); diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 99117cc7f..b2a08e71c 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -186,11 +186,11 @@ CSMWorld::ContainerRefIdAdapter::ContainerRefIdAdapter (const NameColumns& colum std::vector > assoCol; assoCol.push_back(std::make_pair(content, new InventoryHelper(UniversalId::Type_Container))); - + setAssocColumns(assoCol); } -QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, +QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, int index) const { @@ -207,12 +207,11 @@ QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, return (record.get().mFlags & ESM::Container::Respawn)!=0; if (column==mContent) - return true; + return true; // required by IdTree::hasChildren() return NameRefIdAdapter::getData (column, data, index); } - void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index, const QVariant& value) const { @@ -490,16 +489,16 @@ QVariant CSMWorld::NpcRefIdAdapter::getData (const RefIdColumn *column, const Re if (column==mColumns.mHead) return QString::fromUtf8 (record.get().mHead.c_str()); - + if (column==mColumns.mDestinations) - return true; + return true; // required by IdTree::hasChildren() std::map::const_iterator iter = mColumns.mFlags.find (column); if (iter!=mColumns.mFlags.end()) return (record.get().mFlags & iter->second)!=0; - + return ActorRefIdAdapter::getData (column, data, index); } diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index acc6c40c1..f72c0d196 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -536,10 +536,10 @@ namespace CSMWorld return record.get().mAiData.mAlarm; if (column==mActors.mInventory) - return true; + return true; // required by IdTree::hasChildren() if (column==mActors.mSpells) - return true; + return true; // required by IdTree::hasChildren() std::map::const_iterator iter = mActors.mServices.find (column); From 787cef1386d52abe04b28fafa35882de67054027 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 9 Apr 2015 19:39:09 +1000 Subject: [PATCH 685/740] DialogueSubView layout update for dialogues with nested tables only. --- apps/opencs/view/world/dialoguesubview.cpp | 36 ++++++++++++++++------ 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index d0b53a206..79eb48534 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -293,7 +293,6 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: connect(proxy, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), this, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); - //skip = true; } else if (qobject_cast(editor)) { @@ -382,18 +381,27 @@ void CSVWorld::EditWidget::remake(int row) mWidgetMapper->setModel(mTable); mWidgetMapper->setItemDelegate(&mDispatcher); + QFrame* line = new QFrame(mMainWidget); + line->setObjectName(QString::fromUtf8("line")); + line->setGeometry(QRect(320, 150, 118, 3)); + line->setFrameShape(QFrame::HLine); + line->setFrameShadow(QFrame::Sunken); QVBoxLayout *mainLayout = new QVBoxLayout(mMainWidget); + QGridLayout *lockedLayout = new QGridLayout(); QScrollArea *scroll = new QScrollArea(mMainWidget); QWidget *unlockedWidget = new QWidget(scroll); - QGridLayout *unlockedLayout = new QGridLayout(unlockedWidget); - QGridLayout *lockedLayout = new QGridLayout(); + QVBoxLayout *overLayout = new QVBoxLayout(unlockedWidget); + QGridLayout *unlockedLayout = new QGridLayout(); QVBoxLayout *tablesLayout = new QVBoxLayout(); - mainLayout->addLayout(lockedLayout, 0); + mainLayout->addLayout(lockedLayout, QSizePolicy::Fixed); mainLayout->addSpacing(5); // FIXME: arbitrary number - mainLayout->addWidget(scroll, 2); + mainLayout->addWidget(line, 1); + mainLayout->addWidget(scroll, QSizePolicy::Preferred); + overLayout->addLayout(unlockedLayout, QSizePolicy::Preferred); + overLayout->addStretch(1); mainLayout->addSpacing(5); // FIXME: arbitrary number - mainLayout->addLayout(tablesLayout, 0); + mainLayout->addLayout(tablesLayout, QSizePolicy::Preferred); mainLayout->addStretch(1); int unlocked = 0; @@ -457,9 +465,19 @@ void CSVWorld::EditWidget::remake(int row) mWidgetMapper->setCurrentModelIndex(mTable->index(row, 0)); - scroll->setWidget(unlockedWidget); - scroll->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Fixed); - scroll->setWidgetResizable(true); + if (unlocked != 0) + { + mainLayout->removeWidget(line); + scroll->setWidget(unlockedWidget); + scroll->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Minimum); + scroll->setWidgetResizable(true); + } + else + { + delete unlockedWidget; + delete scroll; + } + this->setWidget(mMainWidget); this->setWidgetResizable(true); } From 3a46512b7f22b52bc8e276b86c6f8102ae48c1cc Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 9 Apr 2015 20:15:38 +1000 Subject: [PATCH 686/740] Attempt to account for gcc differences. --- apps/opencs/model/world/data.hpp | 2 ++ apps/opencs/model/world/idadapterimp.hpp | 16 +++++++------- apps/opencs/model/world/subcellcollection.hpp | 22 +++++++++---------- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 298a9be1f..b9e060002 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -42,7 +42,9 @@ #include "refcollection.hpp" #include "infocollection.hpp" #include "pathgrid.hpp" +#ifndef Q_MOC_RUN #include "subcellcollection.hpp" +#endif class QAbstractItemModel; diff --git a/apps/opencs/model/world/idadapterimp.hpp b/apps/opencs/model/world/idadapterimp.hpp index fa7c55bd3..025c2e137 100644 --- a/apps/opencs/model/world/idadapterimp.hpp +++ b/apps/opencs/model/world/idadapterimp.hpp @@ -21,7 +21,7 @@ namespace CSMWorld { ESXRecordT pathgrid = record.get(); - ESXRecordT::PointList& points = pathgrid.mPoints; + ESM::Pathgrid::PointList& points = pathgrid.mPoints; // blank row ESM::Pathgrid::Point point; @@ -43,7 +43,7 @@ namespace CSMWorld { ESXRecordT pathgrid = record.get(); - ESXRecordT::PointList& points = pathgrid.mPoints; + ESM::Pathgrid::PointList& points = pathgrid.mPoints; if (rowToRemove < 0 || rowToRemove >= static_cast (points.size())) throw std::runtime_error ("index out of range"); @@ -58,13 +58,13 @@ namespace CSMWorld virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) { record.get().mPoints = - static_cast &>(nestedTable).mNestedTable; + static_cast &>(nestedTable).mNestedTable; } virtual NestedTableWrapperBase* nestedTable(const Record& record) const { // deleted by dtor of NestedTableStoring - return new NestedTableWrapper(record.get().mPoints); + return new NestedTableWrapper(record.get().mPoints); } virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const @@ -119,7 +119,7 @@ namespace CSMWorld { ESXRecordT pathgrid = record.get(); - ESXRecordT::EdgeList& edges = pathgrid.mEdges; + ESM::Pathgrid::EdgeList& edges = pathgrid.mEdges; // blank row ESM::Pathgrid::Edge edge; @@ -137,7 +137,7 @@ namespace CSMWorld { ESXRecordT pathgrid = record.get(); - ESXRecordT::EdgeList& edges = pathgrid.mEdges; + ESM::Pathgrid::EdgeList& edges = pathgrid.mEdges; if (rowToRemove < 0 || rowToRemove >= static_cast (edges.size())) throw std::runtime_error ("index out of range"); @@ -150,13 +150,13 @@ namespace CSMWorld virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) { record.get().mEdges = - static_cast &>(nestedTable).mNestedTable; + static_cast &>(nestedTable).mNestedTable; } virtual NestedTableWrapperBase* nestedTable(const Record& record) const { // deleted by dtor of NestedTableStoring - return new NestedTableWrapper(record.get().mEdges); + return new NestedTableWrapper(record.get().mEdges); } virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const diff --git a/apps/opencs/model/world/subcellcollection.hpp b/apps/opencs/model/world/subcellcollection.hpp index f2aeb5aaf..919a0a604 100644 --- a/apps/opencs/model/world/subcellcollection.hpp +++ b/apps/opencs/model/world/subcellcollection.hpp @@ -76,7 +76,7 @@ namespace CSMWorld template SubCellCollection::~SubCellCollection() { - for (std::map* >::iterator iter (mAdapters.begin()); + for (typename std::map* >::iterator iter (mAdapters.begin()); iter!=mAdapters.end(); ++iter) delete (*iter).second; } @@ -90,7 +90,7 @@ namespace CSMWorld template NestedIdAdapter* SubCellCollection::getAdapter(const ColumnBase &column) const { - std::map* >::const_iterator iter = + typename std::map* >::const_iterator iter = mAdapters.find (&column); if (iter==mAdapters.end()) @@ -102,59 +102,59 @@ namespace CSMWorld template void SubCellCollection::addNestedRow(int row, int column, int position) { - getAdapter(getColumn(column))->addNestedRow(getRecord(row), position); + getAdapter(Collection::getColumn(column))->addNestedRow(getRecord(row), position); } template void SubCellCollection::removeNestedRows(int row, int column, int subRow) { - getAdapter(getColumn(column))->removeNestedRow(getRecord(row), subRow); + getAdapter(Collection::getColumn(column))->removeNestedRow(getRecord(row), subRow); } template QVariant SubCellCollection::getNestedData (int row, int column, int subRow, int subColumn) const { - return getAdapter(getColumn(column))->getNestedData(getRecord(row), subRow, subColumn); + return getAdapter(Collection::getColumn(column))->getNestedData(getRecord(row), subRow, subColumn); } template void SubCellCollection::setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn) { - getAdapter(getColumn(column))->setNestedData(getRecord(row), data, subRow, subColumn); + getAdapter(Collection::getColumn(column))->setNestedData(getRecord(row), data, subRow, subColumn); } template CSMWorld::NestedTableWrapperBase* SubCellCollection::nestedTable(int row, int column) const { - return getAdapter(getColumn(column))->nestedTable(getRecord(row)); + return getAdapter(Collection::getColumn(column))->nestedTable(getRecord(row)); } template void SubCellCollection::setNestedTable(int row, int column, const CSMWorld::NestedTableWrapperBase& nestedTable) { - getAdapter(getColumn(column))->setNestedTable(getRecord(row), nestedTable); + getAdapter(Collection::getColumn(column))->setNestedTable(getRecord(row), nestedTable); } template int SubCellCollection::getNestedRowsCount(int row, int column) const { - return getAdapter(getColumn(column))->getNestedRowsCount(getRecord(row)); + return getAdapter(Collection::getColumn(column))->getNestedRowsCount(getRecord(row)); } template int SubCellCollection::getNestedColumnsCount(int row, int column) const { - return getAdapter(getColumn(column))->getNestedColumnsCount(getRecord(row)); + return getAdapter(Collection::getColumn(column))->getNestedColumnsCount(getRecord(row)); } template CSMWorld::NestableColumn *SubCellCollection::getNestableColumn(int column) { - return Collection::getNestableColumn(column); + return Collection::getNestableColumn(column); } } From 23db79ebab328298a8a39783299c3ca7e01a0dc7 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 9 Apr 2015 20:53:41 +1000 Subject: [PATCH 687/740] Fix for more gcc differences. --- apps/opencs/model/world/commands.hpp | 2 +- apps/opencs/model/world/idadapter.hpp | 2 +- apps/opencs/model/world/idtree.hpp | 2 +- apps/opencs/model/world/nestedcollection.hpp | 2 +- apps/opencs/model/world/refidadapter.hpp | 2 +- apps/opencs/model/world/refidadapterimp.hpp | 2 +- apps/opencs/model/world/refidcollection.hpp | 2 +- apps/opencs/model/world/subcellcollection.hpp | 24 ++++++++++++------- 8 files changed, 23 insertions(+), 15 deletions(-) diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index 42405a2f9..a70b36178 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -22,7 +22,7 @@ namespace CSMWorld class IdTable; class IdTree; struct RecordBase; - class NestedTableWrapperBase; + struct NestedTableWrapperBase; class ModifyCommand : public QUndoCommand { diff --git a/apps/opencs/model/world/idadapter.hpp b/apps/opencs/model/world/idadapter.hpp index bec21a0f3..753ac01f0 100644 --- a/apps/opencs/model/world/idadapter.hpp +++ b/apps/opencs/model/world/idadapter.hpp @@ -7,7 +7,7 @@ class QVariant; namespace CSMWorld { - class NestedTableWrapperBase; + struct NestedTableWrapperBase; template class NestedIdAdapter diff --git a/apps/opencs/model/world/idtree.hpp b/apps/opencs/model/world/idtree.hpp index 80b44d241..d06d86a4f 100644 --- a/apps/opencs/model/world/idtree.hpp +++ b/apps/opencs/model/world/idtree.hpp @@ -20,7 +20,7 @@ namespace CSMWorld { class NestedCollection; struct RecordBase; - class NestedTableWrapperBase; // FIXME: is this necessary? + struct NestedTableWrapperBase; class IdTree : public IdTable { diff --git a/apps/opencs/model/world/nestedcollection.hpp b/apps/opencs/model/world/nestedcollection.hpp index 8046f9a09..b075f53c4 100644 --- a/apps/opencs/model/world/nestedcollection.hpp +++ b/apps/opencs/model/world/nestedcollection.hpp @@ -6,7 +6,7 @@ class QVariant; namespace CSMWorld { class NestableColumn; - class NestedTableWrapperBase; + struct NestedTableWrapperBase; class NestedCollection { diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index 7f7d00413..91f19577b 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -20,7 +20,7 @@ namespace CSMWorld class RefIdColumn; class RefIdData; struct RecordBase; - class NestedTableWrapperBase; + struct NestedTableWrapperBase; class HelperBase; class RefIdAdapter diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index f72c0d196..7296b6c68 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -16,7 +16,7 @@ namespace CSMWorld { - class NestedTableWrapperBase; + struct NestedTableWrapperBase; struct BaseColumns { diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index 2a271a846..5bf7c177e 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -18,7 +18,7 @@ namespace ESM namespace CSMWorld { class RefIdAdapter; - class NestedTableWrapperBase; + struct NestedTableWrapperBase; class RefIdColumn : public NestableColumn { diff --git a/apps/opencs/model/world/subcellcollection.hpp b/apps/opencs/model/world/subcellcollection.hpp index 919a0a604..92091cf57 100644 --- a/apps/opencs/model/world/subcellcollection.hpp +++ b/apps/opencs/model/world/subcellcollection.hpp @@ -102,53 +102,61 @@ namespace CSMWorld template void SubCellCollection::addNestedRow(int row, int column, int position) { - getAdapter(Collection::getColumn(column))->addNestedRow(getRecord(row), position); + getAdapter(Collection::getColumn(column))->addNestedRow( + Collection::getRecord(row), position); } template void SubCellCollection::removeNestedRows(int row, int column, int subRow) { - getAdapter(Collection::getColumn(column))->removeNestedRow(getRecord(row), subRow); + getAdapter(Collection::getColumn(column))->removeNestedRow( + Collection::getRecord(row), subRow); } template QVariant SubCellCollection::getNestedData (int row, int column, int subRow, int subColumn) const { - return getAdapter(Collection::getColumn(column))->getNestedData(getRecord(row), subRow, subColumn); + return getAdapter(Collection::getColumn(column))->getNestedData( + Collection::getRecord(row), subRow, subColumn); } template void SubCellCollection::setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn) { - getAdapter(Collection::getColumn(column))->setNestedData(getRecord(row), data, subRow, subColumn); + getAdapter(Collection::getColumn(column))->setNestedData( + Collection::getRecord(row), data, subRow, subColumn); } template CSMWorld::NestedTableWrapperBase* SubCellCollection::nestedTable(int row, int column) const { - return getAdapter(Collection::getColumn(column))->nestedTable(getRecord(row)); + return getAdapter(Collection::getColumn(column))->nestedTable( + Collection::getRecord(row)); } template void SubCellCollection::setNestedTable(int row, int column, const CSMWorld::NestedTableWrapperBase& nestedTable) { - getAdapter(Collection::getColumn(column))->setNestedTable(getRecord(row), nestedTable); + getAdapter(Collection::getColumn(column))->setNestedTable( + Collection::getRecord(row), nestedTable); } template int SubCellCollection::getNestedRowsCount(int row, int column) const { - return getAdapter(Collection::getColumn(column))->getNestedRowsCount(getRecord(row)); + return getAdapter(Collection::getColumn(column))->getNestedRowsCount( + Collection::getRecord(row)); } template int SubCellCollection::getNestedColumnsCount(int row, int column) const { - return getAdapter(Collection::getColumn(column))->getNestedColumnsCount(getRecord(row)); + return getAdapter(Collection::getColumn(column))->getNestedColumnsCount( + Collection::getRecord(row)); } template From be9f94b7663940010a4ff1bc8748aab4ac3b57a2 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 9 Apr 2015 21:23:02 +1000 Subject: [PATCH 688/740] Adjust edge indexes when adding/removing points. Fix some travis warnings. --- apps/opencs/model/world/idadapterimp.hpp | 29 +++++++++++++++++-- apps/opencs/model/world/nestedadapters.hpp | 2 +- .../model/world/nestedtableproxymodel.hpp | 2 +- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/apps/opencs/model/world/idadapterimp.hpp b/apps/opencs/model/world/idadapterimp.hpp index 025c2e137..aed847909 100644 --- a/apps/opencs/model/world/idadapterimp.hpp +++ b/apps/opencs/model/world/idadapterimp.hpp @@ -9,7 +9,7 @@ namespace CSMWorld { - class NestedTableWrapperBase; + struct NestedTableWrapperBase; template class PathgridPointListAdapter : public NestedIdAdapter @@ -32,7 +32,16 @@ namespace CSMWorld point.mConnectionNum = 0; point.mUnknown = 0; - // FIXME: inserting a point should trigger re-indexing of the edges + // inserting a point should trigger re-indexing of the edges + std::vector::iterator iter = pathgrid.mEdges.begin(); + for (;iter != pathgrid.mEdges.end(); ++iter) + { + if ((*iter).mV0 > position) + (*iter).mV0++; + if ((*iter).mV1 > position) + (*iter).mV1++; + } + points.insert(points.begin()+position, point); pathgrid.mData.mS2 += 1; // increment the number of points @@ -48,7 +57,21 @@ namespace CSMWorld if (rowToRemove < 0 || rowToRemove >= static_cast (points.size())) throw std::runtime_error ("index out of range"); - // FIXME: deleting a point should trigger re-indexing of the edges + // deleting a point should trigger re-indexing of the edges + // dangling edges are not allowed and hence removed + std::vector::iterator iter = pathgrid.mEdges.begin(); + for (;iter != pathgrid.mEdges.end(); ++iter) + { + if (((*iter).mV0 == rowToRemove) || ((*iter).mV1 == rowToRemove)) + pathgrid.mEdges.erase(iter); + + if ((*iter).mV0 > rowToRemove) + (*iter).mV0--; + + if ((*iter).mV1 > rowToRemove) + (*iter).mV1--; + } + points.erase(points.begin()+rowToRemove); pathgrid.mData.mS2 -= 1; // decrement the number of points diff --git a/apps/opencs/model/world/nestedadapters.hpp b/apps/opencs/model/world/nestedadapters.hpp index a2cbea1a6..015765380 100644 --- a/apps/opencs/model/world/nestedadapters.hpp +++ b/apps/opencs/model/world/nestedadapters.hpp @@ -393,7 +393,7 @@ namespace CSMWorld { std::vector& list = CastableHelper::getRecord(data, index).get().mInventory.mList; - ESM::ContItem newRow = {0, ""}; + ESM::ContItem newRow = {0, {""}}; if (position >= (int)list.size()) { list.push_back(newRow); diff --git a/apps/opencs/model/world/nestedtableproxymodel.hpp b/apps/opencs/model/world/nestedtableproxymodel.hpp index 177a25d28..2ab04a584 100644 --- a/apps/opencs/model/world/nestedtableproxymodel.hpp +++ b/apps/opencs/model/world/nestedtableproxymodel.hpp @@ -16,7 +16,7 @@ namespace CSMWorld { class CollectionBase; - class RecordBase; + struct RecordBase; class IdTree; class NestedTableProxyModel : public QAbstractProxyModel From 330920daa8df5e8294f5e2982de94eb8d2835f36 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 9 Apr 2015 21:41:46 +1000 Subject: [PATCH 689/740] Fix off by one error(s). --- apps/opencs/model/world/idadapterimp.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/idadapterimp.hpp b/apps/opencs/model/world/idadapterimp.hpp index aed847909..510a14f12 100644 --- a/apps/opencs/model/world/idadapterimp.hpp +++ b/apps/opencs/model/world/idadapterimp.hpp @@ -36,9 +36,9 @@ namespace CSMWorld std::vector::iterator iter = pathgrid.mEdges.begin(); for (;iter != pathgrid.mEdges.end(); ++iter) { - if ((*iter).mV0 > position) + if ((*iter).mV0 >= position) (*iter).mV0++; - if ((*iter).mV1 > position) + if ((*iter).mV1 >= position) (*iter).mV1++; } @@ -65,10 +65,10 @@ namespace CSMWorld if (((*iter).mV0 == rowToRemove) || ((*iter).mV1 == rowToRemove)) pathgrid.mEdges.erase(iter); - if ((*iter).mV0 > rowToRemove) + if ((*iter).mV0 >= rowToRemove) (*iter).mV0--; - if ((*iter).mV1 > rowToRemove) + if ((*iter).mV1 >= rowToRemove) (*iter).mV1--; } From bc9dad3ff2a776b084c00065da7529ac170091b0 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 10 Apr 2015 07:31:01 +1000 Subject: [PATCH 690/740] Add index columns and fix edge indexing for point deletion. --- apps/opencs/model/world/columnimp.hpp | 44 ++++++++++++++++++ apps/opencs/model/world/columns.cpp | 6 ++- apps/opencs/model/world/columns.hpp | 14 +++--- apps/opencs/model/world/data.cpp | 3 ++ apps/opencs/model/world/idadapterimp.hpp | 57 +++++++++++++++--------- 5 files changed, 96 insertions(+), 28 deletions(-) diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 27fc3ad04..70c134e01 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -2289,6 +2289,28 @@ namespace CSMWorld } }; + template + struct PathgridIndexColumn : public Column + { + PathgridIndexColumn() + : Column (Columns::ColumnId_PathgridIndex, ColumnBase::Display_Integer) + {} + + virtual QVariant get (const Record& record) const + { + return QVariant(); // FIXME + } + + virtual void set (Record& record, const QVariant& data) + { + } + + virtual bool isEditable() const + { + return false; + } + }; + template struct PathgridPointColumn : public Column { @@ -2338,6 +2360,28 @@ namespace CSMWorld }; + template + struct PathgridEdgeIndexColumn : public Column + { + PathgridEdgeIndexColumn() + : Column (Columns::ColumnId_PathgridEdgeIndex, ColumnBase::Display_Integer) + {} + + virtual QVariant get (const Record& record) const + { + return QVariant(); // FIXME + } + + virtual void set (Record& record, const QVariant& data) + { + } + + virtual bool isEditable() const + { + return false; + } + }; + template struct PathgridEdgeColumn : public Column { diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index db0ebfd86..e6a27138f 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -224,12 +224,14 @@ namespace CSMWorld { ColumnId_BoltSound, "Bolt Sound" }, { ColumnId_PathgridPoints, "Points"}, + { ColumnId_PathgridIndex, "Index"}, { ColumnId_PathgridPosX, "X"}, { ColumnId_PathgridPosY, "Y"}, { ColumnId_PathgridPosZ, "Z"}, { ColumnId_PathgridEdges, "Edges"}, - { ColumnId_PathgridEdge0, "Edge 0"}, - { ColumnId_PathgridEdge1, "Edge 1"}, + { ColumnId_PathgridEdgeIndex, "Index"}, + { ColumnId_PathgridEdge0, "Point 0"}, + { ColumnId_PathgridEdge1, "Point 1"}, { 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 e36e29b3b..2cb7101b0 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -213,12 +213,14 @@ namespace CSMWorld ColumnId_BoltSound = 198, ColumnId_PathgridPoints = 199, - ColumnId_PathgridPosX = 200, - ColumnId_PathgridPosY = 201, - ColumnId_PathgridPosZ = 202, - ColumnId_PathgridEdges = 203, - ColumnId_PathgridEdge0 = 204, - ColumnId_PathgridEdge1 = 205, + ColumnId_PathgridIndex = 200, + ColumnId_PathgridPosX = 201, + ColumnId_PathgridPosY = 202, + ColumnId_PathgridPosZ = 203, + ColumnId_PathgridEdges = 204, + ColumnId_PathgridEdgeIndex = 205, + ColumnId_PathgridEdge0 = 206, + ColumnId_PathgridEdge1 = 207, // 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 ea94fe905..76e34961f 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -262,6 +262,8 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc // new object deleted in dtor of SubCellCollection mPathgrids.addAdapter (std::make_pair(pointList, new PathgridPointListAdapter ())); // new objects deleted in dtor of NestableColumn + // WARNING: The order of the columns below are assumed in PathgridPointListAdapter + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridIndexColumn ()); mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridPointColumn (0)); mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridPointColumn (1)); mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridPointColumn (2)); @@ -269,6 +271,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc PathgridEdgeListColumn *edgeList = new PathgridEdgeListColumn (); mPathgrids.addColumn (edgeList); mPathgrids.addAdapter (std::make_pair(edgeList, new PathgridEdgeListAdapter ())); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridEdgeIndexColumn ()); mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridEdgeColumn (0)); mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridEdgeColumn (1)); diff --git a/apps/opencs/model/world/idadapterimp.hpp b/apps/opencs/model/world/idadapterimp.hpp index 510a14f12..f5ed2e6e1 100644 --- a/apps/opencs/model/world/idadapterimp.hpp +++ b/apps/opencs/model/world/idadapterimp.hpp @@ -33,6 +33,9 @@ namespace CSMWorld point.mUnknown = 0; // inserting a point should trigger re-indexing of the edges + // + // FIXME: undo does not restore edges table view + // FIXME: does not auto refresh edges table view std::vector::iterator iter = pathgrid.mEdges.begin(); for (;iter != pathgrid.mEdges.end(); ++iter) { @@ -59,19 +62,25 @@ namespace CSMWorld // deleting a point should trigger re-indexing of the edges // dangling edges are not allowed and hence removed + // + // FIXME: undo does not restore edges table view + // FIXME: does not auto refresh edges table view std::vector::iterator iter = pathgrid.mEdges.begin(); - for (;iter != pathgrid.mEdges.end(); ++iter) + for (; iter != pathgrid.mEdges.end();) { if (((*iter).mV0 == rowToRemove) || ((*iter).mV1 == rowToRemove)) - pathgrid.mEdges.erase(iter); + iter = pathgrid.mEdges.erase(iter); + else + { + if ((*iter).mV0 > rowToRemove) + (*iter).mV0--; - if ((*iter).mV0 >= rowToRemove) - (*iter).mV0--; + if ((*iter).mV1 > rowToRemove) + (*iter).mV1--; - if ((*iter).mV1 >= rowToRemove) - (*iter).mV1--; + ++iter; + } } - points.erase(points.begin()+rowToRemove); pathgrid.mData.mS2 -= 1; // decrement the number of points @@ -95,9 +104,10 @@ namespace CSMWorld ESM::Pathgrid::Point point = record.get().mPoints[subRowIndex]; switch (subColIndex) { - case 0: return point.mX; - case 1: return point.mY; - case 2: return point.mZ; + case 0: return subRowIndex; + case 1: return point.mX; + case 2: return point.mY; + case 3: return point.mZ; default: throw std::logic_error("Pathgrid point subcolumn index out of range"); } } @@ -109,9 +119,10 @@ namespace CSMWorld ESM::Pathgrid::Point point = pathgrid.mPoints[subRowIndex]; switch (subColIndex) { - case 0: point.mX = value.toInt(); break; - case 1: point.mY = value.toInt(); break; - case 2: point.mZ = value.toInt(); break; + case 0: break; + case 1: point.mX = value.toInt(); break; + case 2: point.mY = value.toInt(); break; + case 3: point.mZ = value.toInt(); break; default: throw std::logic_error("Pathgrid point subcolumn index out of range"); } @@ -122,7 +133,7 @@ namespace CSMWorld virtual int getNestedColumnsCount(const Record& record) const { - return 3; + return 4; } virtual int getNestedRowsCount(const Record& record) const @@ -149,8 +160,11 @@ namespace CSMWorld edge.mV0 = 0; edge.mV1 = 0; - // FIXME: inserting a blank edge does not really make sense, perhaps this should be a + // NOTE: inserting a blank edge does not really make sense, perhaps this should be a // logic_error exception + // + // Currently the code assumes that the end user to know what he/she is doing. + // e.g. Edges come in pairs, from points a->b and b->a edges.insert(edges.begin()+position, edge); record.setModified (pathgrid); @@ -187,12 +201,14 @@ namespace CSMWorld ESM::Pathgrid::Edge edge = record.get().mEdges[subRowIndex]; switch (subColIndex) { - case 0: return edge.mV0; - case 1: return edge.mV1; + case 0: return subRowIndex; + case 1: return edge.mV0; + case 2: return edge.mV1; default: throw std::logic_error("Pathgrid edge subcolumn index out of range"); } } + // FIXME: detect duplicates in mEdges virtual void setNestedData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const { @@ -200,8 +216,9 @@ namespace CSMWorld ESM::Pathgrid::Edge edge = pathgrid.mEdges[subRowIndex]; switch (subColIndex) { - case 0: edge.mV0 = value.toInt(); break; - case 1: edge.mV1 = value.toInt(); break; + case 0: break; + case 1: edge.mV0 = value.toInt(); break; + case 2: edge.mV1 = value.toInt(); break; default: throw std::logic_error("Pathgrid edge subcolumn index out of range"); } @@ -212,7 +229,7 @@ namespace CSMWorld virtual int getNestedColumnsCount(const Record& record) const { - return 2; + return 3; } virtual int getNestedRowsCount(const Record& record) const From 9a564f50628f5c29ce8ea4913d4082c5b92823ec Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 10 Apr 2015 15:28:09 +1000 Subject: [PATCH 691/740] Fix undo for pathgrid points add/remove. --- apps/opencs/model/world/idadapterimp.hpp | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/idadapterimp.hpp b/apps/opencs/model/world/idadapterimp.hpp index f5ed2e6e1..746815414 100644 --- a/apps/opencs/model/world/idadapterimp.hpp +++ b/apps/opencs/model/world/idadapterimp.hpp @@ -87,16 +87,36 @@ namespace CSMWorld record.setModified (pathgrid); } + struct PathgridPointsWrap : public NestedTableWrapperBase + { + ESM::Pathgrid mRecord; + + PathgridPointsWrap(ESM::Pathgrid pathgrid) + : mRecord(pathgrid) {} + + virtual ~PathgridPointsWrap() {} + + virtual int size() const + { + return mRecord.mPoints.size(); // used in IdTree::setNestedTable() + } + }; + virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) { record.get().mPoints = - static_cast &>(nestedTable).mNestedTable; + static_cast(nestedTable).mRecord.mPoints; + record.get().mData.mS2 = + static_cast(nestedTable).mRecord.mData.mS2; + // also update edges in case points were added/removed + record.get().mEdges = + static_cast(nestedTable).mRecord.mEdges; } virtual NestedTableWrapperBase* nestedTable(const Record& record) const { // deleted by dtor of NestedTableStoring - return new NestedTableWrapper(record.get().mPoints); + return new PathgridPointsWrap(record.get()); } virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const From 7990fab708c153545ffef6a5af3be49905b9d705 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 10 Apr 2015 18:09:33 +1000 Subject: [PATCH 692/740] Fix crash when exiting via window manager on some systems. --- apps/opencs/model/world/idtree.cpp | 3 +-- apps/opencs/model/world/idtree.hpp | 1 - apps/opencs/view/doc/view.cpp | 4 ++++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp index 4befd1eee..952c9e329 100644 --- a/apps/opencs/model/world/idtree.cpp +++ b/apps/opencs/model/world/idtree.cpp @@ -54,8 +54,7 @@ QVariant CSMWorld::IdTree::data (const QModelIndex & index, int role) const QVariant CSMWorld::IdTree::nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role) const { - // FIXME: workaround only, a proper fix should stop QHideEvent calls after destruction - if (section < 0 || !idCollection() || section >= idCollection()->getColumns()) + if (section < 0 || section >= idCollection()->getColumns()) return QVariant(); const NestableColumn *parentColumn = mNestedCollection->getNestableColumn(section); diff --git a/apps/opencs/model/world/idtree.hpp b/apps/opencs/model/world/idtree.hpp index d06d86a4f..5f005c4d3 100644 --- a/apps/opencs/model/world/idtree.hpp +++ b/apps/opencs/model/world/idtree.hpp @@ -61,7 +61,6 @@ namespace CSMWorld virtual QModelIndex parent (const QModelIndex& index) const; - // TODO: check if below methods are really needed QVariant nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role = Qt::DisplayRole) const; NestedTableWrapperBase* nestedTable(const QModelIndex &index) const; diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index cf2940b99..f9fe613ef 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -32,6 +32,10 @@ void CSVDoc::View::closeEvent (QCloseEvent *event) event->ignore(); else { + // delete the subviews first + for (QList::iterator iter = mSubViews.begin(); iter != mSubViews.end(); ++iter) + delete *iter; + // closeRequest() returns true if last document mViewManager.removeDocAndView(mDocument); } From 3f4f008c5132689974b4085238311224eba34beb Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 10 Apr 2015 13:27:34 +0200 Subject: [PATCH 693/740] another fix to display type handling --- apps/opencs/model/world/columnbase.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 4f51fcad6..17e4def2f 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -75,6 +75,8 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_Texture, Display_Video, + Display_Id, + Display_None }; From 1220369da3abb6ed4f065908de6fa42df5df51e4 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 11 Apr 2015 11:26:29 +1000 Subject: [PATCH 694/740] Changes as per feedback comments. --- apps/opencs/model/world/collection.hpp | 12 +-- apps/opencs/model/world/columnbase.cpp | 7 +- apps/opencs/model/world/columnbase.hpp | 1 - apps/opencs/model/world/columnimp.hpp | 81 ++++--------------- apps/opencs/model/world/columns.cpp | 6 -- apps/opencs/model/world/commands.cpp | 8 +- apps/opencs/model/world/data.cpp | 14 ++-- apps/opencs/model/world/idadapter.hpp | 2 +- apps/opencs/model/world/idadapterimp.hpp | 4 +- apps/opencs/model/world/nestedadapters.hpp | 4 +- apps/opencs/model/world/refidadapter.cpp | 2 +- apps/opencs/model/world/refidadapter.hpp | 4 +- apps/opencs/model/world/refidcollection.cpp | 7 +- apps/opencs/model/world/refidcollection.hpp | 2 +- apps/opencs/model/world/subcellcollection.hpp | 48 +++++++---- 15 files changed, 77 insertions(+), 125 deletions(-) diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 4bc9632a8..b0571bbed 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -120,8 +120,6 @@ namespace CSMWorld virtual const Record& getRecord (int index) const; - virtual Record& getRecord (int index); - virtual int getAppendIndex (const std::string& id, UniversalId::Type type = UniversalId::Type_None) const; ///< \param type Will be ignored, unless the collection supports multiple record types @@ -151,7 +149,7 @@ namespace CSMWorld void setRecord (int index, const Record& record); ///< \attention This function must not change the ID. - NestableColumn *getNestableColumn (int column); + NestableColumn *getNestableColumn (int column) const; }; template @@ -294,7 +292,7 @@ namespace CSMWorld } template - NestableColumn *Collection::getNestableColumn (int column) + NestableColumn *Collection::getNestableColumn (int column) const { if (column < 0 || column >= static_cast(mColumns.size())) throw std::runtime_error("column index out of range"); @@ -435,12 +433,6 @@ namespace CSMWorld return mRecords.at (index); } - template - Record& Collection::getRecord (int index) - { - return mRecords.at (index); - } - template void Collection::insertRecord (const RecordBase& record, int index, UniversalId::Type type) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index e4d2195be..8d1985ff2 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -26,12 +26,11 @@ int CSMWorld::ColumnBase::getId() const void CSMWorld::NestableColumn::addColumn(CSMWorld::NestableColumn *column) { mNestedColumns.push_back(column); - mHasChildren = true; } const CSMWorld::ColumnBase& CSMWorld::NestableColumn::nestedColumn(int subColumn) const { - if (!mHasChildren) + if (mNestedColumns.empty()) throw std::logic_error("Tried to access nested column of the non-nest column"); return *mNestedColumns.at(subColumn); @@ -39,7 +38,7 @@ const CSMWorld::ColumnBase& CSMWorld::NestableColumn::nestedColumn(int subColumn CSMWorld::NestableColumn::NestableColumn(int columnId, CSMWorld::ColumnBase::Display displayType, int flag) - : mHasChildren(false), CSMWorld::ColumnBase(columnId, displayType, flag) + : CSMWorld::ColumnBase(columnId, displayType, flag) { } @@ -53,5 +52,5 @@ CSMWorld::NestableColumn::~NestableColumn() bool CSMWorld::NestableColumn::hasChildren() const { - return mHasChildren; + return !mNestedColumns.empty(); } diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index aef68fdbd..e6799cf56 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -137,7 +137,6 @@ namespace CSMWorld class NestableColumn : public ColumnBase { std::vector mNestedColumns; - bool mHasChildren; public: diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 70c134e01..3fb9a4685 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -2271,64 +2271,39 @@ namespace CSMWorld PathgridPointListColumn () : Column (Columns::ColumnId_PathgridPoints, ColumnBase::Display_PathgridPointList, ColumnBase::Flag_Dialogue) - { - } + {} virtual QVariant get (const Record& record) const { return true; // required by IdTree::hasChildren() } - virtual void set (Record& record, const QVariant& data) - { - } - virtual bool isEditable() const { return true; } }; - template - struct PathgridIndexColumn : public Column + struct PathgridIndexColumn : public NestableColumn { PathgridIndexColumn() - : Column (Columns::ColumnId_PathgridIndex, ColumnBase::Display_Integer) + : NestableColumn (Columns::ColumnId_PathgridIndex, + ColumnBase::Display_Integer, ColumnBase::Flag_Dialogue) {} - virtual QVariant get (const Record& record) const - { - return QVariant(); // FIXME - } - - virtual void set (Record& record, const QVariant& data) - { - } - virtual bool isEditable() const { return false; } }; - template - struct PathgridPointColumn : public Column + struct PathgridPointColumn : public NestableColumn { - int mIndex; // 0=PosX, 1=PosY, 2=PosZ - PathgridPointColumn(int index) - : Column (Columns::ColumnId_PathgridPosX+index, ColumnBase::Display_Integer), mIndex(index) + : NestableColumn (Columns::ColumnId_PathgridPosX+index, + ColumnBase::Display_Integer, ColumnBase::Flag_Dialogue) {} - virtual QVariant get (const Record& record) const - { - return QVariant(); // FIXME - } - - virtual void set (Record& record, const QVariant& data) - { - } - virtual bool isEditable() const { return true; @@ -2341,18 +2316,13 @@ namespace CSMWorld PathgridEdgeListColumn () : Column (Columns::ColumnId_PathgridEdges, ColumnBase::Display_PathgridEdgeList, ColumnBase::Flag_Dialogue) - { - } + {} virtual QVariant get (const Record& record) const { return true; // required by IdTree::hasChildren() } - virtual void set (Record& record, const QVariant& data) - { - } - virtual bool isEditable() const { return true; @@ -2360,46 +2330,25 @@ namespace CSMWorld }; - template - struct PathgridEdgeIndexColumn : public Column + struct PathgridEdgeIndexColumn : public NestableColumn { PathgridEdgeIndexColumn() - : Column (Columns::ColumnId_PathgridEdgeIndex, ColumnBase::Display_Integer) + : NestableColumn (Columns::ColumnId_PathgridEdgeIndex, + ColumnBase::Display_Integer, ColumnBase::Flag_Dialogue) {} - virtual QVariant get (const Record& record) const - { - return QVariant(); // FIXME - } - - virtual void set (Record& record, const QVariant& data) - { - } - virtual bool isEditable() const { return false; } }; - template - struct PathgridEdgeColumn : public Column + struct PathgridEdgeColumn : public NestableColumn { - int mIndex; - PathgridEdgeColumn (int index) - : Column (Columns::ColumnId_PathgridEdge0+index, ColumnBase::Display_Integer), mIndex(index) - { - } - - virtual QVariant get (const Record& record) const - { - return QVariant(); // FIXME - } - - virtual void set (Record& record, const QVariant& data) - { - } + : NestableColumn (Columns::ColumnId_PathgridEdge0+index, + ColumnBase::Display_Integer, ColumnBase::Flag_Dialogue) + {} virtual bool isEditable() const { diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index e6a27138f..b65cf7f96 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -287,11 +287,6 @@ int CSMWorld::Columns::getId (const std::string& name) namespace { - static const char *sSkills[] = - { - "Long Blade" - }; - static const char *sSpecialisations[] = { "Combat", "Magic", "Stealth", 0 @@ -394,7 +389,6 @@ namespace switch (column) { case CSMWorld::Columns::ColumnId_Specialisation: return sSpecialisations; - case CSMWorld::Columns::ColumnId_Skill: return sSkills; case CSMWorld::Columns::ColumnId_Attribute: return sAttributes; case CSMWorld::Columns::ColumnId_SpellType: return sSpellTypes; case CSMWorld::Columns::ColumnId_ApparatusType: return sApparatusTypes; diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 7acc6058e..d12c5d228 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -185,7 +185,9 @@ CSMWorld::DeleteNestedCommand::DeleteNestedCommand (IdTree& model, mNestedRow(nestedRow), NestedTableStoring(model, id, parentColumn) { - setText (("Delete nested row in " + mId).c_str()); + std::string title = + model.headerData(parentColumn, Qt::Horizontal, Qt::DisplayRole).toString().toUtf8().constData(); + setText (("Delete row in " + title + " sub-table of " + mId).c_str()); } void CSMWorld::DeleteNestedCommand::redo() @@ -211,7 +213,9 @@ CSMWorld::AddNestedCommand::AddNestedCommand(IdTree& model, const std::string& i QUndoCommand(parent), NestedTableStoring(model, id, parentColumn) { - setText (("Added nested row in " + mId).c_str()); + std::string title = + model.headerData(parentColumn, Qt::Horizontal, Qt::DisplayRole).toString().toUtf8().constData(); + setText (("Add row in " + title + " sub-table of " + mId).c_str()); } void CSMWorld::AddNestedCommand::redo() diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 76e34961f..87d5116f1 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -263,17 +263,17 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mPathgrids.addAdapter (std::make_pair(pointList, new PathgridPointListAdapter ())); // new objects deleted in dtor of NestableColumn // WARNING: The order of the columns below are assumed in PathgridPointListAdapter - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridIndexColumn ()); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridPointColumn (0)); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridPointColumn (1)); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridPointColumn (2)); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridIndexColumn ()); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridPointColumn (0)); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridPointColumn (1)); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridPointColumn (2)); PathgridEdgeListColumn *edgeList = new PathgridEdgeListColumn (); mPathgrids.addColumn (edgeList); mPathgrids.addAdapter (std::make_pair(edgeList, new PathgridEdgeListAdapter ())); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridEdgeIndexColumn ()); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridEdgeColumn (0)); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridEdgeColumn (1)); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridEdgeIndexColumn ()); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridEdgeColumn (0)); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridEdgeColumn (1)); mStartScripts.addColumn (new StringIdColumn); mStartScripts.addColumn (new RecordStateColumn); diff --git a/apps/opencs/model/world/idadapter.hpp b/apps/opencs/model/world/idadapter.hpp index 753ac01f0..84ef2d1f8 100644 --- a/apps/opencs/model/world/idadapter.hpp +++ b/apps/opencs/model/world/idadapter.hpp @@ -22,7 +22,7 @@ namespace CSMWorld virtual void removeNestedRow(Record& record, int rowToRemove) const = 0; - virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) = 0; + virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const = 0; virtual NestedTableWrapperBase* nestedTable(const Record& record) const = 0; diff --git a/apps/opencs/model/world/idadapterimp.hpp b/apps/opencs/model/world/idadapterimp.hpp index 746815414..2ce0777ac 100644 --- a/apps/opencs/model/world/idadapterimp.hpp +++ b/apps/opencs/model/world/idadapterimp.hpp @@ -102,7 +102,7 @@ namespace CSMWorld } }; - virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) + virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const { record.get().mPoints = static_cast(nestedTable).mRecord.mPoints; @@ -204,7 +204,7 @@ namespace CSMWorld record.setModified (pathgrid); } - virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) + virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const { record.get().mEdges = static_cast &>(nestedTable).mNestedTable; diff --git a/apps/opencs/model/world/nestedadapters.hpp b/apps/opencs/model/world/nestedadapters.hpp index 015765380..97046276f 100644 --- a/apps/opencs/model/world/nestedadapters.hpp +++ b/apps/opencs/model/world/nestedadapters.hpp @@ -145,8 +145,8 @@ namespace CSMWorld { CastableHelper::getRecord(data, index).get().mSpells.mList.at(subRowIndex) = std::string(value.toString().toUtf8()); } - - throw std::logic_error("Trying to access non-existing column in the nested table!"); + else + throw std::logic_error("Trying to access non-existing column in the nested table!"); } virtual void addNestedRow (RefIdData& data, int index, int position) const diff --git a/apps/opencs/model/world/refidadapter.cpp b/apps/opencs/model/world/refidadapter.cpp index 58b775f47..a12a95196 100644 --- a/apps/opencs/model/world/refidadapter.cpp +++ b/apps/opencs/model/world/refidadapter.cpp @@ -57,7 +57,7 @@ void CSMWorld::NestedRefIdAdapter::addNestedRow (const RefIdColumn *column, RefI getHelper(column)->addNestedRow(data, index, position); //This code grows more boring and boring. I would love some macros. } -void CSMWorld::NestedRefIdAdapter::setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) +void CSMWorld::NestedRefIdAdapter::setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const { getHelper(column)->setNestedTable(data, index, nestedTable); } diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index 91f19577b..1a3f2700e 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -69,7 +69,7 @@ namespace CSMWorld virtual void addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const = 0; - virtual void setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) = 0; + virtual void setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const = 0; virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, const RefIdData& data, int index) const = 0; }; @@ -97,7 +97,7 @@ namespace CSMWorld virtual void addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const; - virtual void setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable); + virtual void setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const; virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, const RefIdData& data, int index) const; diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 41ca7e440..b85deef4e 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -25,8 +25,7 @@ bool CSMWorld::RefIdColumn::isUserEditable() const return mUserEditable; } -// FIXME: const problem -/*const*/ CSMWorld::RefIdAdapter& CSMWorld::RefIdCollection::findAdapter (UniversalId::Type type) const +const CSMWorld::RefIdAdapter& CSMWorld::RefIdCollection::findAdapter (UniversalId::Type type) const { std::map::const_iterator iter = mAdapters.find (type); @@ -684,10 +683,8 @@ void CSMWorld::RefIdCollection::setNestedTable(int row, int column, const CSMWor { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); - // FIXME: const problem - CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); + const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); - // FIXME: const problem adaptor.setNestedTable(&mColumns.at(column), mData, localIndex.first, nestedTable); } diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index 5bf7c177e..3315212c1 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -46,7 +46,7 @@ namespace CSMWorld private: - /*const*/ RefIdAdapter& findAdapter (UniversalId::Type) const; + const RefIdAdapter& findAdapter (UniversalId::Type) const; ///< Throws an exception if no adaptor for \a Type can be found. public: diff --git a/apps/opencs/model/world/subcellcollection.hpp b/apps/opencs/model/world/subcellcollection.hpp index 92091cf57..c53c7006a 100644 --- a/apps/opencs/model/world/subcellcollection.hpp +++ b/apps/opencs/model/world/subcellcollection.hpp @@ -32,7 +32,7 @@ namespace CSMWorld virtual void loadRecord (ESXRecordT& record, ESM::ESMReader& reader); - NestedIdAdapter* getAdapter(const ColumnBase &column) const; + const NestedIdAdapter& getAdapter(const ColumnBase &column) const; public: @@ -88,7 +88,7 @@ namespace CSMWorld } template - NestedIdAdapter* SubCellCollection::getAdapter(const ColumnBase &column) const + const NestedIdAdapter& SubCellCollection::getAdapter(const ColumnBase &column) const { typename std::map* >::const_iterator iter = mAdapters.find (&column); @@ -96,28 +96,36 @@ namespace CSMWorld if (iter==mAdapters.end()) throw std::logic_error("No such column in the nestedidadapter"); - return iter->second; + return *iter->second; } template void SubCellCollection::addNestedRow(int row, int column, int position) { - getAdapter(Collection::getColumn(column))->addNestedRow( - Collection::getRecord(row), position); + Record record; + record.assign(Collection::getRecord(row)); + + getAdapter(Collection::getColumn(column)).addNestedRow(record, position); + + Collection::setRecord(row, record); } template void SubCellCollection::removeNestedRows(int row, int column, int subRow) { - getAdapter(Collection::getColumn(column))->removeNestedRow( - Collection::getRecord(row), subRow); + Record record; + record.assign(Collection::getRecord(row)); + + getAdapter(Collection::getColumn(column)).removeNestedRow(record, subRow); + + Collection::setRecord(row, record); } template QVariant SubCellCollection::getNestedData (int row, int column, int subRow, int subColumn) const { - return getAdapter(Collection::getColumn(column))->getNestedData( + return getAdapter(Collection::getColumn(column)).getNestedData( Collection::getRecord(row), subRow, subColumn); } @@ -125,15 +133,20 @@ namespace CSMWorld void SubCellCollection::setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn) { - getAdapter(Collection::getColumn(column))->setNestedData( - Collection::getRecord(row), data, subRow, subColumn); + Record record; + record.assign(Collection::getRecord(row)); + + getAdapter(Collection::getColumn(column)).setNestedData( + record, data, subRow, subColumn); + + Collection::setRecord(row, record); } template CSMWorld::NestedTableWrapperBase* SubCellCollection::nestedTable(int row, int column) const { - return getAdapter(Collection::getColumn(column))->nestedTable( + return getAdapter(Collection::getColumn(column)).nestedTable( Collection::getRecord(row)); } @@ -141,21 +154,26 @@ namespace CSMWorld void SubCellCollection::setNestedTable(int row, int column, const CSMWorld::NestedTableWrapperBase& nestedTable) { - getAdapter(Collection::getColumn(column))->setNestedTable( - Collection::getRecord(row), nestedTable); + Record record; + record.assign(Collection::getRecord(row)); + + getAdapter(Collection::getColumn(column)).setNestedTable( + record, nestedTable); + + Collection::setRecord(row, record); } template int SubCellCollection::getNestedRowsCount(int row, int column) const { - return getAdapter(Collection::getColumn(column))->getNestedRowsCount( + return getAdapter(Collection::getColumn(column)).getNestedRowsCount( Collection::getRecord(row)); } template int SubCellCollection::getNestedColumnsCount(int row, int column) const { - return getAdapter(Collection::getColumn(column))->getNestedColumnsCount( + return getAdapter(Collection::getColumn(column)).getNestedColumnsCount( Collection::getRecord(row)); } From a632b2cfebd8e71e223f74d06dc0cee1d9ff60d9 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 11 Apr 2015 11:27:48 +1000 Subject: [PATCH 695/740] Fix editing "ID" column within nested tables in dialogue subview. --- apps/opencs/model/world/idtree.cpp | 45 ++++++++++++------- apps/opencs/model/world/idtree.hpp | 6 ++- .../model/world/nestedtableproxymodel.cpp | 6 ++- .../model/world/nestedtableproxymodel.hpp | 2 + 4 files changed, 41 insertions(+), 18 deletions(-) diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp index 952c9e329..49ceced2c 100644 --- a/apps/opencs/model/world/idtree.cpp +++ b/apps/opencs/model/world/idtree.cpp @@ -38,18 +38,26 @@ QVariant CSMWorld::IdTree::data (const QModelIndex & index, int role) const if ((role!=Qt::DisplayRole && role!=Qt::EditRole) || index.row() < 0 || index.column() < 0) return QVariant(); - if (role==Qt::EditRole && !idCollection()->getColumn (index.column()).isEditable()) - return QVariant(); - if (index.internalId() != 0) { - std::pair parentAdress(unfoldIndexAdress(index.internalId())); + std::pair parentAddress(unfoldIndexAddress(index.internalId())); + + if (role == Qt::EditRole && + !mNestedCollection->getNestableColumn(parentAddress.second)->nestedColumn(index.column()).isEditable()) + { + return QVariant(); + } - return mNestedCollection->getNestedData(parentAdress.first, - parentAdress.second, index.row(), index.column()); + return mNestedCollection->getNestedData(parentAddress.first, + parentAddress.second, index.row(), index.column()); } else + { + if (role==Qt::EditRole && !idCollection()->getColumn (index.column()).isEditable()) + return QVariant(); + return idCollection()->getData (index.row(), index.column()); + } } QVariant CSMWorld::IdTree::nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role) const @@ -80,12 +88,12 @@ bool CSMWorld::IdTree::setData (const QModelIndex &index, const QVariant &value, { if (idCollection()->getColumn(parent(index).column()).isEditable() && role==Qt::EditRole) { - const std::pair& parentAdress(unfoldIndexAdress(index.internalId())); + const std::pair& parentAddress(unfoldIndexAddress(index.internalId())); - mNestedCollection->setNestedData(parentAdress.first, parentAdress.second, value, index.row(), index.column()); + mNestedCollection->setNestedData(parentAddress.first, parentAddress.second, value, index.row(), index.column()); - emit dataChanged (CSMWorld::IdTree::index (parentAdress.first, 0), - CSMWorld::IdTree::index (parentAdress.second, idCollection()->getColumns()-1)); + emit dataChanged (CSMWorld::IdTree::index (parentAddress.first, 0), + CSMWorld::IdTree::index (parentAddress.second, idCollection()->getColumns()-1)); return true; } @@ -145,7 +153,7 @@ QModelIndex CSMWorld::IdTree::index (int row, int column, const QModelIndex& par unsigned int encodedId = 0; if (parent.isValid()) { - encodedId = this->foldIndexAdress(parent); + encodedId = this->foldIndexAddress(parent); } if (row<0 || row>=idCollection()->getSize()) @@ -157,13 +165,18 @@ QModelIndex CSMWorld::IdTree::index (int row, int column, const QModelIndex& par return createIndex(row, column, encodedId); // store internal id } +QModelIndex CSMWorld::IdTree::getNestedModelIndex (const std::string& id, int column) const +{ + return CSMWorld::IdTable::index(idCollection()->getIndex (id), column); +} + QModelIndex CSMWorld::IdTree::parent (const QModelIndex& index) const { if (index.internalId() == 0) // 0 is used for indexs with invalid parent (top level data) return QModelIndex(); unsigned int id = index.internalId(); - const std::pair& adress(unfoldIndexAdress(id)); + const std::pair& adress(unfoldIndexAddress(id)); if (adress.first >= this->rowCount() || adress.second >= this->columnCount()) throw "Parent index is not present in the model"; @@ -171,14 +184,14 @@ QModelIndex CSMWorld::IdTree::parent (const QModelIndex& index) const return createIndex(adress.first, adress.second); } -unsigned int CSMWorld::IdTree::foldIndexAdress (const QModelIndex& index) const +unsigned int CSMWorld::IdTree::foldIndexAddress (const QModelIndex& index) const { unsigned int out = index.row() * this->columnCount(); out += index.column(); return ++out; } -std::pair< int, int > CSMWorld::IdTree::unfoldIndexAdress (unsigned int id) const +std::pair< int, int > CSMWorld::IdTree::unfoldIndexAddress (unsigned int id) const { if (id == 0) throw "Attempt to unfold index id of the top level data cell"; @@ -189,6 +202,8 @@ std::pair< int, int > CSMWorld::IdTree::unfoldIndexAdress (unsigned int id) cons return std::make_pair (row, column); } +// FIXME: Not sure why this check is also needed? +// // index.data().isValid() requires RefIdAdapter::getData() to return a valid QVariant for // nested columns (refidadapterimp.hpp) // @@ -198,7 +213,7 @@ bool CSMWorld::IdTree::hasChildren(const QModelIndex& index) const return (index.isValid() && index.internalId() == 0 && mNestedCollection->getNestableColumn(index.column())->hasChildren() && - index.data().isValid()); // FIXME: not sure why this check is also needed + index.data().isValid()); } void CSMWorld::IdTree::setNestedTable(const QModelIndex& index, const CSMWorld::NestedTableWrapperBase& nestedTable) diff --git a/apps/opencs/model/world/idtree.hpp b/apps/opencs/model/world/idtree.hpp index 5f005c4d3..5337ed82b 100644 --- a/apps/opencs/model/world/idtree.hpp +++ b/apps/opencs/model/world/idtree.hpp @@ -34,8 +34,8 @@ namespace CSMWorld IdTree (const IdTree&); IdTree& operator= (const IdTree&); - unsigned int foldIndexAdress(const QModelIndex& index) const; - std::pair unfoldIndexAdress(unsigned int id) const; + unsigned int foldIndexAddress(const QModelIndex& index) const; + std::pair unfoldIndexAddress(unsigned int id) const; public: @@ -61,6 +61,8 @@ namespace CSMWorld virtual QModelIndex parent (const QModelIndex& index) const; + QModelIndex getNestedModelIndex (const std::string& id, int column) const; + QVariant nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role = Qt::DisplayRole) const; NestedTableWrapperBase* nestedTable(const QModelIndex &index) const; diff --git a/apps/opencs/model/world/nestedtableproxymodel.cpp b/apps/opencs/model/world/nestedtableproxymodel.cpp index 182ed11ab..7b35c88e4 100644 --- a/apps/opencs/model/world/nestedtableproxymodel.cpp +++ b/apps/opencs/model/world/nestedtableproxymodel.cpp @@ -50,7 +50,7 @@ QModelIndex CSMWorld::NestedTableProxyModel::mapFromSource(const QModelIndex& so QModelIndex CSMWorld::NestedTableProxyModel::mapToSource(const QModelIndex& proxyIndex) const { - const QModelIndex& parent = mMainModel->getModelIndex (mId, mParentColumn); + const QModelIndex& parent = mMainModel->getNestedModelIndex (mId, mParentColumn); return mMainModel->index(proxyIndex.row(), proxyIndex.column(), parent); } @@ -98,6 +98,10 @@ QVariant CSMWorld::NestedTableProxyModel::headerData(int section, return mMainModel->nestedHeaderData(mParentColumn, section, orientation, role); } +QVariant CSMWorld::NestedTableProxyModel::data(const QModelIndex& index, int role) const +{ + return mMainModel->data(mapToSource(index), role); +} bool CSMWorld::NestedTableProxyModel::setData (const QModelIndex & index, const QVariant & value, int role) { diff --git a/apps/opencs/model/world/nestedtableproxymodel.hpp b/apps/opencs/model/world/nestedtableproxymodel.hpp index 2ab04a584..f5cbdb10b 100644 --- a/apps/opencs/model/world/nestedtableproxymodel.hpp +++ b/apps/opencs/model/world/nestedtableproxymodel.hpp @@ -53,6 +53,8 @@ namespace CSMWorld virtual QVariant headerData (int section, Qt::Orientation orientation, int role) const; + virtual QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const; + virtual bool setData (const QModelIndex & index, const QVariant & value, int role = Qt::EditRole); virtual Qt::ItemFlags flags(const QModelIndex& index) const; From ce7e2e06c15baaebad91a4be4472c75e24af0292 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 11 Apr 2015 13:11:20 +1000 Subject: [PATCH 696/740] Fix editor being created for a non-editable item. --- apps/opencs/model/world/idtree.cpp | 14 +++++++++++++- apps/opencs/model/world/nestedtableproxymodel.cpp | 2 +- apps/opencs/view/world/util.cpp | 2 +- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp index 49ceced2c..eddde5a89 100644 --- a/apps/opencs/model/world/idtree.cpp +++ b/apps/opencs/model/world/idtree.cpp @@ -108,7 +108,19 @@ Qt::ItemFlags CSMWorld::IdTree::flags (const QModelIndex & index) const if (!index.isValid()) return 0; - return IdTable::flags(index); + if (index.internalId() != 0) + { + std::pair parentAddress(unfoldIndexAddress(index.internalId())); + + Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; + + if (mNestedCollection->getNestableColumn(parentAddress.second)->nestedColumn(index.column()).isEditable()) + flags |= Qt::ItemIsEditable; + + return flags; + } + else + return IdTable::flags(index); } bool CSMWorld::IdTree::removeRows (int row, int count, const QModelIndex& parent) diff --git a/apps/opencs/model/world/nestedtableproxymodel.cpp b/apps/opencs/model/world/nestedtableproxymodel.cpp index 7b35c88e4..0f137d78f 100644 --- a/apps/opencs/model/world/nestedtableproxymodel.cpp +++ b/apps/opencs/model/world/nestedtableproxymodel.cpp @@ -110,7 +110,7 @@ bool CSMWorld::NestedTableProxyModel::setData (const QModelIndex & index, const Qt::ItemFlags CSMWorld::NestedTableProxyModel::flags(const QModelIndex& index) const { - return mMainModel->flags(mMainModel->index(0, mParentColumn)); + return mMainModel->flags(mapToSource(index)); } std::string CSMWorld::NestedTableProxyModel::getParentId() const diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index b0f8a035a..f3b23100a 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -120,7 +120,7 @@ void CSVWorld::CommandDelegate::setModelDataImp (QWidget *editor, QAbstractItemM QVariant new_ = hack.getData(); - if (model->data (index)!=new_) + if ((model->data (index)!=new_) && (model->flags(index) & Qt::ItemIsEditable)) getUndoStack().push (new CSMWorld::ModifyCommand (*model, index, new_)); } From 5da2f53bec3f6bc7910f7c12e6f46b09f358ceda Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 11 Apr 2015 13:54:05 +1000 Subject: [PATCH 697/740] Code reorganisation to prepare for nested sound table in regions. --- apps/opencs/model/world/idadapterimp.hpp | 3 +- .../opencs/model/world/nestedidcollection.hpp | 172 ++++++++++++++++++ apps/opencs/model/world/subcellcollection.hpp | 151 +-------------- 3 files changed, 177 insertions(+), 149 deletions(-) create mode 100644 apps/opencs/model/world/nestedidcollection.hpp diff --git a/apps/opencs/model/world/idadapterimp.hpp b/apps/opencs/model/world/idadapterimp.hpp index 2ce0777ac..7df653059 100644 --- a/apps/opencs/model/world/idadapterimp.hpp +++ b/apps/opencs/model/world/idadapterimp.hpp @@ -6,11 +6,10 @@ #include #include "idadapter.hpp" +#include "nestedtablewrapper.hpp" namespace CSMWorld { - struct NestedTableWrapperBase; - template class PathgridPointListAdapter : public NestedIdAdapter { diff --git a/apps/opencs/model/world/nestedidcollection.hpp b/apps/opencs/model/world/nestedidcollection.hpp new file mode 100644 index 000000000..c7e840955 --- /dev/null +++ b/apps/opencs/model/world/nestedidcollection.hpp @@ -0,0 +1,172 @@ +#ifndef CSM_WOLRD_NESTEDIDCOLLECTION_H +#define CSM_WOLRD_NESTEDIDCOLLECTION_H + +#include +#include + +#include "nestedcollection.hpp" +#include "idadapterimp.hpp" + +namespace ESM +{ + class ESMReader; +} + +namespace CSMWorld +{ + struct NestedTableWrapperBase; + struct Cell; + + template + class IdCollection; + + template > + class NestedIdCollection : public IdCollection, public NestedCollection + { + std::map* > mAdapters; + + const NestedIdAdapter& getAdapter(const ColumnBase &column) const; + + public: + + NestedIdCollection (); + ~NestedIdCollection(); + + virtual void addNestedRow(int row, int column, int position); + + virtual void removeNestedRows(int row, int column, int subRow); + + virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const; + + virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn); + + virtual NestedTableWrapperBase* nestedTable(int row, int column) const; + + virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable); + + virtual int getNestedRowsCount(int row, int column) const; + + virtual int getNestedColumnsCount(int row, int column) const; + + // this method is inherited from NestedCollection, not from Collection + virtual NestableColumn *getNestableColumn(int column); + + void addAdapter(std::pair* > adapter); + }; + + template + NestedIdCollection::NestedIdCollection () + {} + + template + NestedIdCollection::~NestedIdCollection() + { + for (typename std::map* >::iterator iter (mAdapters.begin()); + iter!=mAdapters.end(); ++iter) + delete (*iter).second; + } + + template + void NestedIdCollection::addAdapter(std::pair* > adapter) + { + mAdapters.insert(adapter); + } + + template + const NestedIdAdapter& NestedIdCollection::getAdapter(const ColumnBase &column) const + { + typename std::map* >::const_iterator iter = + mAdapters.find (&column); + + if (iter==mAdapters.end()) + throw std::logic_error("No such column in the nestedidadapter"); + + return *iter->second; + } + + template + void NestedIdCollection::addNestedRow(int row, int column, int position) + { + Record record; + record.assign(Collection::getRecord(row)); + + getAdapter(Collection::getColumn(column)).addNestedRow(record, position); + + Collection::setRecord(row, record); + } + + template + void NestedIdCollection::removeNestedRows(int row, int column, int subRow) + { + Record record; + record.assign(Collection::getRecord(row)); + + getAdapter(Collection::getColumn(column)).removeNestedRow(record, subRow); + + Collection::setRecord(row, record); + } + + template + QVariant NestedIdCollection::getNestedData (int row, + int column, int subRow, int subColumn) const + { + return getAdapter(Collection::getColumn(column)).getNestedData( + Collection::getRecord(row), subRow, subColumn); + } + + template + void NestedIdCollection::setNestedData(int row, + int column, const QVariant& data, int subRow, int subColumn) + { + Record record; + record.assign(Collection::getRecord(row)); + + getAdapter(Collection::getColumn(column)).setNestedData( + record, data, subRow, subColumn); + + Collection::setRecord(row, record); + } + + template + CSMWorld::NestedTableWrapperBase* NestedIdCollection::nestedTable(int row, + int column) const + { + return getAdapter(Collection::getColumn(column)).nestedTable( + Collection::getRecord(row)); + } + + template + void NestedIdCollection::setNestedTable(int row, + int column, const CSMWorld::NestedTableWrapperBase& nestedTable) + { + Record record; + record.assign(Collection::getRecord(row)); + + getAdapter(Collection::getColumn(column)).setNestedTable( + record, nestedTable); + + Collection::setRecord(row, record); + } + + template + int NestedIdCollection::getNestedRowsCount(int row, int column) const + { + return getAdapter(Collection::getColumn(column)).getNestedRowsCount( + Collection::getRecord(row)); + } + + template + int NestedIdCollection::getNestedColumnsCount(int row, int column) const + { + return getAdapter(Collection::getColumn(column)).getNestedColumnsCount( + Collection::getRecord(row)); + } + + template + CSMWorld::NestableColumn *NestedIdCollection::getNestableColumn(int column) + { + return Collection::getNestableColumn(column); + } +} + +#endif // CSM_WOLRD_NESTEDIDCOLLECTION_H diff --git a/apps/opencs/model/world/subcellcollection.hpp b/apps/opencs/model/world/subcellcollection.hpp index c53c7006a..df1f8a12e 100644 --- a/apps/opencs/model/world/subcellcollection.hpp +++ b/apps/opencs/model/world/subcellcollection.hpp @@ -1,16 +1,7 @@ #ifndef CSM_WOLRD_SUBCOLLECTION_H #define CSM_WOLRD_SUBCOLLECTION_H -#include -#include - -#include - -#include "columnimp.hpp" -#include "idcollection.hpp" -#include "nestedcollection.hpp" -#include "nestedtablewrapper.hpp" -#include "idadapterimp.hpp" +#include "nestedidcollection.hpp" namespace ESM { @@ -25,40 +16,15 @@ namespace CSMWorld /// \brief Single type collection of top level records that are associated with cells template > - class SubCellCollection : public IdCollection, public NestedCollection + class SubCellCollection : public NestedIdCollection { const IdCollection& mCells; - std::map* > mAdapters; virtual void loadRecord (ESXRecordT& record, ESM::ESMReader& reader); - const NestedIdAdapter& getAdapter(const ColumnBase &column) const; - public: SubCellCollection (const IdCollection& cells); - ~SubCellCollection(); - - virtual void addNestedRow(int row, int column, int position); - - virtual void removeNestedRows(int row, int column, int subRow); - - virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const; - - virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn); - - virtual NestedTableWrapperBase* nestedTable(int row, int column) const; - - virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable); - - virtual int getNestedRowsCount(int row, int column) const; - - virtual int getNestedColumnsCount(int row, int column) const; - - // this method is inherited from NestedCollection, not from Collection - virtual NestableColumn *getNestableColumn(int column); - - void addAdapter(std::pair* > adapter); }; template @@ -69,119 +35,10 @@ namespace CSMWorld } template - SubCellCollection::SubCellCollection (const IdCollection& cells) + SubCellCollection::SubCellCollection ( + const IdCollection& cells) : mCells (cells) {} - - template - SubCellCollection::~SubCellCollection() - { - for (typename std::map* >::iterator iter (mAdapters.begin()); - iter!=mAdapters.end(); ++iter) - delete (*iter).second; - } - - template - void SubCellCollection::addAdapter(std::pair* > adapter) - { - mAdapters.insert(adapter); - } - - template - const NestedIdAdapter& SubCellCollection::getAdapter(const ColumnBase &column) const - { - typename std::map* >::const_iterator iter = - mAdapters.find (&column); - - if (iter==mAdapters.end()) - throw std::logic_error("No such column in the nestedidadapter"); - - return *iter->second; - } - - template - void SubCellCollection::addNestedRow(int row, int column, int position) - { - Record record; - record.assign(Collection::getRecord(row)); - - getAdapter(Collection::getColumn(column)).addNestedRow(record, position); - - Collection::setRecord(row, record); - } - - template - void SubCellCollection::removeNestedRows(int row, int column, int subRow) - { - Record record; - record.assign(Collection::getRecord(row)); - - getAdapter(Collection::getColumn(column)).removeNestedRow(record, subRow); - - Collection::setRecord(row, record); - } - - template - QVariant SubCellCollection::getNestedData (int row, - int column, int subRow, int subColumn) const - { - return getAdapter(Collection::getColumn(column)).getNestedData( - Collection::getRecord(row), subRow, subColumn); - } - - template - void SubCellCollection::setNestedData(int row, - int column, const QVariant& data, int subRow, int subColumn) - { - Record record; - record.assign(Collection::getRecord(row)); - - getAdapter(Collection::getColumn(column)).setNestedData( - record, data, subRow, subColumn); - - Collection::setRecord(row, record); - } - - template - CSMWorld::NestedTableWrapperBase* SubCellCollection::nestedTable(int row, - int column) const - { - return getAdapter(Collection::getColumn(column)).nestedTable( - Collection::getRecord(row)); - } - - template - void SubCellCollection::setNestedTable(int row, - int column, const CSMWorld::NestedTableWrapperBase& nestedTable) - { - Record record; - record.assign(Collection::getRecord(row)); - - getAdapter(Collection::getColumn(column)).setNestedTable( - record, nestedTable); - - Collection::setRecord(row, record); - } - - template - int SubCellCollection::getNestedRowsCount(int row, int column) const - { - return getAdapter(Collection::getColumn(column)).getNestedRowsCount( - Collection::getRecord(row)); - } - - template - int SubCellCollection::getNestedColumnsCount(int row, int column) const - { - return getAdapter(Collection::getColumn(column)).getNestedColumnsCount( - Collection::getRecord(row)); - } - - template - CSMWorld::NestableColumn *SubCellCollection::getNestableColumn(int column) - { - return Collection::getNestableColumn(column); - } } #endif From 88bc62e05450fbd5b35a9beb76c0cccb50122e15 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 11 Apr 2015 15:55:26 +1000 Subject: [PATCH 698/740] Add Region sounds table to dialogue subview. --- apps/opencs/model/world/columnbase.hpp | 1 + apps/opencs/model/world/columnimp.hpp | 46 ++++++++++++ apps/opencs/model/world/columns.cpp | 4 + apps/opencs/model/world/columns.hpp | 4 + apps/opencs/model/world/data.cpp | 8 +- apps/opencs/model/world/data.hpp | 3 +- apps/opencs/model/world/idadapterimp.hpp | 96 +++++++++++++++++++++++- 7 files changed, 156 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index e6799cf56..3902a009b 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -99,6 +99,7 @@ namespace CSMWorld Display_NestedDestinationsList, Display_PathgridPointList, Display_PathgridEdgeList, + Display_RegionSoundList, Display_EnchantmentType, Display_BodyPartType, diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 3fb9a4685..06467a632 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -2355,6 +2355,52 @@ namespace CSMWorld return true; } }; + + template + struct RegionSoundListColumn : public Column + { + RegionSoundListColumn () + : Column (Columns::ColumnId_RegionSounds, + ColumnBase::Display_RegionSoundList, ColumnBase::Flag_Dialogue) + {} + + virtual QVariant get (const Record& record) const + { + return true; // required by IdTree::hasChildren() + } + + virtual bool isEditable() const + { + return true; + } + + }; + + struct RegionSoundNameColumn : public NestableColumn + { + RegionSoundNameColumn () + : NestableColumn (Columns::ColumnId_SoundName, + ColumnBase::Display_String, ColumnBase::Flag_Dialogue) + {} + + virtual bool isEditable() const + { + return true; + } + }; + + struct RegionSoundChanceColumn : public NestableColumn + { + RegionSoundChanceColumn () + : NestableColumn (Columns::ColumnId_SoundChance, + ColumnBase::Display_Integer, ColumnBase::Flag_Dialogue) + {} + + virtual bool isEditable() const + { + return true; + } + }; } #endif diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index b65cf7f96..39b3ea2e3 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -233,6 +233,10 @@ namespace CSMWorld { ColumnId_PathgridEdge0, "Point 0"}, { ColumnId_PathgridEdge1, "Point 1"}, + { ColumnId_RegionSounds, "Sounds"}, + { ColumnId_SoundName, "Name"}, + { ColumnId_SoundChance, "Chance"}, + { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue3, "Use value 3" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 2cb7101b0..49a9208b0 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -222,6 +222,10 @@ namespace CSMWorld ColumnId_PathgridEdge0 = 206, ColumnId_PathgridEdge1 = 207, + ColumnId_RegionSounds = 208, + ColumnId_SoundName = 209, + ColumnId_SoundChance = 210, + // 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 87d5116f1..c387298d2 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -140,6 +140,12 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mRegions.addColumn (new NameColumn); mRegions.addColumn (new MapColourColumn); mRegions.addColumn (new SleepListColumn); + // see idadapterimpl.hpp and columnimp.hpp + RegionSoundListColumn *soundList = new RegionSoundListColumn (); + mRegions.addColumn (soundList); + mRegions.addAdapter (std::make_pair(soundList, new RegionSoundListAdapter ())); + mRegions.getNestableColumn(mRegions.getColumns()-1)->addColumn(new RegionSoundNameColumn ()); + mRegions.getNestableColumn(mRegions.getColumns()-1)->addColumn(new RegionSoundChanceColumn ()); mBirthsigns.addColumn (new StringIdColumn); mBirthsigns.addColumn (new RecordStateColumn); @@ -339,7 +345,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc addModel (new IdTable (&mRaces), UniversalId::Type_Race); addModel (new IdTable (&mSounds), UniversalId::Type_Sound); addModel (new IdTable (&mScripts), UniversalId::Type_Script); - addModel (new IdTable (&mRegions), UniversalId::Type_Region); + addModel (new IdTree (&mRegions, &mRegions), UniversalId::Type_Region); addModel (new IdTable (&mBirthsigns), UniversalId::Type_Birthsign); addModel (new IdTable (&mSpells), UniversalId::Type_Spell); addModel (new IdTable (&mTopics), UniversalId::Type_Topic); diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index b9e060002..329aceaf7 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -34,6 +34,7 @@ #include "../doc/stage.hpp" #include "idcollection.hpp" +#include "nestedidcollection.hpp" #include "universalid.hpp" #include "cell.hpp" #include "land.hpp" @@ -72,7 +73,7 @@ namespace CSMWorld IdCollection mRaces; IdCollection mSounds; IdCollection mScripts; - IdCollection mRegions; + NestedIdCollection mRegions; IdCollection mBirthsigns; IdCollection mSpells; IdCollection mTopics; diff --git a/apps/opencs/model/world/idadapterimp.hpp b/apps/opencs/model/world/idadapterimp.hpp index 7df653059..d5a44aea2 100644 --- a/apps/opencs/model/world/idadapterimp.hpp +++ b/apps/opencs/model/world/idadapterimp.hpp @@ -4,6 +4,7 @@ #include #include +#include #include "idadapter.hpp" #include "nestedtablewrapper.hpp" @@ -127,7 +128,7 @@ namespace CSMWorld case 1: return point.mX; case 2: return point.mY; case 3: return point.mZ; - default: throw std::logic_error("Pathgrid point subcolumn index out of range"); + default: throw std::runtime_error("Pathgrid point subcolumn index out of range"); } } @@ -142,7 +143,7 @@ namespace CSMWorld case 1: point.mX = value.toInt(); break; case 2: point.mY = value.toInt(); break; case 3: point.mZ = value.toInt(); break; - default: throw std::logic_error("Pathgrid point subcolumn index out of range"); + default: throw std::runtime_error("Pathgrid point subcolumn index out of range"); } pathgrid.mPoints[subRowIndex] = point; @@ -223,7 +224,7 @@ namespace CSMWorld case 0: return subRowIndex; case 1: return edge.mV0; case 2: return edge.mV1; - default: throw std::logic_error("Pathgrid edge subcolumn index out of range"); + default: throw std::runtime_error("Pathgrid edge subcolumn index out of range"); } } @@ -238,7 +239,7 @@ namespace CSMWorld case 0: break; case 1: edge.mV0 = value.toInt(); break; case 2: edge.mV1 = value.toInt(); break; - default: throw std::logic_error("Pathgrid edge subcolumn index out of range"); + default: throw std::runtime_error("Pathgrid edge subcolumn index out of range"); } pathgrid.mEdges[subRowIndex] = edge; @@ -256,6 +257,93 @@ namespace CSMWorld return static_cast(record.get().mEdges.size()); } }; + + template + class RegionSoundListAdapter : public NestedIdAdapter + { + public: + RegionSoundListAdapter () {} + + virtual void addNestedRow(Record& record, int position) const + { + ESXRecordT region = record.get(); + + std::vector& soundList = region.mSoundList; + + // blank row + ESXRecordT::SoundRef soundRef; + soundRef.mSound.assign(""); + soundRef.mChance = 0; + + soundList.insert(soundList.begin()+position, soundRef); + + record.setModified (region); + } + + virtual void removeNestedRow(Record& record, int rowToRemove) const + { + ESXRecordT region = record.get(); + + std::vector& soundList = region.mSoundList; + + if (rowToRemove < 0 || rowToRemove >= static_cast (soundList.size())) + throw std::runtime_error ("index out of range"); + + soundList.erase(soundList.begin()+rowToRemove); + + record.setModified (region); + } + + virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const + { + record.get().mSoundList = + static_cast >&>(nestedTable).mNestedTable; + } + + virtual NestedTableWrapperBase* nestedTable(const Record& record) const + { + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(record.get().mSoundList); + } + + virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const + { + ESXRecordT::SoundRef soundRef = record.get().mSoundList[subRowIndex]; + switch (subColIndex) + { + case 0: return QString(soundRef.mSound.toString().c_str()); + case 1: return soundRef.mChance; + default: throw std::runtime_error("Region sounds subcolumn index out of range"); + } + } + + virtual void setNestedData(Record& record, const QVariant& value, + int subRowIndex, int subColIndex) const + { + ESXRecordT region = record.get(); + ESXRecordT::SoundRef soundRef = region.mSoundList[subRowIndex]; + switch (subColIndex) + { + case 0: soundRef.mSound.assign(value.toString().toUtf8().constData()); break; + case 1: soundRef.mChance = static_cast(value.toInt()); break; + default: throw std::runtime_error("Region sounds subcolumn index out of range"); + } + + region.mSoundList[subRowIndex] = soundRef; + + record.setModified (region); + } + + virtual int getNestedColumnsCount(const Record& record) const + { + return 2; + } + + virtual int getNestedRowsCount(const Record& record) const + { + return static_cast(record.get().mSoundList.size()); + } + }; } #endif // CSM_WOLRD_IDADAPTERIMP_H From ea9563ad92c13397497846afad39fcc5d4cafb2d Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 11 Apr 2015 17:51:30 +1000 Subject: [PATCH 699/740] Add faction reactions table to dialogue subview. Fix gcc compile issues. Change nested columns to generic ones where possible. --- apps/opencs/model/world/columnbase.hpp | 2 +- apps/opencs/model/world/columnimp.hpp | 21 ++- apps/opencs/model/world/columns.cpp | 5 + apps/opencs/model/world/columns.hpp | 7 +- apps/opencs/model/world/data.cpp | 22 +++- apps/opencs/model/world/data.hpp | 2 +- apps/opencs/model/world/idadapterimp.hpp | 159 +++++++++++++++++++++-- 7 files changed, 190 insertions(+), 28 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 3902a009b..c994ced15 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -99,7 +99,7 @@ namespace CSMWorld Display_NestedDestinationsList, Display_PathgridPointList, Display_PathgridEdgeList, - Display_RegionSoundList, + Display_NestedHeader, Display_EnchantmentType, Display_BodyPartType, diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 06467a632..675352d35 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -2357,11 +2357,10 @@ namespace CSMWorld }; template - struct RegionSoundListColumn : public Column + struct NestedParentColumn : public Column { - RegionSoundListColumn () - : Column (Columns::ColumnId_RegionSounds, - ColumnBase::Display_RegionSoundList, ColumnBase::Flag_Dialogue) + NestedParentColumn (Columns::ColumnId id) + : Column (id, ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue) {} virtual QVariant get (const Record& record) const @@ -2376,11 +2375,10 @@ namespace CSMWorld }; - struct RegionSoundNameColumn : public NestableColumn + struct NestedStringColumn : public NestableColumn { - RegionSoundNameColumn () - : NestableColumn (Columns::ColumnId_SoundName, - ColumnBase::Display_String, ColumnBase::Flag_Dialogue) + NestedStringColumn (Columns::ColumnId id) + : NestableColumn (id, ColumnBase::Display_String, ColumnBase::Flag_Dialogue) {} virtual bool isEditable() const @@ -2389,11 +2387,10 @@ namespace CSMWorld } }; - struct RegionSoundChanceColumn : public NestableColumn + struct NestedIntegerColumn : public NestableColumn { - RegionSoundChanceColumn () - : NestableColumn (Columns::ColumnId_SoundChance, - ColumnBase::Display_Integer, ColumnBase::Flag_Dialogue) + NestedIntegerColumn (Columns::ColumnId id) + : NestableColumn (id, ColumnBase::Display_Integer, ColumnBase::Flag_Dialogue) {} virtual bool isEditable() const diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 39b3ea2e3..c9155a5ad 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -237,6 +237,10 @@ namespace CSMWorld { ColumnId_SoundName, "Name"}, { ColumnId_SoundChance, "Chance"}, + { ColumnId_FactionReactions, "Reactions"}, + //{ ColumnId_FactionID, "Faction ID"}, + { ColumnId_FactionReaction, "Reaction"}, + { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue3, "Use value 3" }, @@ -263,6 +267,7 @@ namespace CSMWorld { ColumnId_Skill4, "Skill 4" }, { ColumnId_Skill5, "Skill 5" }, { ColumnId_Skill6, "Skill 6" }, + { ColumnId_Skill7, "Skill 7" }, { -1, 0 } // end marker }; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 49a9208b0..531cf9972 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -226,6 +226,10 @@ namespace CSMWorld ColumnId_SoundName = 209, ColumnId_SoundChance = 210, + ColumnId_FactionReactions = 211, + //ColumnId_FactionID = 212, + ColumnId_FactionReaction = 213, + // 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, @@ -259,7 +263,8 @@ namespace CSMWorld ColumnId_Skill3 = 0x50002, ColumnId_Skill4 = 0x50003, ColumnId_Skill5 = 0x50004, - ColumnId_Skill6 = 0x50005 + ColumnId_Skill6 = 0x50005, + ColumnId_Skill7 = 0x50006 }; std::string getName (ColumnId column); diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index c387298d2..3352dd30e 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -108,6 +108,15 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mFactions.addColumn (new HiddenColumn); for (int i=0; i<7; ++i) mFactions.addColumn (new SkillsColumn (i)); + // Faction Reactions + NestedParentColumn *reactions = + new NestedParentColumn (Columns::ColumnId_FactionReactions); + mFactions.addColumn (reactions); + mFactions.addAdapter (std::make_pair(reactions, new FactionReactionsAdapter ())); + mFactions.getNestableColumn(mFactions.getColumns()-1)->addColumn( + new NestedStringColumn (Columns::ColumnId_Faction)); + mFactions.getNestableColumn(mFactions.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_FactionReaction)); mRaces.addColumn (new StringIdColumn); mRaces.addColumn (new RecordStateColumn); @@ -140,12 +149,15 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mRegions.addColumn (new NameColumn); mRegions.addColumn (new MapColourColumn); mRegions.addColumn (new SleepListColumn); - // see idadapterimpl.hpp and columnimp.hpp - RegionSoundListColumn *soundList = new RegionSoundListColumn (); + // Region Sounds + NestedParentColumn *soundList = + new NestedParentColumn (Columns::ColumnId_RegionSounds); mRegions.addColumn (soundList); mRegions.addAdapter (std::make_pair(soundList, new RegionSoundListAdapter ())); - mRegions.getNestableColumn(mRegions.getColumns()-1)->addColumn(new RegionSoundNameColumn ()); - mRegions.getNestableColumn(mRegions.getColumns()-1)->addColumn(new RegionSoundChanceColumn ()); + mRegions.getNestableColumn(mRegions.getColumns()-1)->addColumn( + new NestedStringColumn (Columns::ColumnId_SoundName)); + mRegions.getNestableColumn(mRegions.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_SoundChance)); mBirthsigns.addColumn (new StringIdColumn); mBirthsigns.addColumn (new RecordStateColumn); @@ -341,7 +353,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc addModel (new IdTable (&mGmsts), UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skill); addModel (new IdTable (&mClasses), UniversalId::Type_Class); - addModel (new IdTable (&mFactions), UniversalId::Type_Faction); + addModel (new IdTree (&mFactions, &mFactions), UniversalId::Type_Faction); addModel (new IdTable (&mRaces), UniversalId::Type_Race); addModel (new IdTable (&mSounds), UniversalId::Type_Sound); addModel (new IdTable (&mScripts), UniversalId::Type_Script); diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 329aceaf7..858f82639 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -69,7 +69,7 @@ namespace CSMWorld IdCollection mGmsts; IdCollection mSkills; IdCollection mClasses; - IdCollection mFactions; + NestedIdCollection mFactions; IdCollection mRaces; IdCollection mSounds; IdCollection mScripts; diff --git a/apps/opencs/model/world/idadapterimp.hpp b/apps/opencs/model/world/idadapterimp.hpp index d5a44aea2..00f7b1831 100644 --- a/apps/opencs/model/world/idadapterimp.hpp +++ b/apps/opencs/model/world/idadapterimp.hpp @@ -5,6 +5,7 @@ #include #include +#include #include "idadapter.hpp" #include "nestedtablewrapper.hpp" @@ -218,7 +219,12 @@ namespace CSMWorld virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const { - ESM::Pathgrid::Edge edge = record.get().mEdges[subRowIndex]; + ESXRecordT pathgrid = record.get(); + + if (subRowIndex < 0 || subRowIndex >= static_cast (pathgrid.mEdges.size())) + throw std::runtime_error ("index out of range"); + + ESM::Pathgrid::Edge edge = pathgrid.mEdges[subRowIndex]; switch (subColIndex) { case 0: return subRowIndex; @@ -233,6 +239,10 @@ namespace CSMWorld int subRowIndex, int subColIndex) const { ESXRecordT pathgrid = record.get(); + + if (subRowIndex < 0 || subRowIndex >= static_cast (pathgrid.mEdges.size())) + throw std::runtime_error ("index out of range"); + ESM::Pathgrid::Edge edge = pathgrid.mEdges[subRowIndex]; switch (subColIndex) { @@ -258,6 +268,126 @@ namespace CSMWorld } }; + template + class FactionReactionsAdapter : public NestedIdAdapter + { + public: + FactionReactionsAdapter () {} + + virtual void addNestedRow(Record& record, int position) const + { + ESXRecordT faction = record.get(); + + std::map& reactions = faction.mReactions; + + // blank row + reactions.insert(std::make_pair("", 0)); + + record.setModified (faction); + } + + virtual void removeNestedRow(Record& record, int rowToRemove) const + { + ESXRecordT faction = record.get(); + + std::map& reactions = faction.mReactions; + + if (rowToRemove < 0 || rowToRemove >= static_cast (reactions.size())) + throw std::runtime_error ("index out of range"); + + // FIXME: how to ensure that the map entries correspond to table indicies? + // WARNING: Assumed that the table view has the same order as std::map + std::map::const_iterator iter = reactions.begin(); + for(int i = 0; i < rowToRemove; ++i) + iter++; + reactions.erase(iter); + + record.setModified (faction); + } + + virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const + { + record.get().mReactions = + static_cast >&>(nestedTable).mNestedTable; + } + + virtual NestedTableWrapperBase* nestedTable(const Record& record) const + { + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(record.get().mReactions); + } + + virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const + { + ESXRecordT faction = record.get(); + + std::map& reactions = faction.mReactions; + + if (subRowIndex < 0 || subRowIndex >= static_cast (reactions.size())) + throw std::runtime_error ("index out of range"); + + // FIXME: how to ensure that the map entries correspond to table indicies? + // WARNING: Assumed that the table view has the same order as std::map + std::map::const_iterator iter = reactions.begin(); + for(int i = 0; i < subRowIndex; ++i) + iter++; + switch (subColIndex) + { + case 0: return QString((*iter).first.c_str()); + case 1: return (*iter).second; + default: throw std::runtime_error("Faction reactions subcolumn index out of range"); + } + } + + virtual void setNestedData(Record& record, const QVariant& value, + int subRowIndex, int subColIndex) const + { + ESXRecordT faction = record.get(); + + std::map& reactions = faction.mReactions; + + if (subRowIndex < 0 || subRowIndex >= static_cast (reactions.size())) + throw std::runtime_error ("index out of range"); + + // FIXME: how to ensure that the map entries correspond to table indicies? + // WARNING: Assumed that the table view has the same order as std::map + std::map::const_iterator iter = reactions.begin(); + for(int i = 0; i < subRowIndex; ++i) + iter++; + + std::string factionId = (*iter).first; + int reaction = (*iter).second; + + switch (subColIndex) + { + case 0: + { + reactions.erase(iter); + reactions.insert(std::make_pair(value.toString().toUtf8().constData(), reaction)); + break; + } + case 1: + { + reactions[factionId] = value.toInt(); + break; + } + default: throw std::runtime_error("Faction reactions subcolumn index out of range"); + } + + record.setModified (faction); + } + + virtual int getNestedColumnsCount(const Record& record) const + { + return 2; + } + + virtual int getNestedRowsCount(const Record& record) const + { + return static_cast(record.get().mReactions.size()); + } + }; + template class RegionSoundListAdapter : public NestedIdAdapter { @@ -268,10 +398,10 @@ namespace CSMWorld { ESXRecordT region = record.get(); - std::vector& soundList = region.mSoundList; + std::vector& soundList = region.mSoundList; // blank row - ESXRecordT::SoundRef soundRef; + typename ESXRecordT::SoundRef soundRef; soundRef.mSound.assign(""); soundRef.mChance = 0; @@ -284,7 +414,7 @@ namespace CSMWorld { ESXRecordT region = record.get(); - std::vector& soundList = region.mSoundList; + std::vector& soundList = region.mSoundList; if (rowToRemove < 0 || rowToRemove >= static_cast (soundList.size())) throw std::runtime_error ("index out of range"); @@ -297,18 +427,25 @@ namespace CSMWorld virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const { record.get().mSoundList = - static_cast >&>(nestedTable).mNestedTable; + static_cast >&>(nestedTable).mNestedTable; } virtual NestedTableWrapperBase* nestedTable(const Record& record) const { // deleted by dtor of NestedTableStoring - return new NestedTableWrapper >(record.get().mSoundList); + return new NestedTableWrapper >(record.get().mSoundList); } virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const { - ESXRecordT::SoundRef soundRef = record.get().mSoundList[subRowIndex]; + ESXRecordT region = record.get(); + + std::vector& soundList = region.mSoundList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (soundList.size())) + throw std::runtime_error ("index out of range"); + + typename ESXRecordT::SoundRef soundRef = soundList[subRowIndex]; switch (subColIndex) { case 0: return QString(soundRef.mSound.toString().c_str()); @@ -321,7 +458,13 @@ namespace CSMWorld int subRowIndex, int subColIndex) const { ESXRecordT region = record.get(); - ESXRecordT::SoundRef soundRef = region.mSoundList[subRowIndex]; + + std::vector& soundList = region.mSoundList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (soundList.size())) + throw std::runtime_error ("index out of range"); + + typename ESXRecordT::SoundRef soundRef = soundList[subRowIndex]; switch (subColIndex) { case 0: soundRef.mSound.assign(value.toString().toUtf8().constData()); break; From 9c75dad1acca2d48f26c97123875fc4ed5c60a3c Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 11 Apr 2015 18:21:08 +1000 Subject: [PATCH 700/740] Why is gcc so unkind? --- apps/opencs/model/world/idadapterimp.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/idadapterimp.hpp b/apps/opencs/model/world/idadapterimp.hpp index 00f7b1831..9c4686f4e 100644 --- a/apps/opencs/model/world/idadapterimp.hpp +++ b/apps/opencs/model/world/idadapterimp.hpp @@ -297,7 +297,7 @@ namespace CSMWorld // FIXME: how to ensure that the map entries correspond to table indicies? // WARNING: Assumed that the table view has the same order as std::map - std::map::const_iterator iter = reactions.begin(); + std::map::iterator iter = reactions.begin(); for(int i = 0; i < rowToRemove; ++i) iter++; reactions.erase(iter); @@ -351,7 +351,7 @@ namespace CSMWorld // FIXME: how to ensure that the map entries correspond to table indicies? // WARNING: Assumed that the table view has the same order as std::map - std::map::const_iterator iter = reactions.begin(); + std::map::iterator iter = reactions.begin(); for(int i = 0; i < subRowIndex; ++i) iter++; From f939648736ccf09a4d93699b2f8f3d7ea26ed6e7 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 11 Apr 2015 19:05:03 +1000 Subject: [PATCH 701/740] Add race spells table to dialogue subview. --- apps/opencs/model/world/columns.cpp | 2 +- apps/opencs/model/world/columns.hpp | 2 +- apps/opencs/model/world/data.cpp | 13 ++- apps/opencs/model/world/data.hpp | 2 +- apps/opencs/model/world/idadapterimp.hpp | 96 +++++++++++++++++++++ apps/opencs/model/world/refidcollection.cpp | 2 +- 6 files changed, 110 insertions(+), 7 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index c9155a5ad..a2843d3e8 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -187,7 +187,7 @@ namespace CSMWorld { ColumnId_MeshType, "Mesh Type" }, { ColumnId_ActorInventory, "Inventory" }, - { ColumnId_ActorSpells, "Spells" }, + { ColumnId_SpellList, "Spells" }, { ColumnId_SpellId, "ID"}, { ColumnId_NpcDestinations, "Destinations" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 531cf9972..a1dc89393 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -179,7 +179,7 @@ namespace CSMWorld ColumnId_BodyPartType = 164, ColumnId_MeshType = 165, ColumnId_ActorInventory = 166, - ColumnId_ActorSpells = 167, + ColumnId_SpellList = 167, ColumnId_SpellId = 168, ColumnId_NpcDestinations = 169, ColumnId_DestinationCell = 170, diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 3352dd30e..87ba44001 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -110,7 +110,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mFactions.addColumn (new SkillsColumn (i)); // Faction Reactions NestedParentColumn *reactions = - new NestedParentColumn (Columns::ColumnId_FactionReactions); + new NestedParentColumn (Columns::ColumnId_FactionReactions); mFactions.addColumn (reactions); mFactions.addAdapter (std::make_pair(reactions, new FactionReactionsAdapter ())); mFactions.getNestableColumn(mFactions.getColumns()-1)->addColumn( @@ -129,6 +129,13 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mRaces.addColumn (new WeightHeightColumn (true, false)); mRaces.addColumn (new WeightHeightColumn (false, true)); mRaces.addColumn (new WeightHeightColumn (false, false)); + // Race spells + NestedParentColumn *raceSpells = + new NestedParentColumn (Columns::ColumnId_SpellList); + mRaces.addColumn (raceSpells); + mRaces.addAdapter (std::make_pair(raceSpells, new SpellListAdapter ())); + mRaces.getNestableColumn(mRaces.getColumns()-1)->addColumn( + new NestedStringColumn (Columns::ColumnId_SpellId)); mSounds.addColumn (new StringIdColumn); mSounds.addColumn (new RecordStateColumn); @@ -151,7 +158,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mRegions.addColumn (new SleepListColumn); // Region Sounds NestedParentColumn *soundList = - new NestedParentColumn (Columns::ColumnId_RegionSounds); + new NestedParentColumn (Columns::ColumnId_RegionSounds); mRegions.addColumn (soundList); mRegions.addAdapter (std::make_pair(soundList, new RegionSoundListAdapter ())); mRegions.getNestableColumn(mRegions.getColumns()-1)->addColumn( @@ -354,7 +361,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc addModel (new IdTable (&mSkills), UniversalId::Type_Skill); addModel (new IdTable (&mClasses), UniversalId::Type_Class); addModel (new IdTree (&mFactions, &mFactions), UniversalId::Type_Faction); - addModel (new IdTable (&mRaces), UniversalId::Type_Race); + addModel (new IdTree (&mRaces, &mRaces), UniversalId::Type_Race); addModel (new IdTable (&mSounds), UniversalId::Type_Sound); addModel (new IdTable (&mScripts), UniversalId::Type_Script); addModel (new IdTree (&mRegions, &mRegions), UniversalId::Type_Region); diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 858f82639..172a194be 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -70,7 +70,7 @@ namespace CSMWorld IdCollection mSkills; IdCollection mClasses; NestedIdCollection mFactions; - IdCollection mRaces; + NestedIdCollection mRaces; IdCollection mSounds; IdCollection mScripts; NestedIdCollection mRegions; diff --git a/apps/opencs/model/world/idadapterimp.hpp b/apps/opencs/model/world/idadapterimp.hpp index 9c4686f4e..c49435f1c 100644 --- a/apps/opencs/model/world/idadapterimp.hpp +++ b/apps/opencs/model/world/idadapterimp.hpp @@ -487,6 +487,102 @@ namespace CSMWorld return static_cast(record.get().mSoundList.size()); } }; + + template + class SpellListAdapter : public NestedIdAdapter + { + public: + SpellListAdapter () {} + + virtual void addNestedRow(Record& record, int position) const + { + ESXRecordT raceOrBthSgn = record.get(); + + std::vector& spells = raceOrBthSgn.mPowers.mList; + + // blank row + std::string spell = ""; + + spells.insert(spells.begin()+position, spell); + + record.setModified (raceOrBthSgn); + } + + virtual void removeNestedRow(Record& record, int rowToRemove) const + { + ESXRecordT raceOrBthSgn = record.get(); + + std::vector& spells = raceOrBthSgn.mPowers.mList; + + if (rowToRemove < 0 || rowToRemove >= static_cast (spells.size())) + throw std::runtime_error ("index out of range"); + + spells.erase(spells.begin()+rowToRemove); + + record.setModified (raceOrBthSgn); + } + + virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const + { + record.get().mPowers.mList = + static_cast >&>(nestedTable).mNestedTable; + } + + virtual NestedTableWrapperBase* nestedTable(const Record& record) const + { + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(record.get().mPowers.mList); + } + + virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const + { + ESXRecordT raceOrBthSgn = record.get(); + + std::vector& spells = raceOrBthSgn.mPowers.mList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (spells.size())) + throw std::runtime_error ("index out of range"); + + std::string spell = spells[subRowIndex]; + switch (subColIndex) + { + case 0: return QString(spell.c_str()); + default: throw std::runtime_error("Spells subcolumn index out of range"); + } + } + + virtual void setNestedData(Record& record, const QVariant& value, + int subRowIndex, int subColIndex) const + { + ESXRecordT raceOrBthSgn = record.get(); + + std::vector& spells = raceOrBthSgn.mPowers.mList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (spells.size())) + throw std::runtime_error ("index out of range"); + + std::string spell = spells[subRowIndex]; + switch (subColIndex) + { + case 0: spell = value.toString().toUtf8().constData(); break; + default: throw std::runtime_error("Spells subcolumn index out of range"); + } + + raceOrBthSgn.mPowers.mList[subRowIndex] = spell; + + record.setModified (raceOrBthSgn); + } + + virtual int getNestedColumnsCount(const Record& record) const + { + return 1; + } + + virtual int getNestedRowsCount(const Record& record) const + { + return static_cast(record.get().mPowers.mList.size()); + } + }; } #endif // CSM_WOLRD_IDADAPTERIMP_H diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index b85deef4e..392a1677e 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -106,7 +106,7 @@ CSMWorld::RefIdCollection::RefIdCollection() new RefIdColumn (Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer)); // Nested table - mColumns.push_back(RefIdColumn (Columns::ColumnId_ActorSpells, ColumnBase::Display_NestedSpellList, ColumnBase::Flag_Dialogue)); + mColumns.push_back(RefIdColumn (Columns::ColumnId_SpellList, ColumnBase::Display_NestedSpellList, ColumnBase::Flag_Dialogue)); actorsColumns.mSpells = &mColumns.back(); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_SpellId, CSMWorld::ColumnBase::Display_String)); From 49fd5afdf650243a93e0a276fe665b2c7a6272c4 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 11 Apr 2015 19:17:17 +1000 Subject: [PATCH 702/740] Add birthsign spells table to dialogue subview. --- apps/opencs/model/world/data.cpp | 9 ++++++++- apps/opencs/model/world/data.hpp | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 87ba44001..74b418b30 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -172,6 +172,13 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mBirthsigns.addColumn (new NameColumn); mBirthsigns.addColumn (new TextureColumn); mBirthsigns.addColumn (new DescriptionColumn); + // Birthsign spells + NestedParentColumn *birthSpells = + new NestedParentColumn (Columns::ColumnId_SpellList); + mBirthsigns.addColumn (birthSpells); + mBirthsigns.addAdapter (std::make_pair(birthSpells, new SpellListAdapter ())); + mBirthsigns.getNestableColumn(mBirthsigns.getColumns()-1)->addColumn( + new NestedStringColumn (Columns::ColumnId_SpellId)); mSpells.addColumn (new StringIdColumn); mSpells.addColumn (new RecordStateColumn); @@ -365,7 +372,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc addModel (new IdTable (&mSounds), UniversalId::Type_Sound); addModel (new IdTable (&mScripts), UniversalId::Type_Script); addModel (new IdTree (&mRegions, &mRegions), UniversalId::Type_Region); - addModel (new IdTable (&mBirthsigns), UniversalId::Type_Birthsign); + addModel (new IdTree (&mBirthsigns, &mBirthsigns), UniversalId::Type_Birthsign); addModel (new IdTable (&mSpells), UniversalId::Type_Spell); addModel (new IdTable (&mTopics), UniversalId::Type_Topic); addModel (new IdTable (&mJournals), UniversalId::Type_Journal); diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 172a194be..2d2fd974c 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -74,7 +74,7 @@ namespace CSMWorld IdCollection mSounds; IdCollection mScripts; NestedIdCollection mRegions; - IdCollection mBirthsigns; + NestedIdCollection mBirthsigns; IdCollection mSpells; IdCollection mTopics; IdCollection mJournals; From a460409555b1edc0fa7f8b1a8bb2217fea771ecb Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 11 Apr 2015 21:43:25 +1000 Subject: [PATCH 703/740] Add Spells and Enchantment magic effects table to dialogue subview. The numbers are not yet converted to strings. --- apps/opencs/model/world/columnimp.hpp | 98 +------------------ apps/opencs/model/world/columns.cpp | 6 ++ apps/opencs/model/world/columns.hpp | 6 ++ apps/opencs/model/world/data.cpp | 75 +++++++++++--- apps/opencs/model/world/data.hpp | 4 +- apps/opencs/model/world/idadapterimp.hpp | 119 +++++++++++++++++++++++ 6 files changed, 201 insertions(+), 107 deletions(-) diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 675352d35..0ab33065b 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -2265,97 +2265,6 @@ namespace CSMWorld } }; - template - struct PathgridPointListColumn : public Column - { - PathgridPointListColumn () - : Column (Columns::ColumnId_PathgridPoints, - ColumnBase::Display_PathgridPointList, ColumnBase::Flag_Dialogue) - {} - - virtual QVariant get (const Record& record) const - { - return true; // required by IdTree::hasChildren() - } - - virtual bool isEditable() const - { - return true; - } - }; - - struct PathgridIndexColumn : public NestableColumn - { - PathgridIndexColumn() - : NestableColumn (Columns::ColumnId_PathgridIndex, - ColumnBase::Display_Integer, ColumnBase::Flag_Dialogue) - {} - - virtual bool isEditable() const - { - return false; - } - }; - - struct PathgridPointColumn : public NestableColumn - { - PathgridPointColumn(int index) - : NestableColumn (Columns::ColumnId_PathgridPosX+index, - ColumnBase::Display_Integer, ColumnBase::Flag_Dialogue) - {} - - virtual bool isEditable() const - { - return true; - } - }; - - template - struct PathgridEdgeListColumn : public Column - { - PathgridEdgeListColumn () - : Column (Columns::ColumnId_PathgridEdges, - ColumnBase::Display_PathgridEdgeList, ColumnBase::Flag_Dialogue) - {} - - virtual QVariant get (const Record& record) const - { - return true; // required by IdTree::hasChildren() - } - - virtual bool isEditable() const - { - return true; - } - - }; - - struct PathgridEdgeIndexColumn : public NestableColumn - { - PathgridEdgeIndexColumn() - : NestableColumn (Columns::ColumnId_PathgridEdgeIndex, - ColumnBase::Display_Integer, ColumnBase::Flag_Dialogue) - {} - - virtual bool isEditable() const - { - return false; - } - }; - - struct PathgridEdgeColumn : public NestableColumn - { - PathgridEdgeColumn (int index) - : NestableColumn (Columns::ColumnId_PathgridEdge0+index, - ColumnBase::Display_Integer, ColumnBase::Flag_Dialogue) - {} - - virtual bool isEditable() const - { - return true; - } - }; - template struct NestedParentColumn : public Column { @@ -2389,13 +2298,16 @@ namespace CSMWorld struct NestedIntegerColumn : public NestableColumn { - NestedIntegerColumn (Columns::ColumnId id) + bool mIsEditable; + + NestedIntegerColumn (Columns::ColumnId id, bool isEditable = true) : NestableColumn (id, ColumnBase::Display_Integer, ColumnBase::Flag_Dialogue) + , mIsEditable(isEditable) {} virtual bool isEditable() const { - return true; + return mIsEditable; } }; } diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index a2843d3e8..efe9a5116 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -241,6 +241,12 @@ namespace CSMWorld //{ ColumnId_FactionID, "Faction ID"}, { ColumnId_FactionReaction, "Reaction"}, + { ColumnId_EffectList, "Effects"}, + { ColumnId_EffectId, "ID"}, + { ColumnId_EffectAttribute, "Attrib"}, + { ColumnId_EffectRange, "Range"}, + { ColumnId_EffectArea, "Area"}, + { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue3, "Use value 3" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index a1dc89393..6b3791042 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -230,6 +230,12 @@ namespace CSMWorld //ColumnId_FactionID = 212, ColumnId_FactionReaction = 213, + ColumnId_EffectList = 214, + ColumnId_EffectId = 215, + ColumnId_EffectAttribute = 216, + ColumnId_EffectRange = 217, + ColumnId_EffectArea = 218, + // 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 74b418b30..86cf3bb44 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -189,6 +189,27 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mSpells.addColumn (new FlagColumn (Columns::ColumnId_AutoCalc, 0x1)); mSpells.addColumn (new FlagColumn (Columns::ColumnId_StarterSpell, 0x2)); mSpells.addColumn (new FlagColumn (Columns::ColumnId_AlwaysSucceeds, 0x4)); + // Spell effects + NestedParentColumn *spellEffect = + new NestedParentColumn (Columns::ColumnId_EffectList); + mSpells.addColumn (spellEffect); + mSpells.addAdapter (std::make_pair(spellEffect, new EffectsListAdapter ())); + mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_EffectId)); + mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_Skill)); + mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_EffectAttribute)); + mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_EffectRange)); + mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_EffectArea)); + mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_Duration)); // reuse from light + mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_MinRange)); // reuse from sound + mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_MaxRange)); // reuse from sound mTopics.addColumn (new StringIdColumn); mTopics.addColumn (new RecordStateColumn); @@ -242,6 +263,27 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mEnchantments.addColumn (new CostColumn); mEnchantments.addColumn (new ChargesColumn2); mEnchantments.addColumn (new AutoCalcColumn); + // Enchantment effects + NestedParentColumn *enchantmentEffect = + new NestedParentColumn (Columns::ColumnId_EffectList); + mEnchantments.addColumn (enchantmentEffect); + mEnchantments.addAdapter (std::make_pair(enchantmentEffect, new EffectsListAdapter ())); + mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_EffectId)); + mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_Skill)); + mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_EffectAttribute)); + mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_EffectRange)); + mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_EffectArea)); + mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_Duration)); // reuse from light + mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_MinRange)); // reuse from sound + mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_MaxRange)); // reuse from sound mBodyParts.addColumn (new StringIdColumn); mBodyParts.addColumn (new RecordStateColumn); @@ -289,23 +331,32 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mPathgrids.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Pathgrid)); // new object deleted in dtor of Collection - PathgridPointListColumn *pointList = new PathgridPointListColumn (); + NestedParentColumn *pointList = + new NestedParentColumn (Columns::ColumnId_PathgridPoints); mPathgrids.addColumn (pointList); // new object deleted in dtor of SubCellCollection mPathgrids.addAdapter (std::make_pair(pointList, new PathgridPointListAdapter ())); // new objects deleted in dtor of NestableColumn // WARNING: The order of the columns below are assumed in PathgridPointListAdapter - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridIndexColumn ()); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridPointColumn (0)); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridPointColumn (1)); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridPointColumn (2)); - - PathgridEdgeListColumn *edgeList = new PathgridEdgeListColumn (); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_PathgridIndex, false)); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_PathgridPosX)); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_PathgridPosY)); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_PathgridPosZ)); + + NestedParentColumn *edgeList = + new NestedParentColumn (Columns::ColumnId_PathgridEdges); mPathgrids.addColumn (edgeList); mPathgrids.addAdapter (std::make_pair(edgeList, new PathgridEdgeListAdapter ())); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridEdgeIndexColumn ()); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridEdgeColumn (0)); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn(new PathgridEdgeColumn (1)); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_PathgridEdgeIndex, false)); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_PathgridEdge0)); + mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_PathgridEdge1)); mStartScripts.addColumn (new StringIdColumn); mStartScripts.addColumn (new RecordStateColumn); @@ -373,13 +424,13 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc addModel (new IdTable (&mScripts), UniversalId::Type_Script); addModel (new IdTree (&mRegions, &mRegions), UniversalId::Type_Region); addModel (new IdTree (&mBirthsigns, &mBirthsigns), UniversalId::Type_Birthsign); - addModel (new IdTable (&mSpells), UniversalId::Type_Spell); + addModel (new IdTree (&mSpells, &mSpells), UniversalId::Type_Spell); addModel (new IdTable (&mTopics), UniversalId::Type_Topic); addModel (new IdTable (&mJournals), UniversalId::Type_Journal); addModel (new IdTable (&mTopicInfos, IdTable::Feature_ReorderWithinTopic), UniversalId::Type_TopicInfo); addModel (new IdTable (&mJournalInfos, IdTable::Feature_ReorderWithinTopic), UniversalId::Type_JournalInfo); addModel (new IdTable (&mCells, IdTable::Feature_ViewId), UniversalId::Type_Cell); - addModel (new IdTable (&mEnchantments), UniversalId::Type_Enchantment); + addModel (new IdTree (&mEnchantments, &mEnchantments), UniversalId::Type_Enchantment); addModel (new IdTable (&mBodyParts), UniversalId::Type_BodyPart); addModel (new IdTable (&mSoundGens), UniversalId::Type_SoundGen); addModel (new IdTable (&mMagicEffects), UniversalId::Type_MagicEffect); diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 2d2fd974c..5ab69ac10 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -75,10 +75,10 @@ namespace CSMWorld IdCollection mScripts; NestedIdCollection mRegions; NestedIdCollection mBirthsigns; - IdCollection mSpells; + NestedIdCollection mSpells; IdCollection mTopics; IdCollection mJournals; - IdCollection mEnchantments; + NestedIdCollection mEnchantments; IdCollection mBodyParts; IdCollection mMagicEffects; SubCellCollection mPathgrids; diff --git a/apps/opencs/model/world/idadapterimp.hpp b/apps/opencs/model/world/idadapterimp.hpp index c49435f1c..219032dd3 100644 --- a/apps/opencs/model/world/idadapterimp.hpp +++ b/apps/opencs/model/world/idadapterimp.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "idadapter.hpp" #include "nestedtablewrapper.hpp" @@ -583,6 +584,124 @@ namespace CSMWorld return static_cast(record.get().mPowers.mList.size()); } }; + + template + class EffectsListAdapter : public NestedIdAdapter + { + public: + EffectsListAdapter () {} + + virtual void addNestedRow(Record& record, int position) const + { + ESXRecordT magic = record.get(); + + std::vector& effectsList = magic.mEffects.mList; + + // blank row + ESM::ENAMstruct effect; + effect.mEffectID = 0; + effect.mSkill = 0; + effect.mAttribute = 0; + effect.mRange = 0; + effect.mArea = 0; + effect.mDuration = 0; + effect.mMagnMin = 0; + effect.mMagnMax = 0; + + effectsList.insert(effectsList.begin()+position, effect); + + record.setModified (magic); + } + + virtual void removeNestedRow(Record& record, int rowToRemove) const + { + ESXRecordT magic = record.get(); + + std::vector& effectsList = magic.mEffects.mList; + + if (rowToRemove < 0 || rowToRemove >= static_cast (effectsList.size())) + throw std::runtime_error ("index out of range"); + + effectsList.erase(effectsList.begin()+rowToRemove); + + record.setModified (magic); + } + + virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const + { + record.get().mEffects.mList = + static_cast >&>(nestedTable).mNestedTable; + } + + virtual NestedTableWrapperBase* nestedTable(const Record& record) const + { + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(record.get().mEffects.mList); + } + + virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const + { + ESXRecordT magic = record.get(); + + std::vector& effectsList = magic.mEffects.mList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (effectsList.size())) + throw std::runtime_error ("index out of range"); + + ESM::ENAMstruct effect = effectsList[subRowIndex]; + switch (subColIndex) + { + case 0: return effect.mEffectID; + case 1: return effect.mSkill; + case 2: return effect.mAttribute; + case 3: return effect.mRange; + case 4: return effect.mArea; + case 5: return effect.mDuration; + case 6: return effect.mMagnMin; + case 7: return effect.mMagnMax; + default: throw std::runtime_error("Magic Effects subcolumn index out of range"); + } + } + + virtual void setNestedData(Record& record, const QVariant& value, + int subRowIndex, int subColIndex) const + { + ESXRecordT magic = record.get(); + + std::vector& effectsList = magic.mEffects.mList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (effectsList.size())) + throw std::runtime_error ("index out of range"); + + ESM::ENAMstruct effect = effectsList[subRowIndex]; + switch (subColIndex) + { + case 0: effect.mEffectID = static_cast(value.toInt()); break; + case 1: effect.mSkill = static_cast(value.toInt()); break; + case 2: effect.mAttribute = static_cast(value.toInt()); break; + case 3: effect.mRange = value.toInt(); break; + case 4: effect.mArea = value.toInt(); break; + case 5: effect.mDuration = value.toInt(); break; + case 6: effect.mMagnMin = value.toInt(); break; + case 7: effect.mMagnMax = value.toInt(); break; + default: throw std::runtime_error("Magic Effects subcolumn index out of range"); + } + + magic.mEffects.mList[subRowIndex] = effect; + + record.setModified (magic); + } + + virtual int getNestedColumnsCount(const Record& record) const + { + return 8; + } + + virtual int getNestedRowsCount(const Record& record) const + { + return static_cast(record.get().mEffects.mList.size()); + } + }; } #endif // CSM_WOLRD_IDADAPTERIMP_H From 8dab2f9b14f93509f9c54d1572bb983f372c0546 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 12 Apr 2015 07:46:32 +1000 Subject: [PATCH 704/740] Use human friendly strings in magic effects subtable. --- apps/opencs/model/world/columnimp.hpp | 7 +- apps/opencs/model/world/columns.cpp | 4 +- apps/opencs/model/world/columns.hpp | 2 +- apps/opencs/model/world/data.cpp | 16 +-- apps/opencs/model/world/idadapterimp.hpp | 143 +++++++++++++++++++++-- 5 files changed, 151 insertions(+), 21 deletions(-) diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 0ab33065b..210d63803 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -2286,13 +2286,16 @@ namespace CSMWorld struct NestedStringColumn : public NestableColumn { - NestedStringColumn (Columns::ColumnId id) + bool mIsEditable; + + NestedStringColumn (Columns::ColumnId id, bool isEditable = true) : NestableColumn (id, ColumnBase::Display_String, ColumnBase::Flag_Dialogue) + , mIsEditable(isEditable) {} virtual bool isEditable() const { - return true; + return mIsEditable; } }; diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index efe9a5116..fca16ec0b 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -242,8 +242,8 @@ namespace CSMWorld { ColumnId_FactionReaction, "Reaction"}, { ColumnId_EffectList, "Effects"}, - { ColumnId_EffectId, "ID"}, - { ColumnId_EffectAttribute, "Attrib"}, + { ColumnId_EffectId, "Effect"}, + //{ ColumnId_EffectAttribute, "Attrib"}, { ColumnId_EffectRange, "Range"}, { ColumnId_EffectArea, "Area"}, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 6b3791042..4f77ee23a 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -232,7 +232,7 @@ namespace CSMWorld ColumnId_EffectList = 214, ColumnId_EffectId = 215, - ColumnId_EffectAttribute = 216, + //ColumnId_EffectAttribute = 216, ColumnId_EffectRange = 217, ColumnId_EffectArea = 218, diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 86cf3bb44..538b240dc 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -195,15 +195,15 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mSpells.addColumn (spellEffect); mSpells.addAdapter (std::make_pair(spellEffect, new EffectsListAdapter ())); mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_EffectId)); + new NestedStringColumn (Columns::ColumnId_EffectId/*, false*/)); // false means no edit mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_Skill)); + new NestedStringColumn (Columns::ColumnId_Skill)); mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_EffectAttribute)); + new NestedStringColumn (Columns::ColumnId_Attribute)); // reuse attribute mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( new NestedIntegerColumn (Columns::ColumnId_EffectRange)); mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_EffectArea)); + new NestedStringColumn (Columns::ColumnId_EffectArea)); mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( new NestedIntegerColumn (Columns::ColumnId_Duration)); // reuse from light mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( @@ -269,15 +269,15 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mEnchantments.addColumn (enchantmentEffect); mEnchantments.addAdapter (std::make_pair(enchantmentEffect, new EffectsListAdapter ())); mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_EffectId)); + new NestedStringColumn (Columns::ColumnId_EffectId/*, false*/)); mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_Skill)); + new NestedStringColumn (Columns::ColumnId_Skill)); mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_EffectAttribute)); + new NestedStringColumn (Columns::ColumnId_Attribute)); // reuse attribute mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( new NestedIntegerColumn (Columns::ColumnId_EffectRange)); mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_EffectArea)); + new NestedStringColumn (Columns::ColumnId_EffectArea)); mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( new NestedIntegerColumn (Columns::ColumnId_Duration)); // reuse from light mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( diff --git a/apps/opencs/model/world/idadapterimp.hpp b/apps/opencs/model/world/idadapterimp.hpp index 219032dd3..d5bf83a2d 100644 --- a/apps/opencs/model/world/idadapterimp.hpp +++ b/apps/opencs/model/world/idadapterimp.hpp @@ -7,6 +7,9 @@ #include #include #include +#include // for converting magic effect id to string & back +#include // for converting skill names +#include // for converting attributes #include "idadapter.hpp" #include "nestedtablewrapper.hpp" @@ -651,10 +654,82 @@ namespace CSMWorld ESM::ENAMstruct effect = effectsList[subRowIndex]; switch (subColIndex) { - case 0: return effect.mEffectID; - case 1: return effect.mSkill; - case 2: return effect.mAttribute; - case 3: return effect.mRange; + case 0: + { + // indexToId() prepends "#d+" hence not so user friendly + QString effectId(ESM::MagicEffect::effectIdToString(effect.mEffectID).c_str()); + return effectId.remove(0, 7); // 7 == sizeof("sEffect") - 1 + } + case 1: + { + switch (effect.mSkill) + { + // see ESM::Skill::SkillEnum in + case ESM::Skill::Block: + case ESM::Skill::Armorer: + case ESM::Skill::MediumArmor: + case ESM::Skill::HeavyArmor: + case ESM::Skill::BluntWeapon: + case ESM::Skill::LongBlade: + case ESM::Skill::Axe: + case ESM::Skill::Spear: + case ESM::Skill::Athletics: + case ESM::Skill::Enchant: + case ESM::Skill::Destruction: + case ESM::Skill::Alteration: + case ESM::Skill::Illusion: + case ESM::Skill::Conjuration: + case ESM::Skill::Mysticism: + case ESM::Skill::Restoration: + case ESM::Skill::Alchemy: + case ESM::Skill::Unarmored: + case ESM::Skill::Security: + case ESM::Skill::Sneak: + case ESM::Skill::Acrobatics: + case ESM::Skill::LightArmor: + case ESM::Skill::ShortBlade: + case ESM::Skill::Marksman: + case ESM::Skill::Mercantile: + case ESM::Skill::Speechcraft: + case ESM::Skill::HandToHand: + { + return QString(ESM::Skill::sSkillNames[effect.mSkill].c_str()); + } + case -1: return QString("N/A"); + default: return QVariant(); + } + } + case 2: + { + switch (effect.mAttribute) + { + // see ESM::Attribute::AttributeID in + case ESM::Attribute::Strength: + case ESM::Attribute::Intelligence: + case ESM::Attribute::Willpower: + case ESM::Attribute::Agility: + case ESM::Attribute::Speed: + case ESM::Attribute::Endurance: + case ESM::Attribute::Personality: + case ESM::Attribute::Luck: + { + return QString(ESM::Attribute::sAttributeNames[effect.mAttribute].c_str()); + } + case -1: return QString("N/A"); + default: return QVariant(); + } + } + case 3: + { + switch (effect.mRange) + { + // see ESM::RangeType in + case ESM::RT_Self: return QString("Self"); + case ESM::RT_Touch: return QString("Touch"); + case ESM::RT_Target: return QString("Target"); + default: return QVariant(); + } + } case 4: return effect.mArea; case 5: return effect.mDuration; case 6: return effect.mMagnMin; @@ -676,10 +751,62 @@ namespace CSMWorld ESM::ENAMstruct effect = effectsList[subRowIndex]; switch (subColIndex) { - case 0: effect.mEffectID = static_cast(value.toInt()); break; - case 1: effect.mSkill = static_cast(value.toInt()); break; - case 2: effect.mAttribute = static_cast(value.toInt()); break; - case 3: effect.mRange = value.toInt(); break; + case 0: + { + effect.mEffectID = + ESM::MagicEffect::effectStringToId("sEffect"+value.toString().toStdString()); + break; + } + case 1: + { + std::string skillName = value.toString().toStdString(); + if ("N/A" == skillName) + { + effect.mSkill = -1; + break; + } + + for (unsigned int i = 0; i < ESM::Skill::Length; ++i) + { + if (ESM::Skill::sSkillNames[i] == skillName) + { + effect.mSkill = static_cast(i); + break; + } + } + break; + } + case 2: + { + std::string attr = value.toString().toStdString(); + if ("N/A" == attr) + { + effect.mAttribute = -1; + break; + } + + for (unsigned int i = 0; i < ESM::Attribute::Length; ++i) + { + if (ESM::Attribute::sAttributeNames[i] == attr) + { + effect.mAttribute = static_cast(i); + break; + } + } + break; + } + case 3: + { + std::string effectId = value.toString().toStdString(); + if (effectId == "Self") + effect.mRange = ESM::RT_Self; + else if (effectId == "Touch") + effect.mRange = ESM::RT_Touch; + else if (effectId == "Target") + effect.mRange = ESM::RT_Target; + // else leave unchanged + break; + } case 4: effect.mArea = value.toInt(); break; case 5: effect.mDuration = value.toInt(); break; case 6: effect.mMagnMin = value.toInt(); break; From 4b9c9bf09510b89aff9926522037252daafa9c28 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 12 Apr 2015 08:52:09 +1000 Subject: [PATCH 705/740] Simplify and relocate nested column definitions. --- apps/opencs/model/world/columnbase.cpp | 15 +++++-- apps/opencs/model/world/columnbase.hpp | 27 ++++++++++++ apps/opencs/model/world/columnimp.hpp | 49 ---------------------- apps/opencs/model/world/data.cpp | 58 +++++++++++++------------- 4 files changed, 68 insertions(+), 81 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 8d1985ff2..0d9eb1664 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -3,7 +3,7 @@ #include "columns.hpp" CSMWorld::ColumnBase::ColumnBase (int columnId, Display displayType, int flags) -: mColumnId (columnId), mDisplayType (displayType), mFlags (flags) + : mColumnId (columnId), mDisplayType (displayType), mFlags (flags) {} CSMWorld::ColumnBase::~ColumnBase() {} @@ -39,8 +39,7 @@ const CSMWorld::ColumnBase& CSMWorld::NestableColumn::nestedColumn(int subColumn CSMWorld::NestableColumn::NestableColumn(int columnId, CSMWorld::ColumnBase::Display displayType, int flag) : CSMWorld::ColumnBase(columnId, displayType, flag) -{ -} +{} CSMWorld::NestableColumn::~NestableColumn() { @@ -54,3 +53,13 @@ bool CSMWorld::NestableColumn::hasChildren() const { return !mNestedColumns.empty(); } + +CSMWorld::NestedChildColumn::NestedChildColumn (int id, + CSMWorld::ColumnBase::Display display, bool isEditable) + : NestableColumn (id, display, CSMWorld::ColumnBase::Flag_Dialogue) , mIsEditable(isEditable) +{} + +bool CSMWorld::NestedChildColumn::isEditable () const +{ + return mIsEditable; +} diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index c994ced15..dc3aae11a 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -165,6 +165,33 @@ namespace CSMWorld throw std::logic_error ("Column " + getTitle() + " is not editable"); } }; + + template + struct NestedParentColumn : public Column + { + NestedParentColumn (int id) : Column (id, Display_NestedHeader, Flag_Dialogue) + {} + + virtual QVariant get (const Record& record) const + { + return true; // required by IdTree::hasChildren() + } + + virtual bool isEditable() const + { + return true; + } + }; + + struct NestedChildColumn : public NestableColumn + { + NestedChildColumn (int id, Display display, bool isEditable = true); + + virtual bool isEditable() const; + + private: + bool mIsEditable; + }; } #endif diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 210d63803..68e7dd7b5 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -2264,55 +2264,6 @@ namespace CSMWorld return true; } }; - - template - struct NestedParentColumn : public Column - { - NestedParentColumn (Columns::ColumnId id) - : Column (id, ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue) - {} - - virtual QVariant get (const Record& record) const - { - return true; // required by IdTree::hasChildren() - } - - virtual bool isEditable() const - { - return true; - } - - }; - - struct NestedStringColumn : public NestableColumn - { - bool mIsEditable; - - NestedStringColumn (Columns::ColumnId id, bool isEditable = true) - : NestableColumn (id, ColumnBase::Display_String, ColumnBase::Flag_Dialogue) - , mIsEditable(isEditable) - {} - - virtual bool isEditable() const - { - return mIsEditable; - } - }; - - struct NestedIntegerColumn : public NestableColumn - { - bool mIsEditable; - - NestedIntegerColumn (Columns::ColumnId id, bool isEditable = true) - : NestableColumn (id, ColumnBase::Display_Integer, ColumnBase::Flag_Dialogue) - , mIsEditable(isEditable) - {} - - virtual bool isEditable() const - { - return mIsEditable; - } - }; } #endif diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 538b240dc..69e2b5aa8 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -114,9 +114,9 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mFactions.addColumn (reactions); mFactions.addAdapter (std::make_pair(reactions, new FactionReactionsAdapter ())); mFactions.getNestableColumn(mFactions.getColumns()-1)->addColumn( - new NestedStringColumn (Columns::ColumnId_Faction)); + new NestedChildColumn (Columns::ColumnId_Faction, ColumnBase::Display_String)); mFactions.getNestableColumn(mFactions.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_FactionReaction)); + new NestedChildColumn (Columns::ColumnId_FactionReaction, ColumnBase::Display_Integer)); mRaces.addColumn (new StringIdColumn); mRaces.addColumn (new RecordStateColumn); @@ -135,7 +135,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mRaces.addColumn (raceSpells); mRaces.addAdapter (std::make_pair(raceSpells, new SpellListAdapter ())); mRaces.getNestableColumn(mRaces.getColumns()-1)->addColumn( - new NestedStringColumn (Columns::ColumnId_SpellId)); + new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_String)); mSounds.addColumn (new StringIdColumn); mSounds.addColumn (new RecordStateColumn); @@ -162,9 +162,9 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mRegions.addColumn (soundList); mRegions.addAdapter (std::make_pair(soundList, new RegionSoundListAdapter ())); mRegions.getNestableColumn(mRegions.getColumns()-1)->addColumn( - new NestedStringColumn (Columns::ColumnId_SoundName)); + new NestedChildColumn (Columns::ColumnId_SoundName, ColumnBase::Display_String)); mRegions.getNestableColumn(mRegions.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_SoundChance)); + new NestedChildColumn (Columns::ColumnId_SoundChance, ColumnBase::Display_Integer)); mBirthsigns.addColumn (new StringIdColumn); mBirthsigns.addColumn (new RecordStateColumn); @@ -178,7 +178,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mBirthsigns.addColumn (birthSpells); mBirthsigns.addAdapter (std::make_pair(birthSpells, new SpellListAdapter ())); mBirthsigns.getNestableColumn(mBirthsigns.getColumns()-1)->addColumn( - new NestedStringColumn (Columns::ColumnId_SpellId)); + new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_String)); mSpells.addColumn (new StringIdColumn); mSpells.addColumn (new RecordStateColumn); @@ -195,21 +195,21 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mSpells.addColumn (spellEffect); mSpells.addAdapter (std::make_pair(spellEffect, new EffectsListAdapter ())); mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedStringColumn (Columns::ColumnId_EffectId/*, false*/)); // false means no edit + new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_String/*, false*/)); // false means no edit mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedStringColumn (Columns::ColumnId_Skill)); + new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_String)); mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedStringColumn (Columns::ColumnId_Attribute)); // reuse attribute + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_String)); // reuse attribute mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_EffectRange)); + new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_Integer)); mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedStringColumn (Columns::ColumnId_EffectArea)); + new NestedChildColumn (Columns::ColumnId_EffectArea, ColumnBase::Display_String)); mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_Duration)); // reuse from light + new NestedChildColumn (Columns::ColumnId_Duration, ColumnBase::Display_Integer)); // reuse from light mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_MinRange)); // reuse from sound + new NestedChildColumn (Columns::ColumnId_MinRange, ColumnBase::Display_Integer)); // reuse from sound mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_MaxRange)); // reuse from sound + new NestedChildColumn (Columns::ColumnId_MaxRange, ColumnBase::Display_Integer)); // reuse from sound mTopics.addColumn (new StringIdColumn); mTopics.addColumn (new RecordStateColumn); @@ -269,21 +269,21 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mEnchantments.addColumn (enchantmentEffect); mEnchantments.addAdapter (std::make_pair(enchantmentEffect, new EffectsListAdapter ())); mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedStringColumn (Columns::ColumnId_EffectId/*, false*/)); + new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_String/*, false*/)); mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedStringColumn (Columns::ColumnId_Skill)); + new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_String)); mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedStringColumn (Columns::ColumnId_Attribute)); // reuse attribute + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_String)); // reuse attribute mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_EffectRange)); + new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_Integer)); mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedStringColumn (Columns::ColumnId_EffectArea)); + new NestedChildColumn (Columns::ColumnId_EffectArea, ColumnBase::Display_String)); mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_Duration)); // reuse from light + new NestedChildColumn (Columns::ColumnId_Duration, ColumnBase::Display_Integer)); // reuse from light mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_MinRange)); // reuse from sound + new NestedChildColumn (Columns::ColumnId_MinRange, ColumnBase::Display_Integer)); // reuse from sound mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_MaxRange)); // reuse from sound + new NestedChildColumn (Columns::ColumnId_MaxRange, ColumnBase::Display_Integer)); // reuse from sound mBodyParts.addColumn (new StringIdColumn); mBodyParts.addColumn (new RecordStateColumn); @@ -339,24 +339,24 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc // new objects deleted in dtor of NestableColumn // WARNING: The order of the columns below are assumed in PathgridPointListAdapter mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_PathgridIndex, false)); + new NestedChildColumn (Columns::ColumnId_PathgridIndex, ColumnBase::Display_Integer, false)); mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_PathgridPosX)); + new NestedChildColumn (Columns::ColumnId_PathgridPosX, ColumnBase::Display_Integer)); mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_PathgridPosY)); + new NestedChildColumn (Columns::ColumnId_PathgridPosY, ColumnBase::Display_Integer)); mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_PathgridPosZ)); + new NestedChildColumn (Columns::ColumnId_PathgridPosZ, ColumnBase::Display_Integer)); NestedParentColumn *edgeList = new NestedParentColumn (Columns::ColumnId_PathgridEdges); mPathgrids.addColumn (edgeList); mPathgrids.addAdapter (std::make_pair(edgeList, new PathgridEdgeListAdapter ())); mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_PathgridEdgeIndex, false)); + new NestedChildColumn (Columns::ColumnId_PathgridEdgeIndex, ColumnBase::Display_Integer, false)); mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_PathgridEdge0)); + new NestedChildColumn (Columns::ColumnId_PathgridEdge0, ColumnBase::Display_Integer)); mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( - new NestedIntegerColumn (Columns::ColumnId_PathgridEdge1)); + new NestedChildColumn (Columns::ColumnId_PathgridEdge1, ColumnBase::Display_Integer)); mStartScripts.addColumn (new StringIdColumn); mStartScripts.addColumn (new RecordStateColumn); From 41b368a759ca70405ed7f7d4bdf9e6112393699b Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 12 Apr 2015 10:52:01 +1000 Subject: [PATCH 706/740] Moved templated code around a bit. --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/columnbase.hpp | 3 +- apps/opencs/model/world/data.cpp | 8 +- apps/opencs/model/world/idadapterimp.cpp | 457 +++++++++++++++++++++ apps/opencs/model/world/idadapterimp.hpp | 495 ++++------------------- 5 files changed, 534 insertions(+), 431 deletions(-) create mode 100644 apps/opencs/model/world/idadapterimp.cpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 8cf37da1d..bc0b964ae 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -25,7 +25,7 @@ opencs_units (model/world opencs_units_noqt (model/world universalid record commands columnbase scriptcontext cell refidcollection refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope - pathgrid landtexture land nestedtablewrapper nestedadapters nestedcollection + pathgrid landtexture land nestedtablewrapper nestedadapters nestedcollection idadapterimp ) opencs_hdrs_noqt (model/world diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index dc3aae11a..c7c8d3cd8 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -169,7 +169,8 @@ namespace CSMWorld template struct NestedParentColumn : public Column { - NestedParentColumn (int id) : Column (id, Display_NestedHeader, Flag_Dialogue) + NestedParentColumn (int id) : Column (id, + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue) {} virtual QVariant get (const Record& record) const diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 69e2b5aa8..db644affa 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -112,7 +112,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc NestedParentColumn *reactions = new NestedParentColumn (Columns::ColumnId_FactionReactions); mFactions.addColumn (reactions); - mFactions.addAdapter (std::make_pair(reactions, new FactionReactionsAdapter ())); + mFactions.addAdapter (std::make_pair(reactions, new FactionReactionsAdapter ())); mFactions.getNestableColumn(mFactions.getColumns()-1)->addColumn( new NestedChildColumn (Columns::ColumnId_Faction, ColumnBase::Display_String)); mFactions.getNestableColumn(mFactions.getColumns()-1)->addColumn( @@ -160,7 +160,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc NestedParentColumn *soundList = new NestedParentColumn (Columns::ColumnId_RegionSounds); mRegions.addColumn (soundList); - mRegions.addAdapter (std::make_pair(soundList, new RegionSoundListAdapter ())); + mRegions.addAdapter (std::make_pair(soundList, new RegionSoundListAdapter ())); mRegions.getNestableColumn(mRegions.getColumns()-1)->addColumn( new NestedChildColumn (Columns::ColumnId_SoundName, ColumnBase::Display_String)); mRegions.getNestableColumn(mRegions.getColumns()-1)->addColumn( @@ -335,7 +335,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc new NestedParentColumn (Columns::ColumnId_PathgridPoints); mPathgrids.addColumn (pointList); // new object deleted in dtor of SubCellCollection - mPathgrids.addAdapter (std::make_pair(pointList, new PathgridPointListAdapter ())); + mPathgrids.addAdapter (std::make_pair(pointList, new PathgridPointListAdapter ())); // new objects deleted in dtor of NestableColumn // WARNING: The order of the columns below are assumed in PathgridPointListAdapter mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( @@ -350,7 +350,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc NestedParentColumn *edgeList = new NestedParentColumn (Columns::ColumnId_PathgridEdges); mPathgrids.addColumn (edgeList); - mPathgrids.addAdapter (std::make_pair(edgeList, new PathgridEdgeListAdapter ())); + mPathgrids.addAdapter (std::make_pair(edgeList, new PathgridEdgeListAdapter ())); mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( new NestedChildColumn (Columns::ColumnId_PathgridEdgeIndex, ColumnBase::Display_Integer, false)); mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( diff --git a/apps/opencs/model/world/idadapterimp.cpp b/apps/opencs/model/world/idadapterimp.cpp new file mode 100644 index 000000000..95e68e09e --- /dev/null +++ b/apps/opencs/model/world/idadapterimp.cpp @@ -0,0 +1,457 @@ +#include "idadapterimp.hpp" + +#include +#include + +#include "idcollection.hpp" +#include "pathgrid.hpp" + +namespace CSMWorld +{ + PathgridPointListAdapter::PathgridPointListAdapter () {} + + void PathgridPointListAdapter::addNestedRow(Record& record, int position) const + { + Pathgrid pathgrid = record.get(); + + ESM::Pathgrid::PointList& points = pathgrid.mPoints; + + // blank row + ESM::Pathgrid::Point point; + point.mX = 0; + point.mY = 0; + point.mZ = 0; + point.mAutogenerated = 0; + point.mConnectionNum = 0; + point.mUnknown = 0; + + // inserting a point should trigger re-indexing of the edges + // + // FIXME: does not auto refresh edges table view + std::vector::iterator iter = pathgrid.mEdges.begin(); + for (;iter != pathgrid.mEdges.end(); ++iter) + { + if ((*iter).mV0 >= position) + (*iter).mV0++; + if ((*iter).mV1 >= position) + (*iter).mV1++; + } + + points.insert(points.begin()+position, point); + pathgrid.mData.mS2 += 1; // increment the number of points + + record.setModified (pathgrid); + } + + void PathgridPointListAdapter::removeNestedRow(Record& record, int rowToRemove) const + { + Pathgrid pathgrid = record.get(); + + ESM::Pathgrid::PointList& points = pathgrid.mPoints; + + if (rowToRemove < 0 || rowToRemove >= static_cast (points.size())) + throw std::runtime_error ("index out of range"); + + // deleting a point should trigger re-indexing of the edges + // dangling edges are not allowed and hence removed + // + // FIXME: does not auto refresh edges table view + std::vector::iterator iter = pathgrid.mEdges.begin(); + for (; iter != pathgrid.mEdges.end();) + { + if (((*iter).mV0 == rowToRemove) || ((*iter).mV1 == rowToRemove)) + iter = pathgrid.mEdges.erase(iter); + else + { + if ((*iter).mV0 > rowToRemove) + (*iter).mV0--; + + if ((*iter).mV1 > rowToRemove) + (*iter).mV1--; + + ++iter; + } + } + points.erase(points.begin()+rowToRemove); + pathgrid.mData.mS2 -= 1; // decrement the number of points + + record.setModified (pathgrid); + } + + void PathgridPointListAdapter::setNestedTable(Record& record, + const NestedTableWrapperBase& nestedTable) const + { + record.get().mPoints = + static_cast(nestedTable).mRecord.mPoints; + record.get().mData.mS2 = + static_cast(nestedTable).mRecord.mData.mS2; + // also update edges in case points were added/removed + record.get().mEdges = + static_cast(nestedTable).mRecord.mEdges; + } + + NestedTableWrapperBase* PathgridPointListAdapter::nestedTable(const Record& record) const + { + // deleted by dtor of NestedTableStoring + return new PathgridPointsWrap(record.get()); + } + + QVariant PathgridPointListAdapter::getNestedData(const Record& record, + int subRowIndex, int subColIndex) const + { + ESM::Pathgrid::Point point = record.get().mPoints[subRowIndex]; + switch (subColIndex) + { + case 0: return subRowIndex; + case 1: return point.mX; + case 2: return point.mY; + case 3: return point.mZ; + default: throw std::runtime_error("Pathgrid point subcolumn index out of range"); + } + } + + void PathgridPointListAdapter::setNestedData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const + { + Pathgrid pathgrid = record.get(); + ESM::Pathgrid::Point point = pathgrid.mPoints[subRowIndex]; + switch (subColIndex) + { + case 0: break; + case 1: point.mX = value.toInt(); break; + case 2: point.mY = value.toInt(); break; + case 3: point.mZ = value.toInt(); break; + default: throw std::runtime_error("Pathgrid point subcolumn index out of range"); + } + + pathgrid.mPoints[subRowIndex] = point; + + record.setModified (pathgrid); + } + + int PathgridPointListAdapter::getNestedColumnsCount(const Record& record) const + { + return 4; + } + + int PathgridPointListAdapter::getNestedRowsCount(const Record& record) const + { + return static_cast(record.get().mPoints.size()); + } + + PathgridEdgeListAdapter::PathgridEdgeListAdapter () {} + + // ToDo: seems to be auto-sorted in the dialog table display after insertion + void PathgridEdgeListAdapter::addNestedRow(Record& record, int position) const + { + Pathgrid pathgrid = record.get(); + + ESM::Pathgrid::EdgeList& edges = pathgrid.mEdges; + + // blank row + ESM::Pathgrid::Edge edge; + edge.mV0 = 0; + edge.mV1 = 0; + + // NOTE: inserting a blank edge does not really make sense, perhaps this should be a + // logic_error exception + // + // Currently the code assumes that the end user to know what he/she is doing. + // e.g. Edges come in pairs, from points a->b and b->a + edges.insert(edges.begin()+position, edge); + + record.setModified (pathgrid); + } + + void PathgridEdgeListAdapter::removeNestedRow(Record& record, int rowToRemove) const + { + Pathgrid pathgrid = record.get(); + + ESM::Pathgrid::EdgeList& edges = pathgrid.mEdges; + + if (rowToRemove < 0 || rowToRemove >= static_cast (edges.size())) + throw std::runtime_error ("index out of range"); + + edges.erase(edges.begin()+rowToRemove); + + record.setModified (pathgrid); + } + + void PathgridEdgeListAdapter::setNestedTable(Record& record, + const NestedTableWrapperBase& nestedTable) const + { + record.get().mEdges = + static_cast &>(nestedTable).mNestedTable; + } + + NestedTableWrapperBase* PathgridEdgeListAdapter::nestedTable(const Record& record) const + { + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper(record.get().mEdges); + } + + QVariant PathgridEdgeListAdapter::getNestedData(const Record& record, + int subRowIndex, int subColIndex) const + { + Pathgrid pathgrid = record.get(); + + if (subRowIndex < 0 || subRowIndex >= static_cast (pathgrid.mEdges.size())) + throw std::runtime_error ("index out of range"); + + ESM::Pathgrid::Edge edge = pathgrid.mEdges[subRowIndex]; + switch (subColIndex) + { + case 0: return subRowIndex; + case 1: return edge.mV0; + case 2: return edge.mV1; + default: throw std::runtime_error("Pathgrid edge subcolumn index out of range"); + } + } + + // ToDo: detect duplicates in mEdges + void PathgridEdgeListAdapter::setNestedData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const + { + Pathgrid pathgrid = record.get(); + + if (subRowIndex < 0 || subRowIndex >= static_cast (pathgrid.mEdges.size())) + throw std::runtime_error ("index out of range"); + + ESM::Pathgrid::Edge edge = pathgrid.mEdges[subRowIndex]; + switch (subColIndex) + { + case 0: break; + case 1: edge.mV0 = value.toInt(); break; + case 2: edge.mV1 = value.toInt(); break; + default: throw std::runtime_error("Pathgrid edge subcolumn index out of range"); + } + + pathgrid.mEdges[subRowIndex] = edge; + + record.setModified (pathgrid); + } + + int PathgridEdgeListAdapter::getNestedColumnsCount(const Record& record) const + { + return 3; + } + + int PathgridEdgeListAdapter::getNestedRowsCount(const Record& record) const + { + return static_cast(record.get().mEdges.size()); + } + + FactionReactionsAdapter::FactionReactionsAdapter () {} + + void FactionReactionsAdapter::addNestedRow(Record& record, int position) const + { + ESM::Faction faction = record.get(); + + std::map& reactions = faction.mReactions; + + // blank row + reactions.insert(std::make_pair("", 0)); + + record.setModified (faction); + } + + void FactionReactionsAdapter::removeNestedRow(Record& record, int rowToRemove) const + { + ESM::Faction faction = record.get(); + + std::map& reactions = faction.mReactions; + + if (rowToRemove < 0 || rowToRemove >= static_cast (reactions.size())) + throw std::runtime_error ("index out of range"); + + // FIXME: how to ensure that the map entries correspond to table indicies? + // WARNING: Assumed that the table view has the same order as std::map + std::map::iterator iter = reactions.begin(); + for(int i = 0; i < rowToRemove; ++i) + iter++; + reactions.erase(iter); + + record.setModified (faction); + } + + void FactionReactionsAdapter::setNestedTable(Record& record, + const NestedTableWrapperBase& nestedTable) const + { + record.get().mReactions = + static_cast >&>(nestedTable).mNestedTable; + } + + NestedTableWrapperBase* FactionReactionsAdapter::nestedTable(const Record& record) const + { + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(record.get().mReactions); + } + + QVariant FactionReactionsAdapter::getNestedData(const Record& record, + int subRowIndex, int subColIndex) const + { + ESM::Faction faction = record.get(); + + std::map& reactions = faction.mReactions; + + if (subRowIndex < 0 || subRowIndex >= static_cast (reactions.size())) + throw std::runtime_error ("index out of range"); + + // FIXME: how to ensure that the map entries correspond to table indicies? + // WARNING: Assumed that the table view has the same order as std::map + std::map::const_iterator iter = reactions.begin(); + for(int i = 0; i < subRowIndex; ++i) + iter++; + switch (subColIndex) + { + case 0: return QString((*iter).first.c_str()); + case 1: return (*iter).second; + default: throw std::runtime_error("Faction reactions subcolumn index out of range"); + } + } + + void FactionReactionsAdapter::setNestedData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const + { + ESM::Faction faction = record.get(); + + std::map& reactions = faction.mReactions; + + if (subRowIndex < 0 || subRowIndex >= static_cast (reactions.size())) + throw std::runtime_error ("index out of range"); + + // FIXME: how to ensure that the map entries correspond to table indicies? + // WARNING: Assumed that the table view has the same order as std::map + std::map::iterator iter = reactions.begin(); + for(int i = 0; i < subRowIndex; ++i) + iter++; + + std::string factionId = (*iter).first; + int reaction = (*iter).second; + + switch (subColIndex) + { + case 0: + { + reactions.erase(iter); + reactions.insert(std::make_pair(value.toString().toUtf8().constData(), reaction)); + break; + } + case 1: + { + reactions[factionId] = value.toInt(); + break; + } + default: throw std::runtime_error("Faction reactions subcolumn index out of range"); + } + + record.setModified (faction); + } + + int FactionReactionsAdapter::getNestedColumnsCount(const Record& record) const + { + return 2; + } + + int FactionReactionsAdapter::getNestedRowsCount(const Record& record) const + { + return static_cast(record.get().mReactions.size()); + } + + RegionSoundListAdapter::RegionSoundListAdapter () {} + + void RegionSoundListAdapter::addNestedRow(Record& record, int position) const + { + ESM::Region region = record.get(); + + std::vector& soundList = region.mSoundList; + + // blank row + ESM::Region::SoundRef soundRef; + soundRef.mSound.assign(""); + soundRef.mChance = 0; + + soundList.insert(soundList.begin()+position, soundRef); + + record.setModified (region); + } + + void RegionSoundListAdapter::removeNestedRow(Record& record, int rowToRemove) const + { + ESM::Region region = record.get(); + + std::vector& soundList = region.mSoundList; + + if (rowToRemove < 0 || rowToRemove >= static_cast (soundList.size())) + throw std::runtime_error ("index out of range"); + + soundList.erase(soundList.begin()+rowToRemove); + + record.setModified (region); + } + + void RegionSoundListAdapter::setNestedTable(Record& record, + const NestedTableWrapperBase& nestedTable) const + { + record.get().mSoundList = + static_cast >&>(nestedTable).mNestedTable; + } + + NestedTableWrapperBase* RegionSoundListAdapter::nestedTable(const Record& record) const + { + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(record.get().mSoundList); + } + + QVariant RegionSoundListAdapter::getNestedData(const Record& record, + int subRowIndex, int subColIndex) const + { + ESM::Region region = record.get(); + + std::vector& soundList = region.mSoundList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (soundList.size())) + throw std::runtime_error ("index out of range"); + + ESM::Region::SoundRef soundRef = soundList[subRowIndex]; + switch (subColIndex) + { + case 0: return QString(soundRef.mSound.toString().c_str()); + case 1: return soundRef.mChance; + default: throw std::runtime_error("Region sounds subcolumn index out of range"); + } + } + + void RegionSoundListAdapter::setNestedData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const + { + ESM::Region region = record.get(); + + std::vector& soundList = region.mSoundList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (soundList.size())) + throw std::runtime_error ("index out of range"); + + ESM::Region::SoundRef soundRef = soundList[subRowIndex]; + switch (subColIndex) + { + case 0: soundRef.mSound.assign(value.toString().toUtf8().constData()); break; + case 1: soundRef.mChance = static_cast(value.toInt()); break; + default: throw std::runtime_error("Region sounds subcolumn index out of range"); + } + + region.mSoundList[subRowIndex] = soundRef; + + record.setModified (region); + } + + int RegionSoundListAdapter::getNestedColumnsCount(const Record& record) const + { + return 2; + } + + int RegionSoundListAdapter::getNestedRowsCount(const Record& record) const + { + return static_cast(record.get().mSoundList.size()); + } +} diff --git a/apps/opencs/model/world/idadapterimp.hpp b/apps/opencs/model/world/idadapterimp.hpp index d5bf83a2d..effa0011c 100644 --- a/apps/opencs/model/world/idadapterimp.hpp +++ b/apps/opencs/model/world/idadapterimp.hpp @@ -4,8 +4,6 @@ #include #include -#include -#include #include #include // for converting magic effect id to string & back #include // for converting skill names @@ -14,482 +12,129 @@ #include "idadapter.hpp" #include "nestedtablewrapper.hpp" -namespace CSMWorld +namespace ESM { - template - class PathgridPointListAdapter : public NestedIdAdapter - { - public: - PathgridPointListAdapter () {} - - virtual void addNestedRow(Record& record, int position) const - { - ESXRecordT pathgrid = record.get(); - - ESM::Pathgrid::PointList& points = pathgrid.mPoints; - - // blank row - ESM::Pathgrid::Point point; - point.mX = 0; - point.mY = 0; - point.mZ = 0; - point.mAutogenerated = 0; - point.mConnectionNum = 0; - point.mUnknown = 0; - - // inserting a point should trigger re-indexing of the edges - // - // FIXME: undo does not restore edges table view - // FIXME: does not auto refresh edges table view - std::vector::iterator iter = pathgrid.mEdges.begin(); - for (;iter != pathgrid.mEdges.end(); ++iter) - { - if ((*iter).mV0 >= position) - (*iter).mV0++; - if ((*iter).mV1 >= position) - (*iter).mV1++; - } - - points.insert(points.begin()+position, point); - pathgrid.mData.mS2 += 1; // increment the number of points - - record.setModified (pathgrid); - } - - virtual void removeNestedRow(Record& record, int rowToRemove) const - { - ESXRecordT pathgrid = record.get(); - - ESM::Pathgrid::PointList& points = pathgrid.mPoints; - - if (rowToRemove < 0 || rowToRemove >= static_cast (points.size())) - throw std::runtime_error ("index out of range"); - - // deleting a point should trigger re-indexing of the edges - // dangling edges are not allowed and hence removed - // - // FIXME: undo does not restore edges table view - // FIXME: does not auto refresh edges table view - std::vector::iterator iter = pathgrid.mEdges.begin(); - for (; iter != pathgrid.mEdges.end();) - { - if (((*iter).mV0 == rowToRemove) || ((*iter).mV1 == rowToRemove)) - iter = pathgrid.mEdges.erase(iter); - else - { - if ((*iter).mV0 > rowToRemove) - (*iter).mV0--; - - if ((*iter).mV1 > rowToRemove) - (*iter).mV1--; - - ++iter; - } - } - points.erase(points.begin()+rowToRemove); - pathgrid.mData.mS2 -= 1; // decrement the number of points - - record.setModified (pathgrid); - } - - struct PathgridPointsWrap : public NestedTableWrapperBase - { - ESM::Pathgrid mRecord; - - PathgridPointsWrap(ESM::Pathgrid pathgrid) - : mRecord(pathgrid) {} - - virtual ~PathgridPointsWrap() {} - - virtual int size() const - { - return mRecord.mPoints.size(); // used in IdTree::setNestedTable() - } - }; - - virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const - { - record.get().mPoints = - static_cast(nestedTable).mRecord.mPoints; - record.get().mData.mS2 = - static_cast(nestedTable).mRecord.mData.mS2; - // also update edges in case points were added/removed - record.get().mEdges = - static_cast(nestedTable).mRecord.mEdges; - } - - virtual NestedTableWrapperBase* nestedTable(const Record& record) const - { - // deleted by dtor of NestedTableStoring - return new PathgridPointsWrap(record.get()); - } - - virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const - { - ESM::Pathgrid::Point point = record.get().mPoints[subRowIndex]; - switch (subColIndex) - { - case 0: return subRowIndex; - case 1: return point.mX; - case 2: return point.mY; - case 3: return point.mZ; - default: throw std::runtime_error("Pathgrid point subcolumn index out of range"); - } - } + struct Faction; + struct Region; +} - virtual void setNestedData(Record& record, const QVariant& value, - int subRowIndex, int subColIndex) const - { - ESXRecordT pathgrid = record.get(); - ESM::Pathgrid::Point point = pathgrid.mPoints[subRowIndex]; - switch (subColIndex) - { - case 0: break; - case 1: point.mX = value.toInt(); break; - case 2: point.mY = value.toInt(); break; - case 3: point.mZ = value.toInt(); break; - default: throw std::runtime_error("Pathgrid point subcolumn index out of range"); - } +namespace CSMWorld +{ + struct Pathgrid; - pathgrid.mPoints[subRowIndex] = point; + struct PathgridPointsWrap : public NestedTableWrapperBase + { + ESM::Pathgrid mRecord; - record.setModified (pathgrid); - } + PathgridPointsWrap(ESM::Pathgrid pathgrid) + : mRecord(pathgrid) {} - virtual int getNestedColumnsCount(const Record& record) const - { - return 4; - } + virtual ~PathgridPointsWrap() {} - virtual int getNestedRowsCount(const Record& record) const + virtual int size() const { - return static_cast(record.get().mPoints.size()); + return mRecord.mPoints.size(); // used in IdTree::setNestedTable() } }; - template - class PathgridEdgeListAdapter : public NestedIdAdapter + class PathgridPointListAdapter : public NestedIdAdapter { public: - PathgridEdgeListAdapter () {} - - // FIXME: seems to be auto-sorted in the dialog table display after insertion - virtual void addNestedRow(Record& record, int position) const - { - ESXRecordT pathgrid = record.get(); - - ESM::Pathgrid::EdgeList& edges = pathgrid.mEdges; - - // blank row - ESM::Pathgrid::Edge edge; - edge.mV0 = 0; - edge.mV1 = 0; - - // NOTE: inserting a blank edge does not really make sense, perhaps this should be a - // logic_error exception - // - // Currently the code assumes that the end user to know what he/she is doing. - // e.g. Edges come in pairs, from points a->b and b->a - edges.insert(edges.begin()+position, edge); - - record.setModified (pathgrid); - } - - virtual void removeNestedRow(Record& record, int rowToRemove) const - { - ESXRecordT pathgrid = record.get(); - - ESM::Pathgrid::EdgeList& edges = pathgrid.mEdges; - - if (rowToRemove < 0 || rowToRemove >= static_cast (edges.size())) - throw std::runtime_error ("index out of range"); - - edges.erase(edges.begin()+rowToRemove); - - record.setModified (pathgrid); - } + PathgridPointListAdapter (); - virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const - { - record.get().mEdges = - static_cast &>(nestedTable).mNestedTable; - } - - virtual NestedTableWrapperBase* nestedTable(const Record& record) const - { - // deleted by dtor of NestedTableStoring - return new NestedTableWrapper(record.get().mEdges); - } - - virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const - { - ESXRecordT pathgrid = record.get(); + virtual void addNestedRow(Record& record, int position) const; - if (subRowIndex < 0 || subRowIndex >= static_cast (pathgrid.mEdges.size())) - throw std::runtime_error ("index out of range"); - - ESM::Pathgrid::Edge edge = pathgrid.mEdges[subRowIndex]; - switch (subColIndex) - { - case 0: return subRowIndex; - case 1: return edge.mV0; - case 2: return edge.mV1; - default: throw std::runtime_error("Pathgrid edge subcolumn index out of range"); - } - } + virtual void removeNestedRow(Record& record, int rowToRemove) const; - // FIXME: detect duplicates in mEdges - virtual void setNestedData(Record& record, const QVariant& value, - int subRowIndex, int subColIndex) const - { - ESXRecordT pathgrid = record.get(); + virtual void setNestedTable(Record& record, + const NestedTableWrapperBase& nestedTable) const; - if (subRowIndex < 0 || subRowIndex >= static_cast (pathgrid.mEdges.size())) - throw std::runtime_error ("index out of range"); + virtual NestedTableWrapperBase* nestedTable(const Record& record) const; - ESM::Pathgrid::Edge edge = pathgrid.mEdges[subRowIndex]; - switch (subColIndex) - { - case 0: break; - case 1: edge.mV0 = value.toInt(); break; - case 2: edge.mV1 = value.toInt(); break; - default: throw std::runtime_error("Pathgrid edge subcolumn index out of range"); - } + virtual QVariant getNestedData(const Record& record, + int subRowIndex, int subColIndex) const; - pathgrid.mEdges[subRowIndex] = edge; + virtual void setNestedData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const; - record.setModified (pathgrid); - } + virtual int getNestedColumnsCount(const Record& record) const; - virtual int getNestedColumnsCount(const Record& record) const - { - return 3; - } - - virtual int getNestedRowsCount(const Record& record) const - { - return static_cast(record.get().mEdges.size()); - } + virtual int getNestedRowsCount(const Record& record) const; }; - template - class FactionReactionsAdapter : public NestedIdAdapter + class PathgridEdgeListAdapter : public NestedIdAdapter { public: - FactionReactionsAdapter () {} - - virtual void addNestedRow(Record& record, int position) const - { - ESXRecordT faction = record.get(); - - std::map& reactions = faction.mReactions; - - // blank row - reactions.insert(std::make_pair("", 0)); - - record.setModified (faction); - } - - virtual void removeNestedRow(Record& record, int rowToRemove) const - { - ESXRecordT faction = record.get(); - - std::map& reactions = faction.mReactions; - - if (rowToRemove < 0 || rowToRemove >= static_cast (reactions.size())) - throw std::runtime_error ("index out of range"); - - // FIXME: how to ensure that the map entries correspond to table indicies? - // WARNING: Assumed that the table view has the same order as std::map - std::map::iterator iter = reactions.begin(); - for(int i = 0; i < rowToRemove; ++i) - iter++; - reactions.erase(iter); - - record.setModified (faction); - } - - virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const - { - record.get().mReactions = - static_cast >&>(nestedTable).mNestedTable; - } - - virtual NestedTableWrapperBase* nestedTable(const Record& record) const - { - // deleted by dtor of NestedTableStoring - return new NestedTableWrapper >(record.get().mReactions); - } - - virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const - { - ESXRecordT faction = record.get(); - - std::map& reactions = faction.mReactions; - - if (subRowIndex < 0 || subRowIndex >= static_cast (reactions.size())) - throw std::runtime_error ("index out of range"); - - // FIXME: how to ensure that the map entries correspond to table indicies? - // WARNING: Assumed that the table view has the same order as std::map - std::map::const_iterator iter = reactions.begin(); - for(int i = 0; i < subRowIndex; ++i) - iter++; - switch (subColIndex) - { - case 0: return QString((*iter).first.c_str()); - case 1: return (*iter).second; - default: throw std::runtime_error("Faction reactions subcolumn index out of range"); - } - } + PathgridEdgeListAdapter (); - virtual void setNestedData(Record& record, const QVariant& value, - int subRowIndex, int subColIndex) const - { - ESXRecordT faction = record.get(); + virtual void addNestedRow(Record& record, int position) const; - std::map& reactions = faction.mReactions; + virtual void removeNestedRow(Record& record, int rowToRemove) const; - if (subRowIndex < 0 || subRowIndex >= static_cast (reactions.size())) - throw std::runtime_error ("index out of range"); + virtual void setNestedTable(Record& record, + const NestedTableWrapperBase& nestedTable) const; - // FIXME: how to ensure that the map entries correspond to table indicies? - // WARNING: Assumed that the table view has the same order as std::map - std::map::iterator iter = reactions.begin(); - for(int i = 0; i < subRowIndex; ++i) - iter++; + virtual NestedTableWrapperBase* nestedTable(const Record& record) const; - std::string factionId = (*iter).first; - int reaction = (*iter).second; - - switch (subColIndex) - { - case 0: - { - reactions.erase(iter); - reactions.insert(std::make_pair(value.toString().toUtf8().constData(), reaction)); - break; - } - case 1: - { - reactions[factionId] = value.toInt(); - break; - } - default: throw std::runtime_error("Faction reactions subcolumn index out of range"); - } + virtual QVariant getNestedData(const Record& record, + int subRowIndex, int subColIndex) const; - record.setModified (faction); - } + virtual void setNestedData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const; - virtual int getNestedColumnsCount(const Record& record) const - { - return 2; - } + virtual int getNestedColumnsCount(const Record& record) const; - virtual int getNestedRowsCount(const Record& record) const - { - return static_cast(record.get().mReactions.size()); - } + virtual int getNestedRowsCount(const Record& record) const; }; - template - class RegionSoundListAdapter : public NestedIdAdapter + class FactionReactionsAdapter : public NestedIdAdapter { public: - RegionSoundListAdapter () {} - - virtual void addNestedRow(Record& record, int position) const - { - ESXRecordT region = record.get(); - - std::vector& soundList = region.mSoundList; + FactionReactionsAdapter (); - // blank row - typename ESXRecordT::SoundRef soundRef; - soundRef.mSound.assign(""); - soundRef.mChance = 0; - - soundList.insert(soundList.begin()+position, soundRef); - - record.setModified (region); - } - - virtual void removeNestedRow(Record& record, int rowToRemove) const - { - ESXRecordT region = record.get(); + virtual void addNestedRow(Record& record, int position) const; - std::vector& soundList = region.mSoundList; + virtual void removeNestedRow(Record& record, int rowToRemove) const; - if (rowToRemove < 0 || rowToRemove >= static_cast (soundList.size())) - throw std::runtime_error ("index out of range"); - - soundList.erase(soundList.begin()+rowToRemove); - - record.setModified (region); - } + virtual void setNestedTable(Record& record, + const NestedTableWrapperBase& nestedTable) const; - virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const - { - record.get().mSoundList = - static_cast >&>(nestedTable).mNestedTable; - } + virtual NestedTableWrapperBase* nestedTable(const Record& record) const; - virtual NestedTableWrapperBase* nestedTable(const Record& record) const - { - // deleted by dtor of NestedTableStoring - return new NestedTableWrapper >(record.get().mSoundList); - } + virtual QVariant getNestedData(const Record& record, + int subRowIndex, int subColIndex) const; - virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const - { - ESXRecordT region = record.get(); + virtual void setNestedData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const; - std::vector& soundList = region.mSoundList; + virtual int getNestedColumnsCount(const Record& record) const; - if (subRowIndex < 0 || subRowIndex >= static_cast (soundList.size())) - throw std::runtime_error ("index out of range"); + virtual int getNestedRowsCount(const Record& record) const; + }; - typename ESXRecordT::SoundRef soundRef = soundList[subRowIndex]; - switch (subColIndex) - { - case 0: return QString(soundRef.mSound.toString().c_str()); - case 1: return soundRef.mChance; - default: throw std::runtime_error("Region sounds subcolumn index out of range"); - } - } + class RegionSoundListAdapter : public NestedIdAdapter + { + public: + RegionSoundListAdapter (); - virtual void setNestedData(Record& record, const QVariant& value, - int subRowIndex, int subColIndex) const - { - ESXRecordT region = record.get(); + virtual void addNestedRow(Record& record, int position) const; - std::vector& soundList = region.mSoundList; + virtual void removeNestedRow(Record& record, int rowToRemove) const; - if (subRowIndex < 0 || subRowIndex >= static_cast (soundList.size())) - throw std::runtime_error ("index out of range"); + virtual void setNestedTable(Record& record, + const NestedTableWrapperBase& nestedTable) const; - typename ESXRecordT::SoundRef soundRef = soundList[subRowIndex]; - switch (subColIndex) - { - case 0: soundRef.mSound.assign(value.toString().toUtf8().constData()); break; - case 1: soundRef.mChance = static_cast(value.toInt()); break; - default: throw std::runtime_error("Region sounds subcolumn index out of range"); - } + virtual NestedTableWrapperBase* nestedTable(const Record& record) const; - region.mSoundList[subRowIndex] = soundRef; + virtual QVariant getNestedData(const Record& record, + int subRowIndex, int subColIndex) const; - record.setModified (region); - } + virtual void setNestedData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const; - virtual int getNestedColumnsCount(const Record& record) const - { - return 2; - } + virtual int getNestedColumnsCount(const Record& record) const; - virtual int getNestedRowsCount(const Record& record) const - { - return static_cast(record.get().mSoundList.size()); - } + virtual int getNestedRowsCount(const Record& record) const; }; template From ef84e553beb94cd6ee56ff270dca6a182cc34331 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 12 Apr 2015 13:48:23 +1000 Subject: [PATCH 707/740] Renamed some stuff. --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/data.cpp | 166 +++++++++--------- ...adapterimp.cpp => nestedcoladapterimp.cpp} | 2 +- ...adapterimp.hpp => nestedcoladapterimp.hpp} | 20 +-- ...{idadapter.hpp => nestedcolumnadapter.hpp} | 17 +- .../opencs/model/world/nestedidcollection.hpp | 21 ++- 6 files changed, 114 insertions(+), 114 deletions(-) rename apps/opencs/model/world/{idadapterimp.cpp => nestedcoladapterimp.cpp} (99%) rename apps/opencs/model/world/{idadapterimp.hpp => nestedcoladapterimp.hpp} (96%) rename apps/opencs/model/world/{idadapter.hpp => nestedcolumnadapter.hpp} (77%) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index bc0b964ae..babd3363f 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -25,7 +25,7 @@ opencs_units (model/world opencs_units_noqt (model/world universalid record commands columnbase scriptcontext cell refidcollection refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope - pathgrid landtexture land nestedtablewrapper nestedadapters nestedcollection idadapterimp + pathgrid landtexture land nestedtablewrapper nestedadapters nestedcollection nestedcoladapterimp ) opencs_hdrs_noqt (model/world diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index db644affa..d7280e354 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -18,7 +18,7 @@ #include "columns.hpp" #include "resourcesmanager.hpp" #include "resourcetable.hpp" -#include "idadapterimp.hpp" +#include "nestedcoladapterimp.hpp" void CSMWorld::Data::addModel (QAbstractItemModel *model, UniversalId::Type type, bool update) { @@ -64,6 +64,8 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc : mEncoder (encoding), mPathgrids (mCells), mRefs (mCells), mResourcesManager (resourcesManager), mReader (0), mDialogue (0), mReaderIndex(0) { + int index = 0; + mGlobals.addColumn (new StringIdColumn); mGlobals.addColumn (new RecordStateColumn); mGlobals.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Global)); @@ -109,14 +111,13 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc for (int i=0; i<7; ++i) mFactions.addColumn (new SkillsColumn (i)); // Faction Reactions - NestedParentColumn *reactions = - new NestedParentColumn (Columns::ColumnId_FactionReactions); - mFactions.addColumn (reactions); - mFactions.addAdapter (std::make_pair(reactions, new FactionReactionsAdapter ())); - mFactions.getNestableColumn(mFactions.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_Faction, ColumnBase::Display_String)); - mFactions.getNestableColumn(mFactions.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_FactionReaction, ColumnBase::Display_Integer)); + mFactions.addColumn (new NestedParentColumn (Columns::ColumnId_FactionReactions)); + index = mFactions.getColumns()-1; + mFactions.addAdapter (std::make_pair(&mFactions.getColumn(index), new FactionReactionsAdapter ())); + mFactions.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_Faction, ColumnBase::Display_String)); + mFactions.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_FactionReaction, ColumnBase::Display_Integer)); mRaces.addColumn (new StringIdColumn); mRaces.addColumn (new RecordStateColumn); @@ -130,12 +131,11 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mRaces.addColumn (new WeightHeightColumn (false, true)); mRaces.addColumn (new WeightHeightColumn (false, false)); // Race spells - NestedParentColumn *raceSpells = - new NestedParentColumn (Columns::ColumnId_SpellList); - mRaces.addColumn (raceSpells); - mRaces.addAdapter (std::make_pair(raceSpells, new SpellListAdapter ())); - mRaces.getNestableColumn(mRaces.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_String)); + mRaces.addColumn (new NestedParentColumn (Columns::ColumnId_SpellList)); + index = mRaces.getColumns()-1; + mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new SpellListAdapter ())); + mRaces.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_String)); mSounds.addColumn (new StringIdColumn); mSounds.addColumn (new RecordStateColumn); @@ -157,14 +157,13 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mRegions.addColumn (new MapColourColumn); mRegions.addColumn (new SleepListColumn); // Region Sounds - NestedParentColumn *soundList = - new NestedParentColumn (Columns::ColumnId_RegionSounds); - mRegions.addColumn (soundList); - mRegions.addAdapter (std::make_pair(soundList, new RegionSoundListAdapter ())); - mRegions.getNestableColumn(mRegions.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_SoundName, ColumnBase::Display_String)); - mRegions.getNestableColumn(mRegions.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_SoundChance, ColumnBase::Display_Integer)); + mRegions.addColumn (new NestedParentColumn (Columns::ColumnId_RegionSounds)); + index = mRegions.getColumns()-1; + mRegions.addAdapter (std::make_pair(&mRegions.getColumn(index), new RegionSoundListAdapter ())); + mRegions.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_SoundName, ColumnBase::Display_String)); + mRegions.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_SoundChance, ColumnBase::Display_Integer)); mBirthsigns.addColumn (new StringIdColumn); mBirthsigns.addColumn (new RecordStateColumn); @@ -173,12 +172,12 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mBirthsigns.addColumn (new TextureColumn); mBirthsigns.addColumn (new DescriptionColumn); // Birthsign spells - NestedParentColumn *birthSpells = - new NestedParentColumn (Columns::ColumnId_SpellList); - mBirthsigns.addColumn (birthSpells); - mBirthsigns.addAdapter (std::make_pair(birthSpells, new SpellListAdapter ())); - mBirthsigns.getNestableColumn(mBirthsigns.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_String)); + mBirthsigns.addColumn (new NestedParentColumn (Columns::ColumnId_SpellList)); + index = mBirthsigns.getColumns()-1; + mBirthsigns.addAdapter (std::make_pair(&mBirthsigns.getColumn(index), + new SpellListAdapter ())); + mBirthsigns.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_String)); mSpells.addColumn (new StringIdColumn); mSpells.addColumn (new RecordStateColumn); @@ -190,26 +189,25 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mSpells.addColumn (new FlagColumn (Columns::ColumnId_StarterSpell, 0x2)); mSpells.addColumn (new FlagColumn (Columns::ColumnId_AlwaysSucceeds, 0x4)); // Spell effects - NestedParentColumn *spellEffect = - new NestedParentColumn (Columns::ColumnId_EffectList); - mSpells.addColumn (spellEffect); - mSpells.addAdapter (std::make_pair(spellEffect, new EffectsListAdapter ())); - mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_String/*, false*/)); // false means no edit - mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_String)); - mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_String)); // reuse attribute - mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_Integer)); - mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_EffectArea, ColumnBase::Display_String)); - mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_Duration, ColumnBase::Display_Integer)); // reuse from light - mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_MinRange, ColumnBase::Display_Integer)); // reuse from sound - mSpells.getNestableColumn(mSpells.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_MaxRange, ColumnBase::Display_Integer)); // reuse from sound + mSpells.addColumn (new NestedParentColumn (Columns::ColumnId_EffectList)); + index = mSpells.getColumns()-1; + mSpells.addAdapter (std::make_pair(&mSpells.getColumn(index), new EffectsListAdapter ())); + mSpells.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_String/*, false*/)); // false means no edit + mSpells.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_String)); + mSpells.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_String)); // reuse attribute + mSpells.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_Integer)); + mSpells.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_EffectArea, ColumnBase::Display_String)); + mSpells.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_Duration, ColumnBase::Display_Integer)); // reuse from light + mSpells.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_MinRange, ColumnBase::Display_Integer)); // reuse from sound + mSpells.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_MaxRange, ColumnBase::Display_Integer)); // reuse from sound mTopics.addColumn (new StringIdColumn); mTopics.addColumn (new RecordStateColumn); @@ -264,26 +262,26 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mEnchantments.addColumn (new ChargesColumn2); mEnchantments.addColumn (new AutoCalcColumn); // Enchantment effects - NestedParentColumn *enchantmentEffect = - new NestedParentColumn (Columns::ColumnId_EffectList); - mEnchantments.addColumn (enchantmentEffect); - mEnchantments.addAdapter (std::make_pair(enchantmentEffect, new EffectsListAdapter ())); - mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_String/*, false*/)); - mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_String)); - mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_String)); // reuse attribute - mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_Integer)); - mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_EffectArea, ColumnBase::Display_String)); - mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_Duration, ColumnBase::Display_Integer)); // reuse from light - mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_MinRange, ColumnBase::Display_Integer)); // reuse from sound - mEnchantments.getNestableColumn(mEnchantments.getColumns()-1)->addColumn( - new NestedChildColumn (Columns::ColumnId_MaxRange, ColumnBase::Display_Integer)); // reuse from sound + mEnchantments.addColumn (new NestedParentColumn (Columns::ColumnId_EffectList)); + index = mEnchantments.getColumns()-1; + mEnchantments.addAdapter (std::make_pair(&mEnchantments.getColumn(index), + new EffectsListAdapter ())); + mEnchantments.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_String/*, false*/)); + mEnchantments.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_String)); + mEnchantments.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_String)); // reuse attribute + mEnchantments.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_Integer)); + mEnchantments.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_EffectArea, ColumnBase::Display_String)); + mEnchantments.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_Duration, ColumnBase::Display_Integer)); // reuse from light + mEnchantments.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_MinRange, ColumnBase::Display_Integer)); // reuse from sound + mEnchantments.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_MaxRange, ColumnBase::Display_Integer)); // reuse from sound mBodyParts.addColumn (new StringIdColumn); mBodyParts.addColumn (new RecordStateColumn); @@ -331,31 +329,29 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mPathgrids.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Pathgrid)); // new object deleted in dtor of Collection - NestedParentColumn *pointList = - new NestedParentColumn (Columns::ColumnId_PathgridPoints); - mPathgrids.addColumn (pointList); - // new object deleted in dtor of SubCellCollection - mPathgrids.addAdapter (std::make_pair(pointList, new PathgridPointListAdapter ())); + mPathgrids.addColumn (new NestedParentColumn (Columns::ColumnId_PathgridPoints)); + index = mPathgrids.getColumns()-1; + // new object deleted in dtor of NestedCollection + mPathgrids.addAdapter (std::make_pair(&mPathgrids.getColumn(index), new PathgridPointListAdapter ())); // new objects deleted in dtor of NestableColumn // WARNING: The order of the columns below are assumed in PathgridPointListAdapter - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( + mPathgrids.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_PathgridIndex, ColumnBase::Display_Integer, false)); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( + mPathgrids.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_PathgridPosX, ColumnBase::Display_Integer)); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( + mPathgrids.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_PathgridPosY, ColumnBase::Display_Integer)); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( + mPathgrids.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_PathgridPosZ, ColumnBase::Display_Integer)); - NestedParentColumn *edgeList = - new NestedParentColumn (Columns::ColumnId_PathgridEdges); - mPathgrids.addColumn (edgeList); - mPathgrids.addAdapter (std::make_pair(edgeList, new PathgridEdgeListAdapter ())); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( + mPathgrids.addColumn (new NestedParentColumn (Columns::ColumnId_PathgridEdges)); + index = mPathgrids.getColumns()-1; + mPathgrids.addAdapter (std::make_pair(&mPathgrids.getColumn(index), new PathgridEdgeListAdapter ())); + mPathgrids.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_PathgridEdgeIndex, ColumnBase::Display_Integer, false)); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( + mPathgrids.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_PathgridEdge0, ColumnBase::Display_Integer)); - mPathgrids.getNestableColumn(mPathgrids.getColumns()-1)->addColumn( + mPathgrids.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_PathgridEdge1, ColumnBase::Display_Integer)); mStartScripts.addColumn (new StringIdColumn); diff --git a/apps/opencs/model/world/idadapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp similarity index 99% rename from apps/opencs/model/world/idadapterimp.cpp rename to apps/opencs/model/world/nestedcoladapterimp.cpp index 95e68e09e..2bf1ffadd 100644 --- a/apps/opencs/model/world/idadapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -1,4 +1,4 @@ -#include "idadapterimp.hpp" +#include "nestedcoladapterimp.hpp" #include #include diff --git a/apps/opencs/model/world/idadapterimp.hpp b/apps/opencs/model/world/nestedcoladapterimp.hpp similarity index 96% rename from apps/opencs/model/world/idadapterimp.hpp rename to apps/opencs/model/world/nestedcoladapterimp.hpp index effa0011c..7fed74868 100644 --- a/apps/opencs/model/world/idadapterimp.hpp +++ b/apps/opencs/model/world/nestedcoladapterimp.hpp @@ -1,5 +1,5 @@ -#ifndef CSM_WOLRD_IDADAPTERIMP_H -#define CSM_WOLRD_IDADAPTERIMP_H +#ifndef CSM_WOLRD_NESTEDCOLADAPTERIMP_H +#define CSM_WOLRD_NESTEDCOLADAPTERIMP_H #include @@ -9,7 +9,7 @@ #include // for converting skill names #include // for converting attributes -#include "idadapter.hpp" +#include "nestedcolumnadapter.hpp" #include "nestedtablewrapper.hpp" namespace ESM @@ -37,7 +37,7 @@ namespace CSMWorld } }; - class PathgridPointListAdapter : public NestedIdAdapter + class PathgridPointListAdapter : public NestedColumnAdapter { public: PathgridPointListAdapter (); @@ -62,7 +62,7 @@ namespace CSMWorld virtual int getNestedRowsCount(const Record& record) const; }; - class PathgridEdgeListAdapter : public NestedIdAdapter + class PathgridEdgeListAdapter : public NestedColumnAdapter { public: PathgridEdgeListAdapter (); @@ -87,7 +87,7 @@ namespace CSMWorld virtual int getNestedRowsCount(const Record& record) const; }; - class FactionReactionsAdapter : public NestedIdAdapter + class FactionReactionsAdapter : public NestedColumnAdapter { public: FactionReactionsAdapter (); @@ -112,7 +112,7 @@ namespace CSMWorld virtual int getNestedRowsCount(const Record& record) const; }; - class RegionSoundListAdapter : public NestedIdAdapter + class RegionSoundListAdapter : public NestedColumnAdapter { public: RegionSoundListAdapter (); @@ -138,7 +138,7 @@ namespace CSMWorld }; template - class SpellListAdapter : public NestedIdAdapter + class SpellListAdapter : public NestedColumnAdapter { public: SpellListAdapter () {} @@ -234,7 +234,7 @@ namespace CSMWorld }; template - class EffectsListAdapter : public NestedIdAdapter + class EffectsListAdapter : public NestedColumnAdapter { public: EffectsListAdapter () {} @@ -476,4 +476,4 @@ namespace CSMWorld }; } -#endif // CSM_WOLRD_IDADAPTERIMP_H +#endif // CSM_WOLRD_NESTEDCOLADAPTERIMP_H diff --git a/apps/opencs/model/world/idadapter.hpp b/apps/opencs/model/world/nestedcolumnadapter.hpp similarity index 77% rename from apps/opencs/model/world/idadapter.hpp rename to apps/opencs/model/world/nestedcolumnadapter.hpp index 84ef2d1f8..e7e66ed4d 100644 --- a/apps/opencs/model/world/idadapter.hpp +++ b/apps/opencs/model/world/nestedcolumnadapter.hpp @@ -1,7 +1,5 @@ -#ifndef CSM_WOLRD_IDADAPTER_H -#define CSM_WOLRD_IDADAPTER_H - -#include "record.hpp" +#ifndef CSM_WOLRD_NESTEDCOLUMNADAPTER_H +#define CSM_WOLRD_NESTEDCOLUMNADAPTER_H class QVariant; @@ -9,14 +7,17 @@ namespace CSMWorld { struct NestedTableWrapperBase; + template + struct Record; + template - class NestedIdAdapter + class NestedColumnAdapter { public: - NestedIdAdapter() {} + NestedColumnAdapter() {} - virtual ~NestedIdAdapter() {} + virtual ~NestedColumnAdapter() {} virtual void addNestedRow(Record& record, int position) const = 0; @@ -36,4 +37,4 @@ namespace CSMWorld }; } -#endif // CSM_WOLRD_IDADAPTER_H +#endif // CSM_WOLRD_NESTEDCOLUMNADAPTER_H diff --git a/apps/opencs/model/world/nestedidcollection.hpp b/apps/opencs/model/world/nestedidcollection.hpp index c7e840955..0cf51b9d8 100644 --- a/apps/opencs/model/world/nestedidcollection.hpp +++ b/apps/opencs/model/world/nestedidcollection.hpp @@ -5,7 +5,7 @@ #include #include "nestedcollection.hpp" -#include "idadapterimp.hpp" +#include "nestedcoladapterimp.hpp" namespace ESM { @@ -23,9 +23,9 @@ namespace CSMWorld template > class NestedIdCollection : public IdCollection, public NestedCollection { - std::map* > mAdapters; + std::map* > mAdapters; - const NestedIdAdapter& getAdapter(const ColumnBase &column) const; + const NestedColumnAdapter& getAdapter(const ColumnBase &column) const; public: @@ -51,7 +51,7 @@ namespace CSMWorld // this method is inherited from NestedCollection, not from Collection virtual NestableColumn *getNestableColumn(int column); - void addAdapter(std::pair* > adapter); + void addAdapter(std::pair* > adapter); }; template @@ -61,21 +61,24 @@ namespace CSMWorld template NestedIdCollection::~NestedIdCollection() { - for (typename std::map* >::iterator iter (mAdapters.begin()); - iter!=mAdapters.end(); ++iter) + for (typename std::map* >::iterator + iter (mAdapters.begin()); iter!=mAdapters.end(); ++iter) + { delete (*iter).second; + } } template - void NestedIdCollection::addAdapter(std::pair* > adapter) + void NestedIdCollection::addAdapter(std::pair* > adapter) { mAdapters.insert(adapter); } template - const NestedIdAdapter& NestedIdCollection::getAdapter(const ColumnBase &column) const + const NestedColumnAdapter& NestedIdCollection::getAdapter(const ColumnBase &column) const { - typename std::map* >::const_iterator iter = + typename std::map* >::const_iterator iter = mAdapters.find (&column); if (iter==mAdapters.end()) From 25261a60e58557c8beb749550008bda42edcad1a Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 12 Apr 2015 18:29:42 +1000 Subject: [PATCH 708/740] Add potion magic effects table to dialogue subview. Integration of the adapters to RefIdCollection is incomplete. --- apps/opencs/model/world/refidadapter.hpp | 22 +++-- apps/opencs/model/world/refidadapterimp.cpp | 10 ++- apps/opencs/model/world/refidadapterimp.hpp | 93 +++++++++++++++++++- apps/opencs/model/world/refidcollection.cpp | 95 ++++++++++++++++++++- apps/opencs/model/world/refidcollection.hpp | 6 ++ 5 files changed, 213 insertions(+), 13 deletions(-) diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index 1a3f2700e..f80ce7ab3 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -45,7 +45,7 @@ namespace CSMWorld virtual std::string getId (const RecordBase& record) const = 0; - virtual void setId(RecordBase& record, const std::string& id) = 0; // FIXME: used by RefIdCollection::cloneRecord() + virtual void setId(RecordBase& record, const std::string& id) = 0; // used by RefIdCollection::cloneRecord() }; class NestedRefIdAdapterBase @@ -55,23 +55,27 @@ namespace CSMWorld virtual ~NestedRefIdAdapterBase(); - virtual void setNestedData (const RefIdColumn *column, RefIdData& data, int row, - const QVariant& value, int subRowIndex, int subColIndex) const = 0; + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const = 0; - virtual QVariant getNestedData (const RefIdColumn *column, const RefIdData& data, - int index, int subRowIndex, int subColIndex) const = 0; + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const = 0; virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const = 0; virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const = 0; - virtual void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const = 0; + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const = 0; - virtual void addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const = 0; + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const = 0; - virtual void setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const = 0; + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const = 0; - virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, const RefIdData& data, int index) const = 0; + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const = 0; }; class NestedRefIdAdapter : public NestedRefIdAdapterBase diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index b2a08e71c..426bfe3d1 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -7,10 +7,13 @@ #include #include "nestedtablewrapper.hpp" -CSMWorld::PotionRefIdAdapter::PotionRefIdAdapter (const InventoryColumns& columns, +CSMWorld::PotionColumns::PotionColumns (const InventoryColumns& columns) +: InventoryColumns (columns) {} + +CSMWorld::PotionRefIdAdapter::PotionRefIdAdapter (const PotionColumns& columns, const RefIdColumn *autoCalc) : InventoryRefIdAdapter (UniversalId::Type_Potion, columns), - mAutoCalc (autoCalc) + mAutoCalc (autoCalc), mColumns(columns) {} QVariant CSMWorld::PotionRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, @@ -22,6 +25,9 @@ QVariant CSMWorld::PotionRefIdAdapter::getData (const RefIdColumn *column, const if (column==mAutoCalc) return record.get().mData.mAutoCalc!=0; + if (column==mColumns.mEffects) + return true; // Required to show nested tables in dialogue subview + return InventoryRefIdAdapter::getData (column, data, index); } diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 7296b6c68..b12d0cb6f 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -6,6 +6,7 @@ #include #include +#include #include #include "record.hpp" @@ -315,13 +316,21 @@ namespace CSMWorld record.setModified(record2); } + struct PotionColumns : public InventoryColumns + { + const RefIdColumn *mEffects; + + PotionColumns (const InventoryColumns& columns); + }; + class PotionRefIdAdapter : public InventoryRefIdAdapter { + PotionColumns mColumns; const RefIdColumn *mAutoCalc; public: - PotionRefIdAdapter (const InventoryColumns& columns, const RefIdColumn *autoCalc); + PotionRefIdAdapter (const PotionColumns& columns, const RefIdColumn *autoCalc); virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; @@ -828,6 +837,88 @@ namespace CSMWorld const QVariant& value) const; ///< If the data type does not match an exception is thrown. }; + + class NestedRefIdAdapterBase; + + template + class EffectsListAdapter; + + template + class EffectsRefIdAdapter : public EffectsListAdapter, public NestedRefIdAdapterBase + { + UniversalId::Type mType; + + // not implemented + EffectsRefIdAdapter (const EffectsRefIdAdapter&); + EffectsRefIdAdapter& operator= (const EffectsRefIdAdapter&); + + public: + + EffectsRefIdAdapter(UniversalId::Type type) :mType(type) {} + + virtual ~EffectsRefIdAdapter() {} + + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + EffectsListAdapter::addNestedRow(record, position); + } + + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + EffectsListAdapter::removeNestedRow(record, rowToRemove); + } + + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + EffectsListAdapter::setNestedTable(record, nestedTable); + } + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + return EffectsListAdapter::nestedTable(record); + } + + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + return EffectsListAdapter::getNestedData(record, subRowIndex, subColIndex); + } + + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (row, mType))); + EffectsListAdapter::setNestedData(record, value, subRowIndex, subColIndex); + } + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const + { + const Record record; + return EffectsListAdapter::getNestedColumnsCount(record); + } + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + return EffectsListAdapter::getNestedRowsCount(record); + } + }; } #endif diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 392a1677e..929a3b245 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -9,6 +9,7 @@ #include "refidadapterimp.hpp" #include "columns.hpp" #include "nestedtablewrapper.hpp" +#include "nestedcoladapterimp.hpp" CSMWorld::RefIdColumn::RefIdColumn (int columnId, Display displayType, int flag, bool editable, bool userEditable) @@ -70,6 +71,29 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.push_back (RefIdColumn (Columns::ColumnId_CoinValue, ColumnBase::Display_Integer)); inventoryColumns.mValue = &mColumns.back(); + // nested table + PotionColumns potionColumns (inventoryColumns); + mColumns.push_back (RefIdColumn (Columns::ColumnId_EffectList, ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); + potionColumns.mEffects = &mColumns.back(); // see refidadapterimp.hpp + mNestedAdapters.insert (std::make_pair(&mColumns.back(), + new EffectsRefIdAdapter (UniversalId::Type_Potion))); + mColumns.back().addColumn( + new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_String/*, false*/)); + mColumns.back().addColumn( + new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_String)); + mColumns.back().addColumn( + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_String)); // reuse attribute + mColumns.back().addColumn( + new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new NestedChildColumn (Columns::ColumnId_EffectArea, ColumnBase::Display_String)); + mColumns.back().addColumn( + new NestedChildColumn (Columns::ColumnId_Duration, ColumnBase::Display_Integer)); // reuse from light + mColumns.back().addColumn( + new NestedChildColumn (Columns::ColumnId_MinRange, ColumnBase::Display_Integer)); // reuse from sound + mColumns.back().addColumn( + new NestedChildColumn (Columns::ColumnId_MaxRange, ColumnBase::Display_Integer)); // reuse from sound + EnchantableColumns enchantableColumns (inventoryColumns); mColumns.push_back (RefIdColumn (Columns::ColumnId_Enchantment, ColumnBase::Display_String)); @@ -385,7 +409,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mAdapters.insert (std::make_pair (UniversalId::Type_Activator, new NameRefIdAdapter (UniversalId::Type_Activator, nameColumns))); mAdapters.insert (std::make_pair (UniversalId::Type_Potion, - new PotionRefIdAdapter (inventoryColumns, autoCalc))); + new PotionRefIdAdapter (potionColumns, autoCalc))); mAdapters.insert (std::make_pair (UniversalId::Type_Apparatus, new ApparatusRefIdAdapter (inventoryColumns, apparatusType, toolsColumns.mQuality))); mAdapters.insert (std::make_pair (UniversalId::Type_Armor, @@ -430,6 +454,10 @@ CSMWorld::RefIdCollection::~RefIdCollection() for (std::map::iterator iter (mAdapters.begin()); iter!=mAdapters.end(); ++iter) delete iter->second; + + for (std::map::iterator iter (mNestedAdapters.begin()); + iter!=mNestedAdapters.end(); ++iter) + delete iter->second; } int CSMWorld::RefIdCollection::getSize() const @@ -475,6 +503,12 @@ QVariant CSMWorld::RefIdCollection::getNestedData (int row, int column, int subR { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex(row); + const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column)); + if (nestedAdapter) + { + return nestedAdapter->getNestedData(&mColumns.at (column), mData, localIndex.first, subRow, subColumn); + } + const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); return adaptor.getNestedData (&mColumns.at (column), mData, localIndex.first, subRow, subColumn); @@ -493,6 +527,13 @@ void CSMWorld::RefIdCollection::setNestedData(int row, int column, const QVarian { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column)); + if (nestedAdapter) + { + nestedAdapter->setNestedData(&mColumns.at (column), mData, localIndex.first, data, subRow, subColumn); + return; + } + const RefIdAdapter& adaptor = findAdapter (localIndex.second); dynamic_cast(adaptor).setNestedData (&mColumns.at (column), mData, localIndex.first, data, subRow, subColumn); @@ -507,6 +548,13 @@ void CSMWorld::RefIdCollection::removeNestedRows(int row, int column, int subRow { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column)); + if (nestedAdapter) + { + nestedAdapter->removeNestedRow(&mColumns.at (column), mData, localIndex.first, subRow); + return; + } + const RefIdAdapter& adaptor = findAdapter (localIndex.second); dynamic_cast(adaptor).removeNestedRow(&mColumns.at (column), mData, localIndex.first, subRow); @@ -651,6 +699,12 @@ int CSMWorld::RefIdCollection::getNestedRowsCount(int row, int column) const { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column)); + if (nestedAdapter) + { + return nestedAdapter->getNestedRowsCount(&mColumns.at(column), mData, localIndex.first); + } + const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); return adaptor.getNestedRowsCount(&mColumns.at(column), mData, localIndex.first); @@ -660,6 +714,12 @@ int CSMWorld::RefIdCollection::getNestedColumnsCount(int row, int column) const { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column)); + if (nestedAdapter) + { + return nestedAdapter->getNestedColumnsCount(&mColumns.at(column), mData); + } + const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); return adaptor.getNestedColumnsCount(&mColumns.at(column), mData); @@ -674,6 +734,13 @@ void CSMWorld::RefIdCollection::addNestedRow(int row, int col, int position) { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(col)); + if (nestedAdapter) + { + nestedAdapter->addNestedRow(&mColumns.at(col), mData, localIndex.first, position); + return; + } + const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); adaptor.addNestedRow(&mColumns.at(col), mData, localIndex.first, position); @@ -683,6 +750,13 @@ void CSMWorld::RefIdCollection::setNestedTable(int row, int column, const CSMWor { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column)); + if (nestedAdapter) + { + nestedAdapter->setNestedTable(&mColumns.at(column), mData, localIndex.first, nestedTable); + return; + } + const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); adaptor.setNestedTable(&mColumns.at(column), mData, localIndex.first, nestedTable); @@ -692,7 +766,26 @@ CSMWorld::NestedTableWrapperBase* CSMWorld::RefIdCollection::nestedTable(int row { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column)); + if (nestedAdapter) + { + return nestedAdapter->nestedTable(&mColumns.at(column), mData, localIndex.first); + } + const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); return adaptor.nestedTable(&mColumns.at(column), mData, localIndex.first); } + +const CSMWorld::NestedRefIdAdapterBase* CSMWorld::RefIdCollection::getNestedAdapter(const CSMWorld::ColumnBase &column) const +{ + std::map::const_iterator iter = + mNestedAdapters.find (&column); + + if (iter==mNestedAdapters.end()) + return 0; // FIXME: testing only + //throw std::runtime_error("No such column in the nestedadapters"); + + //return *iter->second; + return iter->second; +} diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index 3315212c1..70651b78d 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -19,6 +19,7 @@ namespace CSMWorld { class RefIdAdapter; struct NestedTableWrapperBase; + class NestedRefIdAdapterBase; class RefIdColumn : public NestableColumn { @@ -44,11 +45,16 @@ namespace CSMWorld std::deque mColumns; std::map mAdapters; + std::map mNestedAdapters; + private: const RefIdAdapter& findAdapter (UniversalId::Type) const; ///< Throws an exception if no adaptor for \a Type can be found. + //const NestedRefIdAdapterBase& getNestedAdapter(const ColumnBase &column) const; + const NestedRefIdAdapterBase* getNestedAdapter(const ColumnBase &column) const; + public: RefIdCollection(); From 7ccf53e750781476e256cdb0ed1e6919edc6e9be Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 12 Apr 2015 20:03:55 +1000 Subject: [PATCH 709/740] Changed over inventory adapters. Fixed a few places where modified records were not set properly. --- .../model/world/nestedcoladapterimp.cpp | 28 +++- .../model/world/nestedcoladapterimp.hpp | 12 +- apps/opencs/model/world/refidadapterimp.cpp | 6 +- apps/opencs/model/world/refidadapterimp.hpp | 147 +++++++++++++++++- apps/opencs/model/world/refidcollection.cpp | 8 +- 5 files changed, 186 insertions(+), 15 deletions(-) diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index 2bf1ffadd..785817d33 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -81,13 +81,17 @@ namespace CSMWorld void PathgridPointListAdapter::setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const { - record.get().mPoints = + Pathgrid pathgrid = record.get(); + + pathgrid.mPoints = static_cast(nestedTable).mRecord.mPoints; - record.get().mData.mS2 = + pathgrid.mData.mS2 = static_cast(nestedTable).mRecord.mData.mS2; // also update edges in case points were added/removed - record.get().mEdges = + pathgrid.mEdges = static_cast(nestedTable).mRecord.mEdges; + + record.setModified (pathgrid); } NestedTableWrapperBase* PathgridPointListAdapter::nestedTable(const Record& record) const @@ -180,8 +184,12 @@ namespace CSMWorld void PathgridEdgeListAdapter::setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const { - record.get().mEdges = + Pathgrid pathgrid = record.get(); + + pathgrid.mEdges = static_cast &>(nestedTable).mNestedTable; + + record.setModified (pathgrid); } NestedTableWrapperBase* PathgridEdgeListAdapter::nestedTable(const Record& record) const @@ -277,8 +285,12 @@ namespace CSMWorld void FactionReactionsAdapter::setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const { - record.get().mReactions = + ESM::Faction faction = record.get(); + + faction.mReactions = static_cast >&>(nestedTable).mNestedTable; + + record.setModified (faction); } NestedTableWrapperBase* FactionReactionsAdapter::nestedTable(const Record& record) const @@ -393,8 +405,12 @@ namespace CSMWorld void RegionSoundListAdapter::setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const { - record.get().mSoundList = + ESM::Region region = record.get(); + + region.mSoundList = static_cast >&>(nestedTable).mNestedTable; + + record.setModified (region); } NestedTableWrapperBase* RegionSoundListAdapter::nestedTable(const Record& record) const diff --git a/apps/opencs/model/world/nestedcoladapterimp.hpp b/apps/opencs/model/world/nestedcoladapterimp.hpp index 7fed74868..387b07e5c 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.hpp +++ b/apps/opencs/model/world/nestedcoladapterimp.hpp @@ -173,8 +173,12 @@ namespace CSMWorld virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const { - record.get().mPowers.mList = + ESXRecordT raceOrBthSgn = record.get(); + + raceOrBthSgn.mPowers.mList = static_cast >&>(nestedTable).mNestedTable; + + record.setModified (raceOrBthSgn); } virtual NestedTableWrapperBase* nestedTable(const Record& record) const @@ -277,8 +281,12 @@ namespace CSMWorld virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const { - record.get().mEffects.mList = + ESXRecordT magic = record.get(); + + magic.mEffects.mList = static_cast >&>(nestedTable).mNestedTable; + + record.setModified (magic); } virtual NestedTableWrapperBase* nestedTable(const Record& record) const diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 426bfe3d1..42d1aa52e 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -26,7 +26,7 @@ QVariant CSMWorld::PotionRefIdAdapter::getData (const RefIdColumn *column, const return record.get().mData.mAutoCalc!=0; if (column==mColumns.mEffects) - return true; // Required to show nested tables in dialogue subview + return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() return InventoryRefIdAdapter::getData (column, data, index); } @@ -213,7 +213,7 @@ QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, return (record.get().mFlags & ESM::Container::Respawn)!=0; if (column==mContent) - return true; // required by IdTree::hasChildren() + return true; // Required to show nested tables in dialogue subview return NameRefIdAdapter::getData (column, data, index); } @@ -497,7 +497,7 @@ QVariant CSMWorld::NpcRefIdAdapter::getData (const RefIdColumn *column, const Re return QString::fromUtf8 (record.get().mHead.c_str()); if (column==mColumns.mDestinations) - return true; // required by IdTree::hasChildren() + return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() std::map::const_iterator iter = mColumns.mFlags.find (column); diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index b12d0cb6f..08e2e7493 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -8,6 +8,9 @@ #include #include #include +#include +#include +#include #include "record.hpp" #include "refiddata.hpp" @@ -545,10 +548,10 @@ namespace CSMWorld return record.get().mAiData.mAlarm; if (column==mActors.mInventory) - return true; // required by IdTree::hasChildren() + return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() if (column==mActors.mSpells) - return true; // required by IdTree::hasChildren() + return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() std::map::const_iterator iter = mActors.mServices.find (column); @@ -908,7 +911,7 @@ namespace CSMWorld virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const { - const Record record; + const Record record; // not used, just a dummy return EffectsListAdapter::getNestedColumnsCount(record); } @@ -919,6 +922,144 @@ namespace CSMWorld return EffectsListAdapter::getNestedRowsCount(record); } }; + + template + class NestedInventoryRefIdAdapter : public NestedRefIdAdapterBase + { + UniversalId::Type mType; + + // not implemented + NestedInventoryRefIdAdapter (const NestedInventoryRefIdAdapter&); + NestedInventoryRefIdAdapter& operator= (const NestedInventoryRefIdAdapter&); + + public: + + NestedInventoryRefIdAdapter(UniversalId::Type type) :mType(type) {} + + virtual ~NestedInventoryRefIdAdapter() {} + + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT container = record.get(); + + std::vector& list = container.mInventory.mList; + + ESM::ContItem newRow = {0, {""}}; + + if (position >= (int)list.size()) + list.push_back(newRow); + else + list.insert(list.begin()+position, newRow); + + record.setModified (container); + } + + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT container = record.get(); + + std::vector& list = container.mInventory.mList; + + if (rowToRemove < 0 || rowToRemove >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + list.erase (list.begin () + rowToRemove); + + record.setModified (container); + } + + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT container = record.get(); + + container.mInventory.mList = + static_cast >&>(nestedTable).mNestedTable; + + record.setModified (container); + } + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(record.get().mInventory.mList); + } + + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + const std::vector& list = record.get().mInventory.mList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + const ESM::ContItem& content = list.at(subRowIndex); + + switch (subColIndex) + { + case 0: return QString::fromUtf8(content.mItem.toString().c_str()); + case 1: return content.mCount; + default: + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + } + } + + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (row, mType))); + ESXRecordT container = record.get(); + std::vector& list = container.mInventory.mList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + switch(subColIndex) + { + case 0: + list.at(subRowIndex).mItem.assign(std::string(value.toString().toUtf8().constData())); + break; + + case 1: + list.at(subRowIndex).mCount = value.toInt(); + break; + + default: + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + } + + record.setModified (container); + } + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const + { + return 2; + } + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + return static_cast(record.get().mInventory.mList.size()); + } + }; } #endif diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 929a3b245..755a1f56f 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -76,7 +76,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.push_back (RefIdColumn (Columns::ColumnId_EffectList, ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); potionColumns.mEffects = &mColumns.back(); // see refidadapterimp.hpp mNestedAdapters.insert (std::make_pair(&mColumns.back(), - new EffectsRefIdAdapter (UniversalId::Type_Potion))); + new EffectsRefIdAdapter (UniversalId::Type_Potion))); mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_String/*, false*/)); mColumns.back().addColumn( @@ -124,6 +124,10 @@ CSMWorld::RefIdCollection::RefIdCollection() // Nested table mColumns.push_back(RefIdColumn (Columns::ColumnId_ActorInventory, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue)); actorsColumns.mInventory = &mColumns.back(); + mNestedAdapters.insert (std::make_pair(&mColumns.back(), + new NestedInventoryRefIdAdapter (UniversalId::Type_Npc))); + mNestedAdapters.insert (std::make_pair(&mColumns.back(), + new NestedInventoryRefIdAdapter (UniversalId::Type_Creature))); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String)); mColumns.back().addColumn( @@ -205,6 +209,8 @@ CSMWorld::RefIdCollection::RefIdCollection() // Nested table mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue)); const RefIdColumn *content = &mColumns.back(); + mNestedAdapters.insert (std::make_pair(&mColumns.back(), + new NestedInventoryRefIdAdapter (UniversalId::Type_Container))); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String)); mColumns.back().addColumn( From a976dca27bb7d0c0b3a8a6e476501d4dc4a649c8 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 13 Apr 2015 06:39:38 +1000 Subject: [PATCH 710/740] Changed over the remaining RefId adapters. Fixed issue where map entries were overwriting the same key... --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/nestedadapters.cpp | 8 - apps/opencs/model/world/nestedadapters.hpp | 420 -------------------- apps/opencs/model/world/refidadapter.cpp | 85 ---- apps/opencs/model/world/refidadapter.hpp | 43 -- apps/opencs/model/world/refidadapterimp.cpp | 15 +- apps/opencs/model/world/refidadapterimp.hpp | 332 +++++++++++++++- apps/opencs/model/world/refidcollection.cpp | 181 +++++---- apps/opencs/model/world/refidcollection.hpp | 5 +- 9 files changed, 422 insertions(+), 669 deletions(-) delete mode 100644 apps/opencs/model/world/nestedadapters.cpp delete mode 100644 apps/opencs/model/world/nestedadapters.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index babd3363f..cfe084e2c 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -25,7 +25,7 @@ opencs_units (model/world opencs_units_noqt (model/world universalid record commands columnbase scriptcontext cell refidcollection refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope - pathgrid landtexture land nestedtablewrapper nestedadapters nestedcollection nestedcoladapterimp + pathgrid landtexture land nestedtablewrapper nestedcollection nestedcoladapterimp ) opencs_hdrs_noqt (model/world diff --git a/apps/opencs/model/world/nestedadapters.cpp b/apps/opencs/model/world/nestedadapters.cpp deleted file mode 100644 index 1c8b1eff1..000000000 --- a/apps/opencs/model/world/nestedadapters.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include "nestedadapters.hpp" - -CSMWorld::HelperBase::HelperBase(CSMWorld::UniversalId::Type type) - : mType(type) -{} - -CSMWorld::HelperBase::~HelperBase() -{} diff --git a/apps/opencs/model/world/nestedadapters.hpp b/apps/opencs/model/world/nestedadapters.hpp deleted file mode 100644 index 97046276f..000000000 --- a/apps/opencs/model/world/nestedadapters.hpp +++ /dev/null @@ -1,420 +0,0 @@ -#ifndef CSM_WORLD_NESTEDADAPTERS_H -#define CSM_WORLD_NESTEDADAPTERS_H - -#include -#include -#include - -#include "universalid.hpp" -#include "nestedtablewrapper.hpp" -#include "record.hpp" -#include "refiddata.hpp" -#include "refidadapter.hpp" -#include -#include -#include -#include -#include -#include - -#include - -/*! \brief - * Nested adapter redirects responsibility to the helper class. Helper classes are polymorhpic (vide HelperBase and CastableHelper) and most likely templates. - */ - -namespace CSMWorld -{ - class RefIdColumn; - - class HelperBase - { - protected: - const CSMWorld::UniversalId::Type mType; - - public: - HelperBase(CSMWorld::UniversalId::Type type); - - virtual ~HelperBase(); - - virtual void setNestedTable(RefIdData& data, - int index, - const NestedTableWrapperBase& nestedTable) = 0; - - virtual NestedTableWrapperBase* nestedTable(const RefIdData& data, - int index) const = 0; - - virtual QVariant getNestedData(const CSMWorld::RefIdData& data, - int index, - int subRowIndex, - int subColIndex) const = 0; - - virtual void removeNestedRow (RefIdData& data, - int index, - int rowToRemove) const = 0; - - virtual void setNestedData (RefIdData& data, - int index, - const QVariant& value, - int subRowIndex, - int subColIndex) const = 0; - - virtual void addNestedRow (RefIdData& data, - int index, - int position) const = 0; - - virtual int getNestedColumnsCount(const RefIdData& data) const = 0; - - virtual int getNestedRowsCount(const RefIdData& data, - int index) const = 0; - }; - - template - class CastableHelper : public HelperBase - { - - public: - CastableHelper(CSMWorld::UniversalId::Type type) - : HelperBase(type) {} - - protected: - const Record& getRecord(const RefIdData& data, int index) const - { - return dynamic_cast&> ( - data.getRecord (RefIdData::LocalIndex (index, mType))); - } - - Record& getRecord(RefIdData& data, int index) const - { - return dynamic_cast&> ( - data.getRecord (RefIdData::LocalIndex (index, mType))); - } - }; - - template - class SpellsHelper : public CastableHelper - { - public: - - SpellsHelper(CSMWorld::UniversalId::Type type) - : CastableHelper(type) {} - - virtual void setNestedTable(RefIdData& data, - int index, - const NestedTableWrapperBase& nestedTable) - { - CastableHelper::getRecord(data, index).get().mSpells.mList = - (static_cast >&>(nestedTable)).mNestedTable; - } - - virtual NestedTableWrapperBase* nestedTable(const RefIdData& data, - int index) const - { - return new NestedTableWrapper >(CastableHelper::getRecord(data, index).get().mSpells.mList); - } - - virtual QVariant getNestedData(const CSMWorld::RefIdData& data, - int index, - int subRowIndex, - int subColIndex) const - { - const std::string& content = CastableHelper::getRecord(data, index).get().mSpells.mList.at(subRowIndex); - - if (subColIndex == 0) - { - return QString::fromUtf8(content.c_str()); - } - - throw std::logic_error("Trying to access non-existing column in the nested table!"); - } - - virtual void removeNestedRow (RefIdData& data, int index, int rowToRemove) const - { - std::vector& list = CastableHelper::getRecord(data, index).get().mSpells.mList; - - list.erase (list.begin () + rowToRemove); - } - - void setNestedData (RefIdData& data, - int index, - const QVariant& value, - int subRowIndex, - int subColIndex) const - { - if (subColIndex == 0) - { - CastableHelper::getRecord(data, index).get().mSpells.mList.at(subRowIndex) = std::string(value.toString().toUtf8()); - } - else - throw std::logic_error("Trying to access non-existing column in the nested table!"); - } - - virtual void addNestedRow (RefIdData& data, int index, int position) const - { - std::vector& list = CastableHelper::getRecord(data, index).get().mSpells.mList; - - std::string newString; - if (position >= (int)list.size()) - { - list.push_back(newString); - return; - } - - list.insert(list.begin()+position, newString); - } - - virtual int getNestedColumnsCount(const RefIdData& data) const - { - return 1; - } - - - virtual int getNestedRowsCount(const RefIdData& data, - int index) const - { - return CastableHelper::getRecord(data, index).get().mSpells.mList.size(); - } - - }; - - template - class DestinationsHelper : public CastableHelper - { - public: - - DestinationsHelper(CSMWorld::UniversalId::Type type) - : CastableHelper(type) {} - - virtual void setNestedTable(RefIdData& data, - int index, - const NestedTableWrapperBase& nestedTable) - { - CastableHelper::getRecord(data, index).get().mTransport.mList = - (static_cast >&>(nestedTable)).mNestedTable; - } - - virtual NestedTableWrapperBase* nestedTable(const RefIdData& data, - int index) const - { - return new NestedTableWrapper >(CastableHelper::getRecord(data, index).get().mTransport.mList); - } - - virtual QVariant getNestedData(const CSMWorld::RefIdData& data, - int index, - int subRowIndex, - int subColIndex) const - { - const ESM::Transport::Dest& content = CastableHelper::getRecord(data, index).get().mTransport.mList.at(subRowIndex); - - switch (subColIndex) - { - case 0: - return QString::fromUtf8(content.mCellName.c_str()); - - case 1: - return content.mPos.pos[0]; - - case 2: - return content.mPos.pos[1]; - - case 3: - return content.mPos.pos[2]; - - case 4: - return content.mPos.rot[0]; - - case 5: - return content.mPos.rot[1]; - - case 6: - return content.mPos.rot[2]; - - default: - throw std::logic_error("Trying to access non-existing column in the nested table!"); - } - } - - virtual void removeNestedRow (RefIdData& data, int index, int rowToRemove) const - { - std::vector& list = CastableHelper::getRecord(data, index).get().mTransport.mList; - - list.erase (list.begin () + rowToRemove); - } - - void setNestedData (RefIdData& data, - int index, - const QVariant& value, - int subRowIndex, - int subColIndex) const - { - switch(subColIndex) - { - case 0: - CastableHelper::getRecord(data, index).get().mTransport.mList.at(subRowIndex).mCellName = std::string(value.toString().toUtf8().constData()); - break; - - case 1: - CastableHelper::getRecord(data, index).get().mTransport.mList.at(subRowIndex).mPos.pos[0] = value.toFloat(); - break; - - case 2: - CastableHelper::getRecord(data, index).get().mTransport.mList.at(subRowIndex).mPos.pos[1] = value.toFloat(); - break; - - case 3: - CastableHelper::getRecord(data, index).get().mTransport.mList.at(subRowIndex).mPos.pos[2] = value.toFloat(); - break; - - case 4: - CastableHelper::getRecord(data, index).get().mTransport.mList.at(subRowIndex).mPos.rot[0] = value.toFloat(); - break; - - case 5: - CastableHelper::getRecord(data, index).get().mTransport.mList.at(subRowIndex).mPos.rot[1] = value.toFloat(); - break; - - case 6: - CastableHelper::getRecord(data, index).get().mTransport.mList.at(subRowIndex).mPos.rot[2] = value.toFloat(); - break; - - default: - throw std::logic_error("Trying to access non-existing column in the nested table!"); - } - } - - virtual void addNestedRow (RefIdData& data, int index, int position) const - { - std::vector& list = CastableHelper::getRecord(data, index).get().mTransport.mList; - - ESM::Position newPos; - for (unsigned i = 0; i < 3; ++i) - { - newPos.pos[i] = 0; - newPos.rot[i] = 0; - } - - ESM::Transport::Dest newRow; - newRow.mPos = newPos; - newRow.mCellName = ""; - - if (position >= (int)list.size()) - { - list.push_back(newRow); - return; - } - - list.insert(list.begin()+position, newRow); - } - - virtual int getNestedColumnsCount(const RefIdData& data) const - { - return 7; - } - - virtual int getNestedRowsCount(const RefIdData& data, - int index) const - { - return CastableHelper::getRecord(data, index).get().mTransport.mList.size(); - } - - }; - - template - class InventoryHelper : public CastableHelper - { - public: - - InventoryHelper(CSMWorld::UniversalId::Type type) - : CastableHelper(type) {} - - virtual void setNestedTable(RefIdData& data, - int index, - const NestedTableWrapperBase& nestedTable) - { - CastableHelper::getRecord(data, index).get().mInventory.mList = - (static_cast >&>(nestedTable)).mNestedTable; - } - - virtual NestedTableWrapperBase* nestedTable(const RefIdData& data, - int index) const - { - return new NestedTableWrapper >(CastableHelper::getRecord(data, index).get().mInventory.mList); - } - - virtual QVariant getNestedData(const CSMWorld::RefIdData& data, - int index, - int subRowIndex, - int subColIndex) const - { - const ESM::ContItem& content = CastableHelper::getRecord(data, index).get().mInventory.mList.at(subRowIndex); - - switch (subColIndex) - { - case 0: - return QString::fromUtf8(content.mItem.toString().c_str()); - - case 1: - return content.mCount; - - default: - throw std::logic_error("Trying to access non-existing column in the nested table!"); - } - } - - virtual void removeNestedRow (RefIdData& data, int index, int rowToRemove) const - { - std::vector& list = CastableHelper::getRecord(data, index).get().mInventory.mList; - - list.erase (list.begin () + rowToRemove); - } - - void setNestedData (RefIdData& data, - int index, - const QVariant& value, - int subRowIndex, - int subColIndex) const - { - switch(subColIndex) - { - case 0: - CastableHelper::getRecord(data, index).get().mInventory.mList.at(subRowIndex).mItem.assign(std::string(value.toString().toUtf8().constData())); - break; - - case 1: - CastableHelper::getRecord(data, index).get().mInventory.mList.at(subRowIndex).mCount = value.toInt(); - break; - - default: - throw std::logic_error("Trying to access non-existing column in the nested table!"); - } - } - - virtual void addNestedRow (RefIdData& data, int index, int position) const - { - std::vector& list = CastableHelper::getRecord(data, index).get().mInventory.mList; - - ESM::ContItem newRow = {0, {""}}; - if (position >= (int)list.size()) - { - list.push_back(newRow); - return; - } - - list.insert(list.begin()+position, newRow); - } - - virtual int getNestedColumnsCount(const RefIdData& data) const - { - return 2; - } - - virtual int getNestedRowsCount(const RefIdData& data, - int index) const - { - return CastableHelper::getRecord(data, index).get().mInventory.mList.size(); - } - - }; -} - -#endif diff --git a/apps/opencs/model/world/refidadapter.cpp b/apps/opencs/model/world/refidadapter.cpp index a12a95196..37cb67bca 100644 --- a/apps/opencs/model/world/refidadapter.cpp +++ b/apps/opencs/model/world/refidadapter.cpp @@ -1,9 +1,5 @@ #include "refidadapter.hpp" -#include "nestedtablewrapper.hpp" - -#include - CSMWorld::RefIdAdapter::RefIdAdapter() {} CSMWorld::RefIdAdapter::~RefIdAdapter() {} @@ -11,84 +7,3 @@ CSMWorld::RefIdAdapter::~RefIdAdapter() {} CSMWorld::NestedRefIdAdapterBase::NestedRefIdAdapterBase() {} CSMWorld::NestedRefIdAdapterBase::~NestedRefIdAdapterBase() {} - -CSMWorld::NestedRefIdAdapter::NestedRefIdAdapter() -{} - -CSMWorld::NestedRefIdAdapter::~NestedRefIdAdapter() -{ - for (unsigned i = 0; i < mAssociatedColumns.size(); ++i) - { - delete mAssociatedColumns[i].second; - } -} - -void CSMWorld::NestedRefIdAdapter::setNestedData (const RefIdColumn *column, RefIdData& data, int row, - const QVariant& value, int subRowIndex, int subColIndex) const -{ - getHelper(column)->setNestedData(data, row, value, subRowIndex, subColIndex); -} - -QVariant CSMWorld::NestedRefIdAdapter::getNestedData(const RefIdColumn *column, const RefIdData& data, - int index, int subRowIndex, int subColIndex) const -{ - return getHelper(column)->getNestedData(data, index, subRowIndex, subColIndex); -} - -int CSMWorld::NestedRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const -{ - return getHelper(column)->getNestedColumnsCount(data); -} - - -int CSMWorld::NestedRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const -{ - return getHelper(column)->getNestedRowsCount(data, index); -} - - -void CSMWorld::NestedRefIdAdapter::removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const -{ - getHelper(column)->removeNestedRow(data, index, rowToRemove); -} - -void CSMWorld::NestedRefIdAdapter::addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const -{ - getHelper(column)->addNestedRow(data, index, position); //This code grows more boring and boring. I would love some macros. -} - -void CSMWorld::NestedRefIdAdapter::setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const -{ - getHelper(column)->setNestedTable(data, index, nestedTable); -} - - -CSMWorld::NestedTableWrapperBase* CSMWorld::NestedRefIdAdapter::nestedTable (const RefIdColumn* column, const RefIdData& data, int index) const -{ - return getHelper(column)->nestedTable(data, index); -} - -CSMWorld::HelperBase* CSMWorld::NestedRefIdAdapter::getHelper(const RefIdColumn *column) const -{ - for (unsigned i = 0; i < mAssociatedColumns.size(); ++i) - { - if (mAssociatedColumns[i].first == column) - { - return mAssociatedColumns[i].second; - } - } - - throw std::logic_error("No such column in the nestedrefidadapter"); - - return NULL; -} - -void CSMWorld::NestedRefIdAdapter::setAssocColumns(const std::vector >& assocColumns) -{ - mAssociatedColumns = assocColumns; -} - -void CSMWorld::NestedRefIdAdapter::addAssocColumn(const std::pair & assocColumn) -{ - mAssociatedColumns.push_back(assocColumn); -} diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index f80ce7ab3..ba9da577d 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -4,8 +4,6 @@ #include #include -#include "nestedadapters.hpp" - /*! \brief * Adapters acts as indirection layer, abstracting details of the record types (in the wrappers) from the higher levels of model. * Please notice that nested adaptor uses helper classes for actually performing any actions. Different record types require different helpers (needs to be created in the subclass and then fetched via member function). @@ -77,47 +75,6 @@ namespace CSMWorld virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, const RefIdData& data, int index) const = 0; }; - - class NestedRefIdAdapter : public NestedRefIdAdapterBase - { - std::vector > mAssociatedColumns; //basically, i wanted a map, but with pointer key - - public: - NestedRefIdAdapter(); - - virtual ~NestedRefIdAdapter(); - - virtual void setNestedData (const RefIdColumn *column, RefIdData& data, int row, - const QVariant& value, int subRowIndex, int subColIndex) const; - - virtual QVariant getNestedData (const RefIdColumn *column, const RefIdData& data, - int index, int subRowIndex, int subColIndex) const; - - virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const; - - virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; - - virtual void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const; - - virtual void addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const; - - virtual void setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const; - - virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, const RefIdData& data, int index) const; - - protected: - void setAssocColumns(const std::vector >& assocColumns); - ///The ownership of the Helper pointers is transfered. - ///The ownership of the column pointers it not transfered (it is not surprising, since columns are created by collection). - ///You MUST call this method to setup the nested adaptor! - - void addAssocColumn(const std::pair & assocColumn); - ///Like setAssocColumn, when it is impossible to set all columns at once - - private: - - HelperBase* getHelper(const RefIdColumn *column) const; - }; } #endif diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 42d1aa52e..cd3a20327 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -188,13 +188,7 @@ CSMWorld::ContainerRefIdAdapter::ContainerRefIdAdapter (const NameColumns& colum const RefIdColumn *weight, const RefIdColumn *organic, const RefIdColumn *respawn, const RefIdColumn *content) : NameRefIdAdapter (UniversalId::Type_Container, columns), mWeight (weight), mOrganic (organic), mRespawn (respawn), mContent(content) -{ - std::vector > assoCol; - - assoCol.push_back(std::make_pair(content, new InventoryHelper(UniversalId::Type_Container))); - - setAssocColumns(assoCol); -} +{} QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, @@ -471,9 +465,7 @@ CSMWorld::NpcColumns::NpcColumns (const ActorColumns& actorColumns) CSMWorld::NpcRefIdAdapter::NpcRefIdAdapter (const NpcColumns& columns) : ActorRefIdAdapter (UniversalId::Type_Npc, columns), mColumns (columns) -{ - NestedRefIdAdapter::addAssocColumn(std::make_pair(columns.mDestinations, new DestinationsHelper(UniversalId::Type_Npc))); -} +{} QVariant CSMWorld::NpcRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, int index) const @@ -496,9 +488,6 @@ QVariant CSMWorld::NpcRefIdAdapter::getData (const RefIdColumn *column, const Re if (column==mColumns.mHead) return QString::fromUtf8 (record.get().mHead.c_str()); - if (column==mColumns.mDestinations) - return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() - std::map::const_iterator iter = mColumns.mFlags.find (column); diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 08e2e7493..32e9148c7 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -11,12 +11,12 @@ #include #include #include +#include #include "record.hpp" #include "refiddata.hpp" #include "universalid.hpp" #include "refidadapter.hpp" -#include "nestedadapters.hpp" namespace CSMWorld { @@ -489,6 +489,7 @@ namespace CSMWorld const RefIdColumn *mAlarm; const RefIdColumn *mInventory; const RefIdColumn *mSpells; + const RefIdColumn *mDestinations; std::map mServices; ActorColumns (const NameColumns& base) : NameColumns (base) {} @@ -496,7 +497,7 @@ namespace CSMWorld /// \brief Adapter for actor IDs (handles common AI functionality) template - class ActorRefIdAdapter : public NameRefIdAdapter, public NestedRefIdAdapter + class ActorRefIdAdapter : public NameRefIdAdapter { ActorColumns mActors; @@ -516,14 +517,7 @@ namespace CSMWorld ActorRefIdAdapter::ActorRefIdAdapter (UniversalId::Type type, const ActorColumns& columns) : NameRefIdAdapter (type, columns), mActors (columns) - { - std::vector > assoCol; - - assoCol.push_back(std::make_pair(mActors.mInventory, new InventoryHelper(type))); - assoCol.push_back(std::make_pair(mActors.mSpells, new SpellsHelper(type))); - - setAssocColumns(assoCol); - } + {} template QVariant ActorRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, @@ -553,6 +547,9 @@ namespace CSMWorld if (column==mActors.mSpells) return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() + if (column==mActors.mDestinations) + return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() + std::map::const_iterator iter = mActors.mServices.find (column); @@ -672,7 +669,7 @@ namespace CSMWorld ///< If the data type does not match an exception is thrown. }; - class ContainerRefIdAdapter : public NameRefIdAdapter, public NestedRefIdAdapter + class ContainerRefIdAdapter : public NameRefIdAdapter { const RefIdColumn *mWeight; const RefIdColumn *mOrganic; @@ -790,7 +787,6 @@ namespace CSMWorld const RefIdColumn *mFaction; const RefIdColumn *mHair; const RefIdColumn *mHead; - const RefIdColumn *mDestinations; NpcColumns (const ActorColumns& actorColumns); }; @@ -1060,6 +1056,318 @@ namespace CSMWorld return static_cast(record.get().mInventory.mList.size()); } }; + + template + class NestedSpellRefIdAdapter : public NestedRefIdAdapterBase + { + UniversalId::Type mType; + + // not implemented + NestedSpellRefIdAdapter (const NestedSpellRefIdAdapter&); + NestedSpellRefIdAdapter& operator= (const NestedSpellRefIdAdapter&); + + public: + + NestedSpellRefIdAdapter(UniversalId::Type type) :mType(type) {} + + virtual ~NestedSpellRefIdAdapter() {} + + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT caster = record.get(); + + std::vector& list = caster.mSpells.mList; + + std::string newString; + + if (position >= (int)list.size()) + list.push_back(newString); + else + list.insert(list.begin()+position, newString); + + record.setModified (caster); + } + + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT caster = record.get(); + + std::vector& list = caster.mSpells.mList; + + if (rowToRemove < 0 || rowToRemove >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + list.erase (list.begin () + rowToRemove); + + record.setModified (caster); + } + + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT caster = record.get(); + + caster.mSpells.mList = + static_cast >&>(nestedTable).mNestedTable; + + record.setModified (caster); + } + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(record.get().mSpells.mList); + } + + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + const std::vector& list = record.get().mSpells.mList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + const std::string& content = list.at(subRowIndex); + + if (subColIndex == 0) + return QString::fromUtf8(content.c_str()); + else + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + } + + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (row, mType))); + ESXRecordT caster = record.get(); + std::vector& list = caster.mSpells.mList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + if (subColIndex == 0) + list.at(subRowIndex) = std::string(value.toString().toUtf8()); + else + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + + record.setModified (caster); + } + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const + { + return 1; + } + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + return static_cast(record.get().mSpells.mList.size()); + } + }; + + template + class NestedTravelRefIdAdapter : public NestedRefIdAdapterBase + { + UniversalId::Type mType; + + // not implemented + NestedTravelRefIdAdapter (const NestedTravelRefIdAdapter&); + NestedTravelRefIdAdapter& operator= (const NestedTravelRefIdAdapter&); + + public: + + NestedTravelRefIdAdapter(UniversalId::Type type) :mType(type) {} + + virtual ~NestedTravelRefIdAdapter() {} + + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT traveller = record.get(); + + std::vector& list = traveller.mTransport.mList; + + ESM::Position newPos; + for (unsigned i = 0; i < 3; ++i) + { + newPos.pos[i] = 0; + newPos.rot[i] = 0; + } + + ESM::Transport::Dest newRow; + newRow.mPos = newPos; + newRow.mCellName = ""; + + if (position >= (int)list.size()) + list.push_back(newRow); + else + list.insert(list.begin()+position, newRow); + + record.setModified (traveller); + } + + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT traveller = record.get(); + + std::vector& list = traveller.mTransport.mList; + + if (rowToRemove < 0 || rowToRemove >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + list.erase (list.begin () + rowToRemove); + + record.setModified (traveller); + } + + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT traveller = record.get(); + + traveller.mTransport.mList = + static_cast >&>(nestedTable).mNestedTable; + + record.setModified (traveller); + } + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(record.get().mTransport.mList); + } + + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + const std::vector& list = record.get().mTransport.mList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + const ESM::Transport::Dest& content = list.at(subRowIndex); + + switch (subColIndex) + { + case 0: + return QString::fromUtf8(content.mCellName.c_str()); + + case 1: + return content.mPos.pos[0]; + + case 2: + return content.mPos.pos[1]; + + case 3: + return content.mPos.pos[2]; + + case 4: + return content.mPos.rot[0]; + + case 5: + return content.mPos.rot[1]; + + case 6: + return content.mPos.rot[2]; + + default: + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + } + } + + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (row, mType))); + ESXRecordT traveller = record.get(); + std::vector& list = traveller.mTransport.mList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + switch(subColIndex) + { + case 0: + list.at(subRowIndex).mCellName = std::string(value.toString().toUtf8().constData()); + break; + + case 1: + list.at(subRowIndex).mPos.pos[0] = value.toFloat(); + break; + + case 2: + list.at(subRowIndex).mPos.pos[1] = value.toFloat(); + break; + + case 3: + list.at(subRowIndex).mPos.pos[2] = value.toFloat(); + break; + + case 4: + list.at(subRowIndex).mPos.rot[0] = value.toFloat(); + break; + + case 5: + list.at(subRowIndex).mPos.rot[1] = value.toFloat(); + break; + + case 6: + list.at(subRowIndex).mPos.rot[2] = value.toFloat(); + break; + + default: + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + } + + record.setModified (traveller); + } + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const + { + return 7; + } + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + return static_cast(record.get().mTransport.mList.size()); + } + }; } #endif diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 755a1f56f..92cd37d0d 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -75,8 +75,12 @@ CSMWorld::RefIdCollection::RefIdCollection() PotionColumns potionColumns (inventoryColumns); mColumns.push_back (RefIdColumn (Columns::ColumnId_EffectList, ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); potionColumns.mEffects = &mColumns.back(); // see refidadapterimp.hpp - mNestedAdapters.insert (std::make_pair(&mColumns.back(), - new EffectsRefIdAdapter (UniversalId::Type_Potion))); + + std::map effectsMap; + effectsMap.insert( + std::make_pair(UniversalId::Type_Potion, new EffectsRefIdAdapter (UniversalId::Type_Potion))); + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), effectsMap)); + mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_String/*, false*/)); mColumns.back().addColumn( @@ -124,10 +128,14 @@ CSMWorld::RefIdCollection::RefIdCollection() // Nested table mColumns.push_back(RefIdColumn (Columns::ColumnId_ActorInventory, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue)); actorsColumns.mInventory = &mColumns.back(); - mNestedAdapters.insert (std::make_pair(&mColumns.back(), - new NestedInventoryRefIdAdapter (UniversalId::Type_Npc))); - mNestedAdapters.insert (std::make_pair(&mColumns.back(), - new NestedInventoryRefIdAdapter (UniversalId::Type_Creature))); + + std::map inventoryMap; + inventoryMap.insert( + std::make_pair(UniversalId::Type_Npc, new NestedInventoryRefIdAdapter (UniversalId::Type_Npc))); + inventoryMap.insert( + std::make_pair(UniversalId::Type_Creature, new NestedInventoryRefIdAdapter (UniversalId::Type_Creature))); + + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), inventoryMap)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String)); mColumns.back().addColumn( @@ -136,9 +144,42 @@ CSMWorld::RefIdCollection::RefIdCollection() // Nested table mColumns.push_back(RefIdColumn (Columns::ColumnId_SpellList, ColumnBase::Display_NestedSpellList, ColumnBase::Flag_Dialogue)); actorsColumns.mSpells = &mColumns.back(); + + std::map spellsMap; + spellsMap.insert( + std::make_pair(UniversalId::Type_Npc, new NestedSpellRefIdAdapter (UniversalId::Type_Npc))); + spellsMap.insert( + std::make_pair(UniversalId::Type_Creature, new NestedSpellRefIdAdapter (UniversalId::Type_Creature))); + + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), spellsMap)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_SpellId, CSMWorld::ColumnBase::Display_String)); + // Nested table + mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcDestinations, ColumnBase::Display_NestedDestinationsList, ColumnBase::Flag_Dialogue)); + actorsColumns.mDestinations = &mColumns.back(); + + std::map destMap; + destMap.insert( + std::make_pair(UniversalId::Type_Npc, new NestedTravelRefIdAdapter (UniversalId::Type_Npc))); + destMap.insert( + std::make_pair(UniversalId::Type_Creature, new NestedTravelRefIdAdapter (UniversalId::Type_Creature))); + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), destMap)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_DestinationCell, CSMWorld::ColumnBase::Display_String)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_PosX, CSMWorld::ColumnBase::Display_Float)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_PosY, CSMWorld::ColumnBase::Display_Float)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_PosZ, CSMWorld::ColumnBase::Display_Float)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_RotX, CSMWorld::ColumnBase::Display_Float)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_RotY, CSMWorld::ColumnBase::Display_Float)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_RotZ, CSMWorld::ColumnBase::Display_Float)); + static const struct { int mName; @@ -209,8 +250,12 @@ CSMWorld::RefIdCollection::RefIdCollection() // Nested table mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue)); const RefIdColumn *content = &mColumns.back(); - mNestedAdapters.insert (std::make_pair(&mColumns.back(), - new NestedInventoryRefIdAdapter (UniversalId::Type_Container))); + + std::map contMap; + contMap.insert( + std::make_pair(UniversalId::Type_Container, new NestedInventoryRefIdAdapter (UniversalId::Type_Container))); + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), contMap)); + mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String)); mColumns.back().addColumn( @@ -351,24 +396,6 @@ CSMWorld::RefIdCollection::RefIdCollection() npcColumns.mFlags.insert (std::make_pair (metalBlood, ESM::NPC::Metal)); - // Nested table - mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcDestinations, ColumnBase::Display_NestedDestinationsList, ColumnBase::Flag_Dialogue)); - npcColumns.mDestinations = &mColumns.back(); - mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_DestinationCell, CSMWorld::ColumnBase::Display_String)); - mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_PosX, CSMWorld::ColumnBase::Display_Float)); - mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_PosY, CSMWorld::ColumnBase::Display_Float)); - mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_PosZ, CSMWorld::ColumnBase::Display_Float)); - mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_RotX, CSMWorld::ColumnBase::Display_Float)); - mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_RotY, CSMWorld::ColumnBase::Display_Float)); - mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_RotZ, CSMWorld::ColumnBase::Display_Float)); - WeaponColumns weaponColumns (enchantableColumns); mColumns.push_back (RefIdColumn (Columns::ColumnId_WeaponType, ColumnBase::Display_WeaponType)); @@ -461,9 +488,13 @@ CSMWorld::RefIdCollection::~RefIdCollection() iter!=mAdapters.end(); ++iter) delete iter->second; - for (std::map::iterator iter (mNestedAdapters.begin()); + for (std::vector > >::iterator iter (mNestedAdapters.begin()); iter!=mNestedAdapters.end(); ++iter) - delete iter->second; + { + for (std::map::iterator it ((iter->second).begin()); + it!=(iter->second).end(); ++it) + delete it->second; + } } int CSMWorld::RefIdCollection::getSize() const @@ -509,15 +540,11 @@ QVariant CSMWorld::RefIdCollection::getNestedData (int row, int column, int subR { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex(row); - const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column)); + const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); if (nestedAdapter) - { return nestedAdapter->getNestedData(&mColumns.at (column), mData, localIndex.first, subRow, subColumn); - } - - const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); - - return adaptor.getNestedData (&mColumns.at (column), mData, localIndex.first, subRow, subColumn); + else + throw std::runtime_error("Could not find a nestedadapter"); } void CSMWorld::RefIdCollection::setData (int index, int column, const QVariant& data) @@ -533,16 +560,14 @@ void CSMWorld::RefIdCollection::setNestedData(int row, int column, const QVarian { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); - const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column)); + const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); if (nestedAdapter) { nestedAdapter->setNestedData(&mColumns.at (column), mData, localIndex.first, data, subRow, subColumn); return; } - - const RefIdAdapter& adaptor = findAdapter (localIndex.second); - - dynamic_cast(adaptor).setNestedData (&mColumns.at (column), mData, localIndex.first, data, subRow, subColumn); + else + throw std::runtime_error("Could not find a nestedadapter"); } void CSMWorld::RefIdCollection::removeRows (int index, int count) @@ -554,16 +579,14 @@ void CSMWorld::RefIdCollection::removeNestedRows(int row, int column, int subRow { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); - const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column)); + const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); if (nestedAdapter) { nestedAdapter->removeNestedRow(&mColumns.at (column), mData, localIndex.first, subRow); return; } - - const RefIdAdapter& adaptor = findAdapter (localIndex.second); - - dynamic_cast(adaptor).removeNestedRow(&mColumns.at (column), mData, localIndex.first, subRow); + else + throw std::runtime_error("Could not find a nestedadapter"); } void CSMWorld::RefIdCollection::appendBlankRecord (const std::string& id, UniversalId::Type type) @@ -705,30 +728,22 @@ int CSMWorld::RefIdCollection::getNestedRowsCount(int row, int column) const { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); - const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column)); + const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); if (nestedAdapter) - { return nestedAdapter->getNestedRowsCount(&mColumns.at(column), mData, localIndex.first); - } - - const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); - - return adaptor.getNestedRowsCount(&mColumns.at(column), mData, localIndex.first); + else + throw std::runtime_error("Could not find a nestedadapter"); } int CSMWorld::RefIdCollection::getNestedColumnsCount(int row, int column) const { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); - const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column)); + const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); if (nestedAdapter) - { return nestedAdapter->getNestedColumnsCount(&mColumns.at(column), mData); - } - - const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); - - return adaptor.getNestedColumnsCount(&mColumns.at(column), mData); + else + throw std::runtime_error("Could not find a nestedadapter"); } CSMWorld::NestableColumn *CSMWorld::RefIdCollection::getNestableColumn(int column) @@ -740,58 +755,56 @@ void CSMWorld::RefIdCollection::addNestedRow(int row, int col, int position) { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); - const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(col)); + const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(col), localIndex.second); if (nestedAdapter) { nestedAdapter->addNestedRow(&mColumns.at(col), mData, localIndex.first, position); return; } - - const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); - - adaptor.addNestedRow(&mColumns.at(col), mData, localIndex.first, position); + else + throw std::runtime_error("Could not find a nestedadapter"); } void CSMWorld::RefIdCollection::setNestedTable(int row, int column, const CSMWorld::NestedTableWrapperBase& nestedTable) { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); - const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column)); + const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); if (nestedAdapter) { nestedAdapter->setNestedTable(&mColumns.at(column), mData, localIndex.first, nestedTable); return; } - - const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); - - adaptor.setNestedTable(&mColumns.at(column), mData, localIndex.first, nestedTable); + else + throw std::runtime_error("Could not find a nestedadapter"); } CSMWorld::NestedTableWrapperBase* CSMWorld::RefIdCollection::nestedTable(int row, int column) const { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); - const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column)); + const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); if (nestedAdapter) - { return nestedAdapter->nestedTable(&mColumns.at(column), mData, localIndex.first); - } - - const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast(findAdapter (localIndex.second)); - - return adaptor.nestedTable(&mColumns.at(column), mData, localIndex.first); + else + throw std::runtime_error("Could not find a nestedadapter"); } -const CSMWorld::NestedRefIdAdapterBase* CSMWorld::RefIdCollection::getNestedAdapter(const CSMWorld::ColumnBase &column) const +const CSMWorld::NestedRefIdAdapterBase* CSMWorld::RefIdCollection::getNestedAdapter(const CSMWorld::ColumnBase &column, UniversalId::Type type) const { - std::map::const_iterator iter = - mNestedAdapters.find (&column); + for (std::vector > >::const_iterator iter (mNestedAdapters.begin()); + iter!=mNestedAdapters.end(); ++iter) + { + if ((iter->first) == &column) + { + std::map::const_iterator it = + (iter->second).find(type); - if (iter==mNestedAdapters.end()) - return 0; // FIXME: testing only - //throw std::runtime_error("No such column in the nestedadapters"); + if (it == (iter->second).end()) + throw std::runtime_error("No such type in the nestedadapters"); - //return *iter->second; - return iter->second; + return it->second; + } + } + throw std::runtime_error("No such column in the nestedadapters"); } diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index 70651b78d..f183dc7a0 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -45,15 +45,14 @@ namespace CSMWorld std::deque mColumns; std::map mAdapters; - std::map mNestedAdapters; + std::vector > > mNestedAdapters; private: const RefIdAdapter& findAdapter (UniversalId::Type) const; ///< Throws an exception if no adaptor for \a Type can be found. - //const NestedRefIdAdapterBase& getNestedAdapter(const ColumnBase &column) const; - const NestedRefIdAdapterBase* getNestedAdapter(const ColumnBase &column) const; + const NestedRefIdAdapterBase* getNestedAdapter(const ColumnBase &column, UniversalId::Type type) const; public: From 221c57adee071d63f79ca86cda55e5974d335be3 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 13 Apr 2015 07:05:06 +1000 Subject: [PATCH 711/740] Fix template syntax and travis warnings. --- apps/opencs/model/world/refidadapterimp.hpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 32e9148c7..2599dc960 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -17,11 +17,10 @@ #include "refiddata.hpp" #include "universalid.hpp" #include "refidadapter.hpp" +#include "nestedtablewrapper.hpp" namespace CSMWorld { - struct NestedTableWrapperBase; - struct BaseColumns { const RefIdColumn *mId; @@ -857,6 +856,7 @@ namespace CSMWorld virtual ~EffectsRefIdAdapter() {} + using NestedRefIdAdapterBase::addNestedRow; virtual void addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const { @@ -865,6 +865,7 @@ namespace CSMWorld EffectsListAdapter::addNestedRow(record, position); } + using NestedRefIdAdapterBase::removeNestedRow; virtual void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const { @@ -873,6 +874,7 @@ namespace CSMWorld EffectsListAdapter::removeNestedRow(record, rowToRemove); } + using NestedRefIdAdapterBase::setNestedTable; virtual void setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const { @@ -881,6 +883,7 @@ namespace CSMWorld EffectsListAdapter::setNestedTable(record, nestedTable); } + using NestedRefIdAdapterBase::nestedTable; virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, const RefIdData& data, int index) const { @@ -889,6 +892,7 @@ namespace CSMWorld return EffectsListAdapter::nestedTable(record); } + using NestedRefIdAdapterBase::getNestedData; virtual QVariant getNestedData (const RefIdColumn *column, const RefIdData& data, int index, int subRowIndex, int subColIndex) const { @@ -897,6 +901,7 @@ namespace CSMWorld return EffectsListAdapter::getNestedData(record, subRowIndex, subColIndex); } + using NestedRefIdAdapterBase::setNestedData; virtual void setNestedData (const RefIdColumn *column, RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const { @@ -905,12 +910,14 @@ namespace CSMWorld EffectsListAdapter::setNestedData(record, value, subRowIndex, subColIndex); } + using NestedRefIdAdapterBase::getNestedColumnsCount; virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const { const Record record; // not used, just a dummy return EffectsListAdapter::getNestedColumnsCount(record); } + using NestedRefIdAdapterBase::getNestedRowsCount; virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const { const Record& record = @@ -978,7 +985,7 @@ namespace CSMWorld ESXRecordT container = record.get(); container.mInventory.mList = - static_cast >&>(nestedTable).mNestedTable; + static_cast >&>(nestedTable).mNestedTable; record.setModified (container); } @@ -1116,7 +1123,7 @@ namespace CSMWorld ESXRecordT caster = record.get(); caster.mSpells.mList = - static_cast >&>(nestedTable).mNestedTable; + static_cast >&>(nestedTable).mNestedTable; record.setModified (caster); } @@ -1128,7 +1135,7 @@ namespace CSMWorld static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); // deleted by dtor of NestedTableStoring - return new NestedTableWrapper >(record.get().mSpells.mList); + return new NestedTableWrapper >(record.get().mSpells.mList); } virtual QVariant getNestedData (const RefIdColumn *column, @@ -1251,7 +1258,7 @@ namespace CSMWorld ESXRecordT traveller = record.get(); traveller.mTransport.mList = - static_cast >&>(nestedTable).mNestedTable; + static_cast >&>(nestedTable).mNestedTable; record.setModified (traveller); } @@ -1263,7 +1270,7 @@ namespace CSMWorld static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); // deleted by dtor of NestedTableStoring - return new NestedTableWrapper >(record.get().mTransport.mList); + return new NestedTableWrapper >(record.get().mTransport.mList); } virtual QVariant getNestedData (const RefIdColumn *column, From 60e5ff8811e84951a9bd160a4a2969fc50b55a92 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 13 Apr 2015 08:03:30 +1000 Subject: [PATCH 712/740] Remove duplicated checks and exceptions. --- apps/opencs/model/world/refidadapterimp.hpp | 2 +- apps/opencs/model/world/refidcollection.cpp | 76 ++++++--------------- apps/opencs/model/world/refidcollection.hpp | 2 +- 3 files changed, 24 insertions(+), 56 deletions(-) diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 2599dc960..a3007d415 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -997,7 +997,7 @@ namespace CSMWorld static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); // deleted by dtor of NestedTableStoring - return new NestedTableWrapper >(record.get().mInventory.mList); + return new NestedTableWrapper >(record.get().mInventory.mList); } virtual QVariant getNestedData (const RefIdColumn *column, diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 92cd37d0d..3f14ba4ac 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -539,12 +539,9 @@ QVariant CSMWorld::RefIdCollection::getData (int index, int column) const QVariant CSMWorld::RefIdCollection::getNestedData (int row, int column, int subRow, int subColumn) const { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex(row); + const CSMWorld::NestedRefIdAdapterBase& nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); - const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); - if (nestedAdapter) - return nestedAdapter->getNestedData(&mColumns.at (column), mData, localIndex.first, subRow, subColumn); - else - throw std::runtime_error("Could not find a nestedadapter"); + return nestedAdapter.getNestedData(&mColumns.at (column), mData, localIndex.first, subRow, subColumn); } void CSMWorld::RefIdCollection::setData (int index, int column, const QVariant& data) @@ -559,15 +556,10 @@ void CSMWorld::RefIdCollection::setData (int index, int column, const QVariant& void CSMWorld::RefIdCollection::setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn) { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + const CSMWorld::NestedRefIdAdapterBase& nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); - const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); - if (nestedAdapter) - { - nestedAdapter->setNestedData(&mColumns.at (column), mData, localIndex.first, data, subRow, subColumn); - return; - } - else - throw std::runtime_error("Could not find a nestedadapter"); + nestedAdapter.setNestedData(&mColumns.at (column), mData, localIndex.first, data, subRow, subColumn); + return; } void CSMWorld::RefIdCollection::removeRows (int index, int count) @@ -578,15 +570,10 @@ void CSMWorld::RefIdCollection::removeRows (int index, int count) void CSMWorld::RefIdCollection::removeNestedRows(int row, int column, int subRow) { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + const CSMWorld::NestedRefIdAdapterBase& nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); - const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); - if (nestedAdapter) - { - nestedAdapter->removeNestedRow(&mColumns.at (column), mData, localIndex.first, subRow); - return; - } - else - throw std::runtime_error("Could not find a nestedadapter"); + nestedAdapter.removeNestedRow(&mColumns.at (column), mData, localIndex.first, subRow); + return; } void CSMWorld::RefIdCollection::appendBlankRecord (const std::string& id, UniversalId::Type type) @@ -727,23 +714,17 @@ const CSMWorld::RefIdData& CSMWorld::RefIdCollection::getDataSet() const int CSMWorld::RefIdCollection::getNestedRowsCount(int row, int column) const { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + const CSMWorld::NestedRefIdAdapterBase& nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); - const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); - if (nestedAdapter) - return nestedAdapter->getNestedRowsCount(&mColumns.at(column), mData, localIndex.first); - else - throw std::runtime_error("Could not find a nestedadapter"); + return nestedAdapter.getNestedRowsCount(&mColumns.at(column), mData, localIndex.first); } int CSMWorld::RefIdCollection::getNestedColumnsCount(int row, int column) const { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + const CSMWorld::NestedRefIdAdapterBase& nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); - const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); - if (nestedAdapter) - return nestedAdapter->getNestedColumnsCount(&mColumns.at(column), mData); - else - throw std::runtime_error("Could not find a nestedadapter"); + return nestedAdapter.getNestedColumnsCount(&mColumns.at(column), mData); } CSMWorld::NestableColumn *CSMWorld::RefIdCollection::getNestableColumn(int column) @@ -754,43 +735,30 @@ CSMWorld::NestableColumn *CSMWorld::RefIdCollection::getNestableColumn(int colum void CSMWorld::RefIdCollection::addNestedRow(int row, int col, int position) { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + const CSMWorld::NestedRefIdAdapterBase& nestedAdapter = getNestedAdapter(mColumns.at(col), localIndex.second); - const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(col), localIndex.second); - if (nestedAdapter) - { - nestedAdapter->addNestedRow(&mColumns.at(col), mData, localIndex.first, position); - return; - } - else - throw std::runtime_error("Could not find a nestedadapter"); + nestedAdapter.addNestedRow(&mColumns.at(col), mData, localIndex.first, position); + return; } void CSMWorld::RefIdCollection::setNestedTable(int row, int column, const CSMWorld::NestedTableWrapperBase& nestedTable) { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + const CSMWorld::NestedRefIdAdapterBase& nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); - const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); - if (nestedAdapter) - { - nestedAdapter->setNestedTable(&mColumns.at(column), mData, localIndex.first, nestedTable); - return; - } - else - throw std::runtime_error("Could not find a nestedadapter"); + nestedAdapter.setNestedTable(&mColumns.at(column), mData, localIndex.first, nestedTable); + return; } CSMWorld::NestedTableWrapperBase* CSMWorld::RefIdCollection::nestedTable(int row, int column) const { RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row); + const CSMWorld::NestedRefIdAdapterBase& nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); - const CSMWorld::NestedRefIdAdapterBase* nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second); - if (nestedAdapter) - return nestedAdapter->nestedTable(&mColumns.at(column), mData, localIndex.first); - else - throw std::runtime_error("Could not find a nestedadapter"); + return nestedAdapter.nestedTable(&mColumns.at(column), mData, localIndex.first); } -const CSMWorld::NestedRefIdAdapterBase* CSMWorld::RefIdCollection::getNestedAdapter(const CSMWorld::ColumnBase &column, UniversalId::Type type) const +const CSMWorld::NestedRefIdAdapterBase& CSMWorld::RefIdCollection::getNestedAdapter(const CSMWorld::ColumnBase &column, UniversalId::Type type) const { for (std::vector > >::const_iterator iter (mNestedAdapters.begin()); iter!=mNestedAdapters.end(); ++iter) @@ -803,7 +771,7 @@ const CSMWorld::NestedRefIdAdapterBase* CSMWorld::RefIdCollection::getNestedAdap if (it == (iter->second).end()) throw std::runtime_error("No such type in the nestedadapters"); - return it->second; + return *it->second; } } throw std::runtime_error("No such column in the nestedadapters"); diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index f183dc7a0..4d511d12d 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -52,7 +52,7 @@ namespace CSMWorld const RefIdAdapter& findAdapter (UniversalId::Type) const; ///< Throws an exception if no adaptor for \a Type can be found. - const NestedRefIdAdapterBase* getNestedAdapter(const ColumnBase &column, UniversalId::Type type) const; + const NestedRefIdAdapterBase& getNestedAdapter(const ColumnBase &column, UniversalId::Type type) const; public: From 526b53fce017d154f1a01e5095f4c42d1a271241 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 13 Apr 2015 14:14:00 +1000 Subject: [PATCH 713/740] Add AI packages table to dialogue subview. Also minor bug fixes. --- apps/opencs/model/world/columns.cpp | 17 +- apps/opencs/model/world/columns.hpp | 24 +- .../model/world/nestedcoladapterimp.cpp | 4 +- .../model/world/nestedcoladapterimp.hpp | 3 +- apps/opencs/model/world/refidadapterimp.hpp | 316 +++++++++++++++++- apps/opencs/model/world/refidcollection.cpp | 36 ++ 6 files changed, 380 insertions(+), 20 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index fca16ec0b..92a0d8f8d 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -192,9 +192,9 @@ namespace CSMWorld { ColumnId_NpcDestinations, "Destinations" }, { ColumnId_DestinationCell, "Cell"}, - { ColumnId_PosX, "X"}, - { ColumnId_PosY, "Y"}, - { ColumnId_PosZ, "Z"}, + { ColumnId_PosX, "Dest X"}, + { ColumnId_PosY, "Dest Y"}, + { ColumnId_PosZ, "Dest Z"}, { ColumnId_RotX, "Rotation X"}, { ColumnId_RotY, "Rotation Y"}, { ColumnId_RotZ, "Rotation Z"}, @@ -247,6 +247,17 @@ namespace CSMWorld { ColumnId_EffectRange, "Range"}, { ColumnId_EffectArea, "Area"}, + { ColumnId_AiPackageList, "Ai Packages"}, + { ColumnId_AiPackage, "Package"}, + { ColumnId_AiWanderDist, "Wander Dist"}, + { ColumnId_AiWanderDuration, "Wander Duration"}, + { ColumnId_AiWanderToD, "Wander ToD"}, + { ColumnId_AiWanderIdle, "Wander Idle"}, + { ColumnId_AiWanderRepeat, "Wander Repeat"}, + { ColumnId_AiActivateName, "Activate"}, + { ColumnId_AiTargetId, "Target ID"}, + { ColumnId_AiTargetCell, "Target Cell"}, + { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue3, "Use value 3" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 4f77ee23a..2788966a7 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -183,9 +183,9 @@ namespace CSMWorld ColumnId_SpellId = 168, ColumnId_NpcDestinations = 169, ColumnId_DestinationCell = 170, - ColumnId_PosX = 171, - ColumnId_PosY = 172, - ColumnId_PosZ = 173, + ColumnId_PosX = 171, // these are float + ColumnId_PosY = 172, // these are float + ColumnId_PosZ = 173, // these are float ColumnId_RotX = 174, ColumnId_RotY = 175, ColumnId_RotZ = 176, @@ -214,9 +214,9 @@ namespace CSMWorld ColumnId_PathgridPoints = 199, ColumnId_PathgridIndex = 200, - ColumnId_PathgridPosX = 201, - ColumnId_PathgridPosY = 202, - ColumnId_PathgridPosZ = 203, + ColumnId_PathgridPosX = 201, // these are int + ColumnId_PathgridPosY = 202, // these are int + ColumnId_PathgridPosZ = 203, // these are int ColumnId_PathgridEdges = 204, ColumnId_PathgridEdgeIndex = 205, ColumnId_PathgridEdge0 = 206, @@ -236,6 +236,18 @@ namespace CSMWorld ColumnId_EffectRange = 217, ColumnId_EffectArea = 218, + ColumnId_AiPackageList = 219, + ColumnId_AiPackage = 220, + ColumnId_AiWanderDist = 221, + ColumnId_AiWanderDuration = 222, + ColumnId_AiWanderToD = 223, + ColumnId_AiWanderIdle = 224, + ColumnId_AiWanderRepeat = 225, + ColumnId_AiActivateName = 226, + // use ColumnId_PosX, etc for AI destinations + ColumnId_AiTargetId = 227, + ColumnId_AiTargetCell = 228, + // 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/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index 785817d33..d974a34c7 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -121,7 +121,7 @@ namespace CSMWorld ESM::Pathgrid::Point point = pathgrid.mPoints[subRowIndex]; switch (subColIndex) { - case 0: break; + case 0: return; // return without saving case 1: point.mX = value.toInt(); break; case 2: point.mY = value.toInt(); break; case 3: point.mZ = value.toInt(); break; @@ -228,7 +228,7 @@ namespace CSMWorld ESM::Pathgrid::Edge edge = pathgrid.mEdges[subRowIndex]; switch (subColIndex) { - case 0: break; + case 0: return; // return without saving case 1: edge.mV0 = value.toInt(); break; case 2: edge.mV1 = value.toInt(); break; default: throw std::runtime_error("Pathgrid edge subcolumn index out of range"); diff --git a/apps/opencs/model/world/nestedcoladapterimp.hpp b/apps/opencs/model/world/nestedcoladapterimp.hpp index 387b07e5c..3328396fb 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.hpp +++ b/apps/opencs/model/world/nestedcoladapterimp.hpp @@ -457,7 +457,8 @@ namespace CSMWorld effect.mRange = ESM::RT_Touch; else if (effectId == "Target") effect.mRange = ESM::RT_Target; - // else leave unchanged + else + return; // leave unchanged break; } case 4: effect.mArea = value.toInt(); break; diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index a3007d415..c0fcba43c 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -10,8 +10,6 @@ #include #include #include -#include -#include #include "record.hpp" #include "refiddata.hpp" @@ -489,6 +487,7 @@ namespace CSMWorld const RefIdColumn *mInventory; const RefIdColumn *mSpells; const RefIdColumn *mDestinations; + const RefIdColumn *mAiPackages; std::map mServices; ActorColumns (const NameColumns& base) : NameColumns (base) {} @@ -549,6 +548,9 @@ namespace CSMWorld if (column==mActors.mDestinations) return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() + if (column==mActors.mAiPackages) + return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() + std::map::const_iterator iter = mActors.mServices.find (column); @@ -985,7 +987,7 @@ namespace CSMWorld ESXRecordT container = record.get(); container.mInventory.mList = - static_cast >&>(nestedTable).mNestedTable; + static_cast >&>(nestedTable).mNestedTable; record.setModified (container); } @@ -997,7 +999,7 @@ namespace CSMWorld static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); // deleted by dtor of NestedTableStoring - return new NestedTableWrapper >(record.get().mInventory.mList); + return new NestedTableWrapper >(record.get().mInventory.mList); } virtual QVariant getNestedData (const RefIdColumn *column, @@ -1123,7 +1125,7 @@ namespace CSMWorld ESXRecordT caster = record.get(); caster.mSpells.mList = - static_cast >&>(nestedTable).mNestedTable; + static_cast >&>(nestedTable).mNestedTable; record.setModified (caster); } @@ -1135,7 +1137,7 @@ namespace CSMWorld static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); // deleted by dtor of NestedTableStoring - return new NestedTableWrapper >(record.get().mSpells.mList); + return new NestedTableWrapper >(record.get().mSpells.mList); } virtual QVariant getNestedData (const RefIdColumn *column, @@ -1258,7 +1260,7 @@ namespace CSMWorld ESXRecordT traveller = record.get(); traveller.mTransport.mList = - static_cast >&>(nestedTable).mNestedTable; + static_cast >&>(nestedTable).mNestedTable; record.setModified (traveller); } @@ -1270,7 +1272,7 @@ namespace CSMWorld static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); // deleted by dtor of NestedTableStoring - return new NestedTableWrapper >(record.get().mTransport.mList); + return new NestedTableWrapper >(record.get().mTransport.mList); } virtual QVariant getNestedData (const RefIdColumn *column, @@ -1375,6 +1377,304 @@ namespace CSMWorld return static_cast(record.get().mTransport.mList.size()); } }; + + template + class ActorAiRefIdAdapter : public NestedRefIdAdapterBase + { + UniversalId::Type mType; + + // not implemented + ActorAiRefIdAdapter (const ActorAiRefIdAdapter&); + ActorAiRefIdAdapter& operator= (const ActorAiRefIdAdapter&); + + public: + + ActorAiRefIdAdapter(UniversalId::Type type) :mType(type) {} + + virtual ~ActorAiRefIdAdapter() {} + + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT actor = record.get(); + + std::vector& list = actor.mAiPackage.mList; + + ESM::AIPackage newRow; + newRow.mType = ESM::AI_CNDT; + newRow.mCellName = ""; + + if (position >= (int)list.size()) + list.push_back(newRow); + else + list.insert(list.begin()+position, newRow); + + record.setModified (actor); + } + + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT actor = record.get(); + + std::vector& list = actor.mAiPackage.mList; + + if (rowToRemove < 0 || rowToRemove >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + list.erase (list.begin () + rowToRemove); + + record.setModified (actor); + } + + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT actor = record.get(); + + actor.mAiPackage.mList = + static_cast >&>(nestedTable).mNestedTable; + + record.setModified (actor); + } + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(record.get().mAiPackage.mList); + } + + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + const std::vector& list = record.get().mAiPackage.mList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + const ESM::AIPackage& content = list.at(subRowIndex); + + switch (subColIndex) + { + case 0: + switch (content.mType) + { + case ESM::AI_Wander: return QString("AI Wander"); + case ESM::AI_Travel: return QString("AI Travel"); + case ESM::AI_Follow: return QString("AI Follow"); + case ESM::AI_Escort: return QString("AI Escort"); + case ESM::AI_Activate: return QString("AI Activate"); + case ESM::AI_CNDT: + default: return QString("None"); + } + case 1: // wander dist + if (content.mType == ESM::AI_Wander) + return content.mWander.mDistance; + else + return QVariant(); + case 2: // wander dur + if (content.mType == ESM::AI_Wander || + content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) + return content.mWander.mDuration; + else + return QVariant(); + case 3: // wander ToD + if (content.mType == ESM::AI_Wander) + return content.mWander.mTimeOfDay; // FIXME: not sure of the format + else + return QVariant(); + case 4: // wander idle + if (content.mType == ESM::AI_Wander) + { + return static_cast(content.mWander.mIdle[0]); // FIXME: + } + else + return QVariant(); + case 5: // wander repeat + if (content.mType == ESM::AI_Wander) + return QString(content.mWander.mShouldRepeat ? "Yes" : "No"); + else + return QVariant(); + case 6: // activate name + if (content.mType == ESM::AI_Activate) + return QString(content.mActivate.mName.toString().c_str()); + else + return QVariant(); + case 7: // target id + if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) + return QString(content.mTarget.mId.toString().c_str()); + else + return QVariant(); + case 8: // target cell + if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) + return QString::fromUtf8(content.mCellName.c_str()); + else + return QVariant(); + case 9: + if (content.mType == ESM::AI_Travel) + return content.mTravel.mX; + else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) + return content.mTarget.mX; + else + return QVariant(); + case 10: + if (content.mType == ESM::AI_Travel) + return content.mTravel.mY; + else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) + return content.mTarget.mY; + else + return QVariant(); + case 11: + if (content.mType == ESM::AI_Travel) + return content.mTravel.mZ; + else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) + return content.mTarget.mZ; + else + return QVariant(); + default: + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + } + } + + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (row, mType))); + ESXRecordT actor = record.get(); + std::vector& list = actor.mAiPackage.mList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + ESM::AIPackage& content = list.at(subRowIndex); + + switch(subColIndex) + { + case 0: // ai package type + if ("AI Wander" == value.toString().toStdString()) + content.mType = ESM::AI_Wander; + else if ("AI Travel" == value.toString().toStdString()) + content.mType = ESM::AI_Travel; + else if ("AI Follow" == value.toString().toStdString()) + content.mType = ESM::AI_Follow; + else if ("AI Escort" == value.toString().toStdString()) + content.mType = ESM::AI_Escort; + else if ("AI Activate" == value.toString().toStdString()) + content.mType = ESM::AI_Activate; + else + content.mType = ESM::AI_CNDT; + break; // always save + + case 1: + if (content.mType == ESM::AI_Wander) + content.mWander.mDistance = static_cast(value.toInt()); + else + return; // return without saving + case 2: + if (content.mType == ESM::AI_Wander || + content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) + content.mWander.mDuration = static_cast(value.toInt()); + else + return; // return without saving + case 3: + if (content.mType == ESM::AI_Wander) + content.mWander.mTimeOfDay = static_cast(value.toInt()); + else + return; // return without saving + case 4: + if (content.mType == ESM::AI_Wander) + break; // FIXME: idle + else + return; // return without saving + case 5: + if (content.mType == ESM::AI_Wander) + { + if ("Yes" == value.toString().toStdString()) + content.mWander.mShouldRepeat = 1; + if ("No" == value.toString().toStdString()) + content.mWander.mShouldRepeat = 0; + else + return; // return without saving + } + case 6: // NAME32 + if (content.mType == ESM::AI_Activate) + { + content.mActivate.mName.assign(value.toString().toUtf8().constData()); + break; + } + else + return; // return without saving + case 7: // NAME32 + if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) + { + content.mTarget.mId.assign(value.toString().toUtf8().constData()); + break; + } + else + return; // return without saving + case 8: + if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) + { + content.mCellName = std::string(value.toString().toUtf8().constData()); + break; + } + else + return; // return without saving + case 9: + if (content.mType == ESM::AI_Travel) + content.mTravel.mZ = value.toFloat(); + else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) + content.mTarget.mZ = value.toFloat(); + else + return; // return without saving + case 10: + if (content.mType == ESM::AI_Travel) + content.mTravel.mZ = value.toFloat(); + else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) + content.mTarget.mZ = value.toFloat(); + else + return; // return without saving + case 11: + if (content.mType == ESM::AI_Travel) + content.mTravel.mZ = value.toFloat(); + else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort) + content.mTarget.mZ = value.toFloat(); + else + return; // return without saving + default: + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + } + + record.setModified (actor); + } + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const + { + return 12; + } + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + return static_cast(record.get().mAiPackage.mList.size()); + } + }; } #endif diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 3f14ba4ac..000426a0b 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -180,6 +180,42 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_RotZ, CSMWorld::ColumnBase::Display_Float)); + // Nested table + mColumns.push_back(RefIdColumn (Columns::ColumnId_AiPackageList, ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); + actorsColumns.mAiPackages = &mColumns.back(); + + std::map aiMap; + aiMap.insert( + std::make_pair(UniversalId::Type_Npc, new ActorAiRefIdAdapter (UniversalId::Type_Npc))); + aiMap.insert( + std::make_pair(UniversalId::Type_Creature, new ActorAiRefIdAdapter (UniversalId::Type_Creature))); + + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), aiMap)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_AiPackage, CSMWorld::ColumnBase::Display_String)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_AiWanderDist, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_AiWanderDuration, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_AiWanderToD, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_AiWanderIdle, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_AiWanderRepeat, CSMWorld::ColumnBase::Display_String)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_AiActivateName, CSMWorld::ColumnBase::Display_String)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_AiTargetId, CSMWorld::ColumnBase::Display_String)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_AiTargetCell, CSMWorld::ColumnBase::Display_String)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_PosX, CSMWorld::ColumnBase::Display_Float)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_PosY, CSMWorld::ColumnBase::Display_Float)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_PosZ, CSMWorld::ColumnBase::Display_Float)); + static const struct { int mName; From 513c3a47cb8d54b6dea46bdb5816bde1f5739aa8 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 13 Apr 2015 21:08:23 +1000 Subject: [PATCH 714/740] Add clothing/armor part reference table to dialogue subview. --- apps/opencs/model/world/columns.cpp | 7 +- apps/opencs/model/world/columns.hpp | 7 +- .../model/world/nestedcoladapterimp.hpp | 2 +- apps/opencs/model/world/refidadapterimp.cpp | 16 +- apps/opencs/model/world/refidadapterimp.hpp | 199 ++++++++++++++++-- apps/opencs/model/world/refidcollection.cpp | 24 ++- 6 files changed, 222 insertions(+), 33 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 92a0d8f8d..547efac56 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -250,7 +250,7 @@ namespace CSMWorld { ColumnId_AiPackageList, "Ai Packages"}, { ColumnId_AiPackage, "Package"}, { ColumnId_AiWanderDist, "Wander Dist"}, - { ColumnId_AiWanderDuration, "Wander Duration"}, + { ColumnId_AiDuration, "Duration"}, { ColumnId_AiWanderToD, "Wander ToD"}, { ColumnId_AiWanderIdle, "Wander Idle"}, { ColumnId_AiWanderRepeat, "Wander Repeat"}, @@ -258,6 +258,11 @@ namespace CSMWorld { ColumnId_AiTargetId, "Target ID"}, { ColumnId_AiTargetCell, "Target Cell"}, + { ColumnId_PartRefList, "Part Reference"}, + { ColumnId_PartRefType, "Type"}, + { ColumnId_PartRefMale, "Male"}, + { ColumnId_PartRefFemale, "Female"}, + { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue3, "Use value 3" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 2788966a7..6068ea6e7 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -239,7 +239,7 @@ namespace CSMWorld ColumnId_AiPackageList = 219, ColumnId_AiPackage = 220, ColumnId_AiWanderDist = 221, - ColumnId_AiWanderDuration = 222, + ColumnId_AiDuration = 222, ColumnId_AiWanderToD = 223, ColumnId_AiWanderIdle = 224, ColumnId_AiWanderRepeat = 225, @@ -248,6 +248,11 @@ namespace CSMWorld ColumnId_AiTargetId = 227, ColumnId_AiTargetCell = 228, + ColumnId_PartRefList = 229, + ColumnId_PartRefType = 230, + ColumnId_PartRefMale = 231, + ColumnId_PartRefFemale = 232, + // 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/nestedcoladapterimp.hpp b/apps/opencs/model/world/nestedcoladapterimp.hpp index 3328396fb..2aa1123a3 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.hpp +++ b/apps/opencs/model/world/nestedcoladapterimp.hpp @@ -175,7 +175,7 @@ namespace CSMWorld { ESXRecordT raceOrBthSgn = record.get(); - raceOrBthSgn.mPowers.mList = + raceOrBthSgn.mPowers.mList = static_cast >&>(nestedTable).mNestedTable; record.setModified (raceOrBthSgn); diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index cd3a20327..98c1b6f0f 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -81,9 +81,10 @@ void CSMWorld::ApparatusRefIdAdapter::setData (const RefIdColumn *column, RefIdD CSMWorld::ArmorRefIdAdapter::ArmorRefIdAdapter (const EnchantableColumns& columns, - const RefIdColumn *type, const RefIdColumn *health, const RefIdColumn *armor) + const RefIdColumn *type, const RefIdColumn *health, const RefIdColumn *armor, + const RefIdColumn *partRef) : EnchantableRefIdAdapter (UniversalId::Type_Armor, columns), - mType (type), mHealth (health), mArmor (armor) + mType (type), mHealth (health), mArmor (armor), mPartRef(partRef) {} QVariant CSMWorld::ArmorRefIdAdapter::getData (const RefIdColumn *column, @@ -101,6 +102,9 @@ QVariant CSMWorld::ArmorRefIdAdapter::getData (const RefIdColumn *column, if (column==mArmor) return record.get().mData.mArmor; + if (column==mPartRef) + return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() + return EnchantableRefIdAdapter::getData (column, data, index); } @@ -156,8 +160,9 @@ void CSMWorld::BookRefIdAdapter::setData (const RefIdColumn *column, RefIdData& } CSMWorld::ClothingRefIdAdapter::ClothingRefIdAdapter (const EnchantableColumns& columns, - const RefIdColumn *type) -: EnchantableRefIdAdapter (UniversalId::Type_Clothing, columns), mType (type) + const RefIdColumn *type, const RefIdColumn *partRef) +: EnchantableRefIdAdapter (UniversalId::Type_Clothing, columns), mType (type), + mPartRef(partRef) {} QVariant CSMWorld::ClothingRefIdAdapter::getData (const RefIdColumn *column, @@ -169,6 +174,9 @@ QVariant CSMWorld::ClothingRefIdAdapter::getData (const RefIdColumn *column, if (column==mType) return record.get().mData.mType; + if (column==mPartRef) + return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() + return EnchantableRefIdAdapter::getData (column, data, index); } diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index c0fcba43c..bc00d31f9 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -622,11 +622,12 @@ namespace CSMWorld const RefIdColumn *mType; const RefIdColumn *mHealth; const RefIdColumn *mArmor; + const RefIdColumn *mPartRef; public: ArmorRefIdAdapter (const EnchantableColumns& columns, const RefIdColumn *type, - const RefIdColumn *health, const RefIdColumn *armor); + const RefIdColumn *health, const RefIdColumn *armor, const RefIdColumn *partRef); virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; @@ -657,10 +658,12 @@ namespace CSMWorld class ClothingRefIdAdapter : public EnchantableRefIdAdapter { const RefIdColumn *mType; + const RefIdColumn *mPartRef; public: - ClothingRefIdAdapter (const EnchantableColumns& columns, const RefIdColumn *type); + ClothingRefIdAdapter (const EnchantableColumns& columns, + const RefIdColumn *type, const RefIdColumn *partRef); virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; @@ -1290,27 +1293,13 @@ namespace CSMWorld switch (subColIndex) { - case 0: - return QString::fromUtf8(content.mCellName.c_str()); - - case 1: - return content.mPos.pos[0]; - - case 2: - return content.mPos.pos[1]; - - case 3: - return content.mPos.pos[2]; - - case 4: - return content.mPos.rot[0]; - - case 5: - return content.mPos.rot[1]; - - case 6: - return content.mPos.rot[2]; - + case 0: return QString::fromUtf8(content.mCellName.c_str()); + case 1: return content.mPos.pos[0]; + case 2: return content.mPos.pos[1]; + case 3: return content.mPos.pos[2]; + case 4: return content.mPos.rot[0]; + case 5: return content.mPos.rot[1]; + case 6: return content.mPos.rot[2]; default: throw std::runtime_error("Trying to access non-existing column in the nested table!"); } @@ -1675,6 +1664,170 @@ namespace CSMWorld return static_cast(record.get().mAiPackage.mList.size()); } }; + + static const char *sPartRefs[ESM::PRT_Count] = + { + "Head", "Hair", "Neck", "Cuirass", "Groin", + "Skirt", "Right Hand", "Left Hand", "Right Wrist", "Left Wrist", + "Shield", "Right Forearm", "Left Forearm", "Right Upperarm", "Left Upperarm", + "Right Foot", "Left Foot", "Right Ankle", "Left Ankle", "Right Knee", + "Left Knee", "Right Leg", "Left Leg", "Right Pauldron", "Left Pauldron", + "Weapon", "Tail" + }; + + template + class BodyPartRefIdAdapter : public NestedRefIdAdapterBase + { + UniversalId::Type mType; + + // not implemented + BodyPartRefIdAdapter (const BodyPartRefIdAdapter&); + BodyPartRefIdAdapter& operator= (const BodyPartRefIdAdapter&); + + public: + + BodyPartRefIdAdapter(UniversalId::Type type) :mType(type) {} + + virtual ~BodyPartRefIdAdapter() {} + + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT apparel = record.get(); + + std::vector& list = apparel.mParts.mParts; + + ESM::PartReference newPart; + newPart.mPart = 0; // 0 == head + newPart.mMale = ""; + newPart.mFemale = ""; + + if (position >= (int)list.size()) + list.push_back(newPart); + else + list.insert(list.begin()+position, newPart); + + record.setModified (apparel); + } + + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT apparel = record.get(); + + std::vector& list = apparel.mParts.mParts; + + if (rowToRemove < 0 || rowToRemove >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + list.erase (list.begin () + rowToRemove); + + record.setModified (apparel); + } + + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT apparel = record.get(); + + apparel.mParts.mParts = + static_cast >&>(nestedTable).mNestedTable; + + record.setModified (apparel); + } + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(record.get().mParts.mParts); + } + + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + const std::vector& list = record.get().mParts.mParts; + + if (subRowIndex < 0 || subRowIndex >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + const ESM::PartReference& content = list.at(subRowIndex); + + switch (subColIndex) + { + case 0: return QString(sPartRefs[content.mPart]); + case 1: return QString(content.mMale.c_str()); + case 2: return QString(content.mFemale.c_str()); + default: + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + } + } + + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (row, mType))); + ESXRecordT apparel = record.get(); + std::vector& list = apparel.mParts.mParts; + + if (subRowIndex < 0 || subRowIndex >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + switch(subColIndex) + { + case 0: + { + std::string part = value.toString().toStdString(); + bool found = false; + for (unsigned int i = 0; i < ESM::PRT_Count; ++i) + { + if (part == sPartRefs[i]) + { + list.at(subRowIndex).mPart = static_cast(i); + found = true; + break; + } + } + if (!found) + return; // return without saving + else + break; + } + case 1: list.at(subRowIndex).mMale = value.toString().toStdString(); break; + case 2: list.at(subRowIndex).mFemale = value.toString().toStdString(); break; + default: + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + } + + record.setModified (apparel); + } + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const + { + return 3; + } + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + return static_cast(record.get().mParts.mParts.size()); + } + }; } #endif diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 000426a0b..48f95451c 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -196,7 +196,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_AiWanderDist, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_AiWanderDuration, CSMWorld::ColumnBase::Display_Integer)); + new RefIdColumn (Columns::ColumnId_AiDuration, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_AiWanderToD, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( @@ -475,6 +475,24 @@ CSMWorld::RefIdCollection::RefIdCollection() weaponColumns.mFlags.insert (std::make_pair (&mColumns.back(), sWeaponFlagTable[i].mFlag)); } + // Nested table + mColumns.push_back(RefIdColumn (Columns::ColumnId_PartRefList, ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); + const RefIdColumn *partRef = &mColumns.back(); + + std::map partMap; + partMap.insert( + std::make_pair(UniversalId::Type_Armor, new BodyPartRefIdAdapter (UniversalId::Type_Armor))); + partMap.insert( + std::make_pair(UniversalId::Type_Clothing, new BodyPartRefIdAdapter (UniversalId::Type_Clothing))); + + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), partMap)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_PartRefType, CSMWorld::ColumnBase::Display_String)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_PartRefMale, CSMWorld::ColumnBase::Display_String)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_PartRefFemale, CSMWorld::ColumnBase::Display_String)); + mAdapters.insert (std::make_pair (UniversalId::Type_Activator, new NameRefIdAdapter (UniversalId::Type_Activator, nameColumns))); mAdapters.insert (std::make_pair (UniversalId::Type_Potion, @@ -482,11 +500,11 @@ CSMWorld::RefIdCollection::RefIdCollection() mAdapters.insert (std::make_pair (UniversalId::Type_Apparatus, new ApparatusRefIdAdapter (inventoryColumns, apparatusType, toolsColumns.mQuality))); mAdapters.insert (std::make_pair (UniversalId::Type_Armor, - new ArmorRefIdAdapter (enchantableColumns, armorType, health, armor))); + new ArmorRefIdAdapter (enchantableColumns, armorType, health, armor, partRef))); mAdapters.insert (std::make_pair (UniversalId::Type_Book, new BookRefIdAdapter (enchantableColumns, scroll, attribute))); mAdapters.insert (std::make_pair (UniversalId::Type_Clothing, - new ClothingRefIdAdapter (enchantableColumns, clothingType))); + new ClothingRefIdAdapter (enchantableColumns, clothingType, partRef))); mAdapters.insert (std::make_pair (UniversalId::Type_Container, new ContainerRefIdAdapter (nameColumns, weightCapacity, organic, respawn, content))); mAdapters.insert (std::make_pair (UniversalId::Type_Creature, From 1c7ed795c2c45daa7707bac70be534a811bd691c Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 13 Apr 2015 22:21:27 +1000 Subject: [PATCH 715/740] Add creature/item levelled lists to dialogue subview. --- apps/opencs/model/world/columns.cpp | 4 + apps/opencs/model/world/columns.hpp | 4 + apps/opencs/model/world/refidadapterimp.hpp | 182 ++++++++++++++++++++ apps/opencs/model/world/refidcollection.cpp | 109 ++++++------ 4 files changed, 250 insertions(+), 49 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 547efac56..83d6ceb57 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -263,6 +263,10 @@ namespace CSMWorld { ColumnId_PartRefMale, "Male"}, { ColumnId_PartRefFemale, "Female"}, + { ColumnId_LevelledList,"Levelled List"}, + { ColumnId_LevelledItemId,"Item ID"}, + { ColumnId_LevelledItemLevel,"Level"}, + { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue3, "Use value 3" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 6068ea6e7..81cae5e36 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -253,6 +253,10 @@ namespace CSMWorld ColumnId_PartRefMale = 231, ColumnId_PartRefFemale = 232, + ColumnId_LevelledList = 233, + ColumnId_LevelledItemId = 234, + ColumnId_LevelledItemLevel = 235, + // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. ColumnId_UseValue1 = 0x10000, diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index bc00d31f9..d09aaaa45 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -1828,6 +1828,188 @@ namespace CSMWorld return static_cast(record.get().mParts.mParts.size()); } }; + + struct LevListColumns : public BaseColumns + { + const RefIdColumn *mLevList; + + LevListColumns (const BaseColumns& base) : BaseColumns (base) {} + }; + + template + class LevelledListRefIdAdapter : public BaseRefIdAdapter + { + LevListColumns mLevList; + + public: + + LevelledListRefIdAdapter (UniversalId::Type type, const LevListColumns &columns); + + virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) + const; + + virtual void setData (const RefIdColumn *column, RefIdData& data, int index, + const QVariant& value) const; + ///< If the data type does not match an exception is thrown. + }; + + template + LevelledListRefIdAdapter::LevelledListRefIdAdapter (UniversalId::Type type, + const LevListColumns &columns) + : BaseRefIdAdapter (type, columns), mLevList (columns) + {} + + template + QVariant LevelledListRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, + int index) const + { + if (column==mLevList.mLevList) + return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() + + return BaseRefIdAdapter::getData (column, data, index); + } + + template + void LevelledListRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index, + const QVariant& value) const + { + BaseRefIdAdapter::setData (column, data, index, value); + return; + } + + template + class NestedLevListRefIdAdapter : public NestedRefIdAdapterBase + { + UniversalId::Type mType; + + // not implemented + NestedLevListRefIdAdapter (const NestedLevListRefIdAdapter&); + NestedLevListRefIdAdapter& operator= (const NestedLevListRefIdAdapter&); + + public: + + NestedLevListRefIdAdapter(UniversalId::Type type) :mType(type) {} + + virtual ~NestedLevListRefIdAdapter() {} + + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT leveled = record.get(); + + std::vector& list = leveled.mList; + + ESM::LevelledListBase::LevelItem newItem; + newItem.mId = ""; + newItem.mLevel = 0; + + if (position >= (int)list.size()) + list.push_back(newItem); + else + list.insert(list.begin()+position, newItem); + + record.setModified (leveled); + } + + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT leveled = record.get(); + + std::vector& list = leveled.mList; + + if (rowToRemove < 0 || rowToRemove >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + list.erase (list.begin () + rowToRemove); + + record.setModified (leveled); + } + + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + ESXRecordT leveled = record.get(); + + leveled.mList = + static_cast >&>(nestedTable).mNestedTable; + + record.setModified (leveled); + } + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(record.get().mList); + } + + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + const std::vector& list = record.get().mList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + const ESM::LevelledListBase::LevelItem& content = list.at(subRowIndex); + + switch (subColIndex) + { + case 0: return QString(content.mId.c_str()); + case 1: return content.mLevel; + default: + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + } + } + + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (row, mType))); + ESXRecordT leveled = record.get(); + std::vector& list = leveled.mList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (list.size())) + throw std::runtime_error ("index out of range"); + + switch(subColIndex) + { + case 0: list.at(subRowIndex).mId = value.toString().toStdString(); break; + case 1: list.at(subRowIndex).mLevel = static_cast(value.toInt()); break; + default: + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + } + + record.setModified (leveled); + } + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const + { + return 2; + } + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + return static_cast(record.get().mList.size()); + } + }; } #endif diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 48f95451c..be5d67766 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -73,14 +73,13 @@ CSMWorld::RefIdCollection::RefIdCollection() // nested table PotionColumns potionColumns (inventoryColumns); - mColumns.push_back (RefIdColumn (Columns::ColumnId_EffectList, ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); + mColumns.push_back (RefIdColumn (Columns::ColumnId_EffectList, + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); potionColumns.mEffects = &mColumns.back(); // see refidadapterimp.hpp - std::map effectsMap; - effectsMap.insert( - std::make_pair(UniversalId::Type_Potion, new EffectsRefIdAdapter (UniversalId::Type_Potion))); + effectsMap.insert(std::make_pair(UniversalId::Type_Potion, + new EffectsRefIdAdapter (UniversalId::Type_Potion))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), effectsMap)); - mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_String/*, false*/)); mColumns.back().addColumn( @@ -126,15 +125,14 @@ CSMWorld::RefIdCollection::RefIdCollection() actorsColumns.mAlarm = &mColumns.back(); // Nested table - mColumns.push_back(RefIdColumn (Columns::ColumnId_ActorInventory, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue)); + mColumns.push_back(RefIdColumn (Columns::ColumnId_ActorInventory, + ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue)); actorsColumns.mInventory = &mColumns.back(); - std::map inventoryMap; - inventoryMap.insert( - std::make_pair(UniversalId::Type_Npc, new NestedInventoryRefIdAdapter (UniversalId::Type_Npc))); - inventoryMap.insert( - std::make_pair(UniversalId::Type_Creature, new NestedInventoryRefIdAdapter (UniversalId::Type_Creature))); - + inventoryMap.insert(std::make_pair(UniversalId::Type_Npc, + new NestedInventoryRefIdAdapter (UniversalId::Type_Npc))); + inventoryMap.insert(std::make_pair(UniversalId::Type_Creature, + new NestedInventoryRefIdAdapter (UniversalId::Type_Creature))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), inventoryMap)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String)); @@ -142,28 +140,27 @@ CSMWorld::RefIdCollection::RefIdCollection() new RefIdColumn (Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer)); // Nested table - mColumns.push_back(RefIdColumn (Columns::ColumnId_SpellList, ColumnBase::Display_NestedSpellList, ColumnBase::Flag_Dialogue)); + mColumns.push_back(RefIdColumn (Columns::ColumnId_SpellList, + ColumnBase::Display_NestedSpellList, ColumnBase::Flag_Dialogue)); actorsColumns.mSpells = &mColumns.back(); - std::map spellsMap; - spellsMap.insert( - std::make_pair(UniversalId::Type_Npc, new NestedSpellRefIdAdapter (UniversalId::Type_Npc))); - spellsMap.insert( - std::make_pair(UniversalId::Type_Creature, new NestedSpellRefIdAdapter (UniversalId::Type_Creature))); - + spellsMap.insert(std::make_pair(UniversalId::Type_Npc, + new NestedSpellRefIdAdapter (UniversalId::Type_Npc))); + spellsMap.insert(std::make_pair(UniversalId::Type_Creature, + new NestedSpellRefIdAdapter (UniversalId::Type_Creature))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), spellsMap)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_SpellId, CSMWorld::ColumnBase::Display_String)); // Nested table - mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcDestinations, ColumnBase::Display_NestedDestinationsList, ColumnBase::Flag_Dialogue)); + mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcDestinations, + ColumnBase::Display_NestedDestinationsList, ColumnBase::Flag_Dialogue)); actorsColumns.mDestinations = &mColumns.back(); - std::map destMap; - destMap.insert( - std::make_pair(UniversalId::Type_Npc, new NestedTravelRefIdAdapter (UniversalId::Type_Npc))); - destMap.insert( - std::make_pair(UniversalId::Type_Creature, new NestedTravelRefIdAdapter (UniversalId::Type_Creature))); + destMap.insert(std::make_pair(UniversalId::Type_Npc, + new NestedTravelRefIdAdapter (UniversalId::Type_Npc))); + destMap.insert(std::make_pair(UniversalId::Type_Creature, + new NestedTravelRefIdAdapter (UniversalId::Type_Creature))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), destMap)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_DestinationCell, CSMWorld::ColumnBase::Display_String)); @@ -181,15 +178,14 @@ CSMWorld::RefIdCollection::RefIdCollection() new RefIdColumn (Columns::ColumnId_RotZ, CSMWorld::ColumnBase::Display_Float)); // Nested table - mColumns.push_back(RefIdColumn (Columns::ColumnId_AiPackageList, ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); + mColumns.push_back(RefIdColumn (Columns::ColumnId_AiPackageList, + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); actorsColumns.mAiPackages = &mColumns.back(); - std::map aiMap; - aiMap.insert( - std::make_pair(UniversalId::Type_Npc, new ActorAiRefIdAdapter (UniversalId::Type_Npc))); - aiMap.insert( - std::make_pair(UniversalId::Type_Creature, new ActorAiRefIdAdapter (UniversalId::Type_Creature))); - + aiMap.insert(std::make_pair(UniversalId::Type_Npc, + new ActorAiRefIdAdapter (UniversalId::Type_Npc))); + aiMap.insert(std::make_pair(UniversalId::Type_Creature, + new ActorAiRefIdAdapter (UniversalId::Type_Creature))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), aiMap)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_AiPackage, CSMWorld::ColumnBase::Display_String)); @@ -284,14 +280,13 @@ CSMWorld::RefIdCollection::RefIdCollection() const RefIdColumn *respawn = &mColumns.back(); // Nested table - mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue)); + mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent, + ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue)); const RefIdColumn *content = &mColumns.back(); - std::map contMap; - contMap.insert( - std::make_pair(UniversalId::Type_Container, new NestedInventoryRefIdAdapter (UniversalId::Type_Container))); + contMap.insert(std::make_pair(UniversalId::Type_Container, + new NestedInventoryRefIdAdapter (UniversalId::Type_Container))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), contMap)); - mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String)); mColumns.back().addColumn( @@ -478,20 +473,36 @@ CSMWorld::RefIdCollection::RefIdCollection() // Nested table mColumns.push_back(RefIdColumn (Columns::ColumnId_PartRefList, ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); const RefIdColumn *partRef = &mColumns.back(); - std::map partMap; - partMap.insert( - std::make_pair(UniversalId::Type_Armor, new BodyPartRefIdAdapter (UniversalId::Type_Armor))); - partMap.insert( - std::make_pair(UniversalId::Type_Clothing, new BodyPartRefIdAdapter (UniversalId::Type_Clothing))); - + partMap.insert(std::make_pair(UniversalId::Type_Armor, + new BodyPartRefIdAdapter (UniversalId::Type_Armor))); + partMap.insert(std::make_pair(UniversalId::Type_Clothing, + new BodyPartRefIdAdapter (UniversalId::Type_Clothing))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), partMap)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_PartRefType, CSMWorld::ColumnBase::Display_String)); + new RefIdColumn (Columns::ColumnId_PartRefType, CSMWorld::ColumnBase::Display_String)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_PartRefMale, CSMWorld::ColumnBase::Display_String)); + new RefIdColumn (Columns::ColumnId_PartRefMale, CSMWorld::ColumnBase::Display_String)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_PartRefFemale, CSMWorld::ColumnBase::Display_String)); + new RefIdColumn (Columns::ColumnId_PartRefFemale, CSMWorld::ColumnBase::Display_String)); + + LevListColumns levListColumns (baseColumns); + + // Nested table + mColumns.push_back(RefIdColumn (Columns::ColumnId_LevelledList, + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); + levListColumns.mLevList = &mColumns.back(); + std::map levListMap; + levListMap.insert(std::make_pair(UniversalId::Type_CreatureLevelledList, + new NestedLevListRefIdAdapter (UniversalId::Type_CreatureLevelledList))); + levListMap.insert(std::make_pair(UniversalId::Type_ItemLevelledList, + new NestedLevListRefIdAdapter (UniversalId::Type_ItemLevelledList))); + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), levListMap)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_LevelledItemId, CSMWorld::ColumnBase::Display_String)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_LevelledItemLevel, CSMWorld::ColumnBase::Display_Integer)); + mAdapters.insert (std::make_pair (UniversalId::Type_Activator, new NameRefIdAdapter (UniversalId::Type_Activator, nameColumns))); @@ -514,10 +525,10 @@ CSMWorld::RefIdCollection::RefIdCollection() mAdapters.insert (std::make_pair (UniversalId::Type_Ingredient, new InventoryRefIdAdapter (UniversalId::Type_Ingredient, inventoryColumns))); mAdapters.insert (std::make_pair (UniversalId::Type_CreatureLevelledList, - new BaseRefIdAdapter ( - UniversalId::Type_CreatureLevelledList, baseColumns))); + new LevelledListRefIdAdapter ( + UniversalId::Type_CreatureLevelledList, levListColumns))); mAdapters.insert (std::make_pair (UniversalId::Type_ItemLevelledList, - new BaseRefIdAdapter (UniversalId::Type_ItemLevelledList, baseColumns))); + new LevelledListRefIdAdapter (UniversalId::Type_ItemLevelledList, levListColumns))); mAdapters.insert (std::make_pair (UniversalId::Type_Light, new LightRefIdAdapter (lightColumns))); mAdapters.insert (std::make_pair (UniversalId::Type_Lockpick, From a2d824bfa6a9e4422cc2c754a05b18d01186b45a Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 17 Apr 2015 01:27:36 +1000 Subject: [PATCH 716/740] Changes to support dialogue only items but in a list view via QDataWidgetMapper. --- apps/opencs/model/world/columnbase.hpp | 13 +-- apps/opencs/model/world/idtree.cpp | 3 +- .../model/world/nestedtableproxymodel.cpp | 33 +++++-- .../model/world/nestedtableproxymodel.hpp | 4 +- apps/opencs/view/world/dialoguesubview.cpp | 96 ++++++++++++++++--- apps/opencs/view/world/dialoguesubview.hpp | 27 +++--- apps/opencs/view/world/util.cpp | 2 +- 7 files changed, 134 insertions(+), 44 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index c7c8d3cd8..813de8d96 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -23,7 +23,8 @@ namespace CSMWorld enum Flags { Flag_Table = 1, // column should be displayed in table view - Flag_Dialogue = 2 // column should be displayed in dialogue view + Flag_Dialogue = 2, // column should be displayed in dialogue view + Flag_Dialogue_List = 4 // column should be diaplyed in dialogue view }; enum Display @@ -94,11 +95,11 @@ namespace CSMWorld Display_QuestStatusType, //Those are top level columns that nest other columns - Display_NestedItemList, - Display_NestedSpellList, - Display_NestedDestinationsList, - Display_PathgridPointList, - Display_PathgridEdgeList, + Display_NestedItemList, // delete? + Display_NestedSpellList, // delete? + Display_NestedDestinationsList, // delete? + Display_PathgridPointList, // delete? + Display_PathgridEdgeList, // delete? Display_NestedHeader, Display_EnchantmentType, diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp index eddde5a89..06db09a0f 100644 --- a/apps/opencs/model/world/idtree.cpp +++ b/apps/opencs/model/world/idtree.cpp @@ -93,8 +93,7 @@ bool CSMWorld::IdTree::setData (const QModelIndex &index, const QVariant &value, mNestedCollection->setNestedData(parentAddress.first, parentAddress.second, value, index.row(), index.column()); emit dataChanged (CSMWorld::IdTree::index (parentAddress.first, 0), - CSMWorld::IdTree::index (parentAddress.second, idCollection()->getColumns()-1)); - + CSMWorld::IdTree::index (parentAddress.first, idCollection()->getColumns()-1)); return true; } else diff --git a/apps/opencs/model/world/nestedtableproxymodel.cpp b/apps/opencs/model/world/nestedtableproxymodel.cpp index 0f137d78f..acf197716 100644 --- a/apps/opencs/model/world/nestedtableproxymodel.cpp +++ b/apps/opencs/model/world/nestedtableproxymodel.cpp @@ -32,12 +32,15 @@ CSMWorld::NestedTableProxyModel::NestedTableProxyModel(const QModelIndex& parent connect(mMainModel, SIGNAL(resetEnd(const QString&)), this, SLOT(forwardResetEnd(const QString&))); + + connect(mMainModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), + this, SLOT(forwardDataChanged(const QModelIndex &, const QModelIndex &))); } QModelIndex CSMWorld::NestedTableProxyModel::mapFromSource(const QModelIndex& sourceIndex) const { const QModelIndex& testedParent = mMainModel->parent(sourceIndex); - const QModelIndex& parent = mMainModel->getModelIndex (mId, mParentColumn); + const QModelIndex& parent = mMainModel->getNestedModelIndex (mId, mParentColumn); if (testedParent == parent) { return createIndex(sourceIndex.row(), sourceIndex.column()); @@ -75,13 +78,8 @@ QModelIndex CSMWorld::NestedTableProxyModel::index(int row, int column, const QM int rows = mMainModel->rowCount(parent); int columns = mMainModel->columnCount(parent); - if (row < 0 || - row >= rows || - column < 0 || - column >= columns) - { + if (row < 0 || row >= rows || column < 0 || column >= columns) return QModelIndex(); - } return createIndex(row, column); } @@ -103,6 +101,9 @@ QVariant CSMWorld::NestedTableProxyModel::data(const QModelIndex& index, int rol return mMainModel->data(mapToSource(index), role); } +// NOTE: Due to mapToSouce(index) the dataChanged() signal resulting from setData() will have the +// source model's index values. The indicies need to be converted to the proxy space values. +// See forwardDataChanged() bool CSMWorld::NestedTableProxyModel::setData (const QModelIndex & index, const QVariant & value, int role) { return mMainModel->setData(mapToSource(index), value, role); @@ -128,7 +129,8 @@ CSMWorld::IdTree* CSMWorld::NestedTableProxyModel::model() const return mMainModel; } -void CSMWorld::NestedTableProxyModel::forwardRowsAboutToInserted(const QModelIndex& parent, int first, int last) +void CSMWorld::NestedTableProxyModel::forwardRowsAboutToInserted(const QModelIndex& parent, + int first, int last) { if (indexIsParent(parent)) { @@ -151,7 +153,8 @@ bool CSMWorld::NestedTableProxyModel::indexIsParent(const QModelIndex& index) mMainModel->data(mMainModel->index(index.row(), 0)).toString().toUtf8().constData() == mId); } -void CSMWorld::NestedTableProxyModel::forwardRowsAboutToRemoved(const QModelIndex& parent, int first, int last) +void CSMWorld::NestedTableProxyModel::forwardRowsAboutToRemoved(const QModelIndex& parent, + int first, int last) { if (indexIsParent(parent)) { @@ -178,3 +181,15 @@ void CSMWorld::NestedTableProxyModel::forwardResetEnd(const QString& id) if (id.toUtf8() == mId.c_str()) endResetModel(); } + +void CSMWorld::NestedTableProxyModel::forwardDataChanged (const QModelIndex& topLeft, + const QModelIndex& bottomRight) +{ + const QModelIndex& parent = mMainModel->getNestedModelIndex (mId, mParentColumn); + + if (topLeft.column() <= parent.column() && bottomRight.column() >= parent.column()) + { + emit dataChanged(index(0,0), + index(mMainModel->rowCount(parent)-1, mMainModel->columnCount(parent)-1)); + } +} diff --git a/apps/opencs/model/world/nestedtableproxymodel.hpp b/apps/opencs/model/world/nestedtableproxymodel.hpp index f5cbdb10b..2d5a46c48 100644 --- a/apps/opencs/model/world/nestedtableproxymodel.hpp +++ b/apps/opencs/model/world/nestedtableproxymodel.hpp @@ -47,7 +47,7 @@ namespace CSMWorld virtual int columnCount(const QModelIndex& parent) const; - virtual QModelIndex index(int row, int column, const QModelIndex& parent) const; + virtual QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const; virtual QModelIndex parent(const QModelIndex& index) const; @@ -76,6 +76,8 @@ namespace CSMWorld void forwardResetStart(const QString& id); void forwardResetEnd(const QString& id); + + void forwardDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); }; } diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 79eb48534..88791c9cd 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -28,6 +28,7 @@ #include "../../model/world/columns.hpp" #include "../../model/world/record.hpp" #include "../../model/world/tablemimedata.hpp" +#include "../../model/world/idtree.hpp" #include "../../model/doc/document.hpp" #include "../../model/world/commands.hpp" @@ -175,9 +176,10 @@ void CSVWorld::DialogueDelegateDispatcherProxy::tableMimeDataDropped(const std:: ==============================DialogueDelegateDispatcher========================================== */ -CSVWorld::DialogueDelegateDispatcher::DialogueDelegateDispatcher(QObject* parent, CSMWorld::IdTable* table, CSMDoc::Document& document) : +CSVWorld::DialogueDelegateDispatcher::DialogueDelegateDispatcher(QObject* parent, + CSMWorld::IdTable* table, CSMDoc::Document& document, QAbstractItemModel *model) : mParent(parent), -mTable(table), +mTable(model ? model : table), mDocument (document), mNotEditableDelegate(table, parent) { @@ -199,7 +201,8 @@ CSVWorld::CommandDelegate* CSVWorld::DialogueDelegateDispatcher::makeDelegate(CS return delegate; } -void CSVWorld::DialogueDelegateDispatcher::editorDataCommited(QWidget* editor, const QModelIndex& index, CSMWorld::ColumnBase::Display display) +void CSVWorld::DialogueDelegateDispatcher::editorDataCommited(QWidget* editor, + const QModelIndex& index, CSMWorld::ColumnBase::Display display) { setModelData(editor, mTable, index, display); } @@ -231,12 +234,14 @@ void CSVWorld::DialogueDelegateDispatcher::setEditorData (QWidget* editor, const } } -void CSVWorld::DialogueDelegateDispatcher::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const +void CSVWorld::DialogueDelegateDispatcher::setModelData(QWidget* editor, + QAbstractItemModel* model, const QModelIndex& index) const { setModelData(editor, model, index, CSMWorld::ColumnBase::Display_None); } -void CSVWorld::DialogueDelegateDispatcher::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const +void CSVWorld::DialogueDelegateDispatcher::setModelData(QWidget* editor, + QAbstractItemModel* model, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const { std::map::const_iterator delegateIt(mDelegates.find(display)); if (delegateIt != mDelegates.end()) @@ -245,17 +250,20 @@ void CSVWorld::DialogueDelegateDispatcher::setModelData(QWidget* editor, QAbstra } } -void CSVWorld::DialogueDelegateDispatcher::paint (QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const +void CSVWorld::DialogueDelegateDispatcher::paint (QPainter* painter, + const QStyleOptionViewItem& option, const QModelIndex& index) const { //Does nothing } -QSize CSVWorld::DialogueDelegateDispatcher::sizeHint (const QStyleOptionViewItem& option, const QModelIndex& index) const +QSize CSVWorld::DialogueDelegateDispatcher::sizeHint (const QStyleOptionViewItem& option, + const QModelIndex& index) const { return QSize(); //silencing warning, otherwise does nothing } -QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase::Display display, const QModelIndex& index) +QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase::Display display, + const QModelIndex& index) { QVariant variant = index.data(); if (!variant.isValid()) @@ -270,14 +278,16 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: QWidget* editor = NULL; if (! (mTable->flags (index) & Qt::ItemIsEditable)) { - return mNotEditableDelegate.createEditor(qobject_cast(mParent), QStyleOptionViewItem(), index); + return mNotEditableDelegate.createEditor(qobject_cast(mParent), + QStyleOptionViewItem(), index); } std::map::iterator delegateIt(mDelegates.find(display)); if (delegateIt != mDelegates.end()) { - editor = delegateIt->second->createEditor(qobject_cast(mParent), QStyleOptionViewItem(), index, display); + editor = delegateIt->second->createEditor(qobject_cast(mParent), + QStyleOptionViewItem(), index, display); DialogueDelegateDispatcherProxy* proxy = new DialogueDelegateDispatcherProxy(editor, display); @@ -339,12 +349,15 @@ CSVWorld::EditWidget::~EditWidget() { delete mNestedModels[i]; } + delete mNestedTableDispatcher; } CSVWorld::EditWidget::EditWidget(QWidget *parent, int row, CSMWorld::IdTable* table, CSMDoc::Document& document, bool createAndDelete) : mDispatcher(this, table, document), +mNestedTableDispatcher(NULL), QScrollArea(parent), mWidgetMapper(NULL), +mNestedTableMapper(NULL), mMainWidget(NULL), mDocument (document), mTable(table) @@ -362,6 +375,7 @@ void CSVWorld::EditWidget::remake(int row) delete mNestedModels[i]; } mNestedModels.clear(); + delete mNestedTableDispatcher; if (mMainWidget) { @@ -376,6 +390,11 @@ void CSVWorld::EditWidget::remake(int row) delete mWidgetMapper; mWidgetMapper = 0; } + if (mNestedTableMapper) + { + delete mNestedTableMapper; + mNestedTableMapper = 0; + } mWidgetMapper = new QDataWidgetMapper (this); mWidgetMapper->setModel(mTable); @@ -417,7 +436,8 @@ void CSVWorld::EditWidget::remake(int row) CSMWorld::ColumnBase::Display display = static_cast (mTable->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); - if (mTable->hasChildren(mTable->index(row, i))) + if (mTable->hasChildren(mTable->index(row, i)) && + !(flags & CSMWorld::ColumnBase::Flag_Dialogue_List)) { mNestedModels.push_back(new CSMWorld::NestedTableProxyModel (mTable->index(row, i), display, dynamic_cast(mTable))); @@ -425,14 +445,15 @@ void CSVWorld::EditWidget::remake(int row) table->resizeColumnsToContents(); - QLabel* label = new QLabel (mTable->headerData (i, Qt::Horizontal, Qt::DisplayRole).toString(), mMainWidget); + QLabel* label = + new QLabel (mTable->headerData (i, Qt::Horizontal, Qt::DisplayRole).toString(), mMainWidget); label->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed); tablesLayout->addWidget(label); tablesLayout->addWidget(table); } - else + else if (!(flags & CSMWorld::ColumnBase::Flag_Dialogue_List)) { mDispatcher.makeDelegate (display); QWidget* editor = mDispatcher.makeEditor (display, (mTable->index (row, i))); @@ -460,6 +481,55 @@ void CSVWorld::EditWidget::remake(int row) } } } + else + { + mNestedModels.push_back(new CSMWorld::NestedTableProxyModel ( + static_cast(mTable)->index(row, i), + display, static_cast(mTable))); + mNestedTableMapper = new QDataWidgetMapper (this); + + mNestedTableMapper->setModel(mNestedModels.back()); + // FIXME: lack MIME support? + mNestedTableDispatcher = + new DialogueDelegateDispatcher (this, mTable, mDocument, mNestedModels.back()); + mNestedTableMapper->setItemDelegate(mNestedTableDispatcher); + + int columnCount = + mTable->columnCount(mTable->getModelIndex (mNestedModels.back()->getParentId(), i)); + for (int col = 0; col < columnCount; ++col) + { + int displayRole = mNestedModels.back()->headerData (col, + Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt(); + + CSMWorld::ColumnBase::Display display = + static_cast (displayRole); + + mNestedTableDispatcher->makeDelegate (display); + + // FIXME: assumed all columns are editable + QWidget* editor = + mNestedTableDispatcher->makeEditor (display, mNestedModels.back()->index (0, col)); + if (editor) + { + mNestedTableMapper->addMapping (editor, col); + + std::string disString = mNestedModels.back()->headerData (col, + Qt::Horizontal, Qt::DisplayRole).toString().toStdString(); + // Need ot use Qt::DisplayRole in order to get the correct string + // from CSMWorld::Columns + QLabel* label = new QLabel (mNestedModels.back()->headerData (col, + Qt::Horizontal, Qt::DisplayRole).toString(), mMainWidget); + + label->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed); + editor->setSizePolicy (QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); + + unlockedLayout->addWidget (label, unlocked, 0); + unlockedLayout->addWidget (editor, unlocked, 1); + ++unlocked; + } + } + mNestedTableMapper->setCurrentModelIndex(mNestedModels.back()->index(0, 0)); + } } } diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 72acb1966..067ff95f5 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -107,9 +107,9 @@ namespace CSVWorld QObject* mParent; - CSMWorld::IdTable* mTable; + QAbstractItemModel* mTable; - CSMDoc::Document& mDocument; + CSMDoc::Document& mDocument; NotEditableSubDelegate mNotEditableDelegate; @@ -119,22 +119,25 @@ namespace CSVWorld public: DialogueDelegateDispatcher(QObject* parent, CSMWorld::IdTable* table, - CSMDoc::Document& document); + CSMDoc::Document& document, + QAbstractItemModel* model = 0); ~DialogueDelegateDispatcher(); CSVWorld::CommandDelegate* makeDelegate(CSMWorld::ColumnBase::Display display); - QWidget* makeEditor(CSMWorld::ColumnBase::Display display, - const QModelIndex& index); - ///< will return null if delegate is not present, parent of the widget is same as for dispatcher itself + QWidget* makeEditor(CSMWorld::ColumnBase::Display display, const QModelIndex& index); + ///< will return null if delegate is not present, parent of the widget is + //same as for dispatcher itself - virtual void setEditorData (QWidget* editor, - const QModelIndex& index) const; + virtual void setEditorData (QWidget* editor, const QModelIndex& index) const; - virtual void setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const; + virtual void setModelData (QWidget* editor, QAbstractItemModel* model, + const QModelIndex& index) const; - virtual void setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const; + virtual void setModelData (QWidget* editor, + QAbstractItemModel* model, const QModelIndex& index, + CSMWorld::ColumnBase::Display display) const; virtual void paint (QPainter* painter, const QStyleOptionViewItem& option, @@ -153,15 +156,15 @@ namespace CSVWorld void tableMimeDataDropped(QWidget* editor, const QModelIndex& index, const CSMWorld::UniversalId& id, const CSMDoc::Document* document); - - }; class EditWidget : public QScrollArea { Q_OBJECT QDataWidgetMapper *mWidgetMapper; + QDataWidgetMapper *mNestedTableMapper; DialogueDelegateDispatcher mDispatcher; + DialogueDelegateDispatcher *mNestedTableDispatcher; QWidget* mMainWidget; CSMWorld::IdTable* mTable; CSMDoc::Document& mDocument; diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index f3b23100a..5694c6e5a 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -180,7 +180,7 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO case CSMWorld::ColumnBase::Display_Float: { QDoubleSpinBox *dsb = new QDoubleSpinBox(parent); - dsb->setRange(FLT_MIN, FLT_MAX); + dsb->setRange(-FLT_MAX, FLT_MAX); dsb->setSingleStep(0.01f); dsb->setDecimals(3); return dsb; From 4951fc477ca0ee0bee330f280ba613483d80a176 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 16 Apr 2015 18:50:22 +0200 Subject: [PATCH 717/740] added replace function --- apps/opencs/model/tools/reportmodel.cpp | 17 +++++- apps/opencs/model/tools/reportmodel.hpp | 4 +- apps/opencs/model/tools/search.cpp | 68 +++++++++++++++++++----- apps/opencs/model/tools/search.hpp | 12 +++-- apps/opencs/view/tools/reporttable.cpp | 59 +++++++++++++++++++- apps/opencs/view/tools/reporttable.hpp | 10 ++++ apps/opencs/view/tools/searchbox.cpp | 46 +++++++++++++--- apps/opencs/view/tools/searchbox.hpp | 6 +++ apps/opencs/view/tools/searchsubview.cpp | 37 +++++++++++-- apps/opencs/view/tools/searchsubview.hpp | 5 ++ 10 files changed, 234 insertions(+), 30 deletions(-) diff --git a/apps/opencs/model/tools/reportmodel.cpp b/apps/opencs/model/tools/reportmodel.cpp index 627199c22..5648ace54 100644 --- a/apps/opencs/model/tools/reportmodel.cpp +++ b/apps/opencs/model/tools/reportmodel.cpp @@ -80,7 +80,7 @@ QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const char type, ignore; int fieldIndex; - if ((stream >> type >> ignore >> fieldIndex) && type=='r') + if ((stream >> type >> ignore >> fieldIndex) && (type=='r' || type=='R')) { field = CSMWorld::Columns::getName ( static_cast (fieldIndex)); @@ -135,6 +135,21 @@ void CSMTools::ReportModel::add (const CSMWorld::UniversalId& id, const std::str endInsertRows(); } +void CSMTools::ReportModel::flagAsReplaced (int index) +{ + Line& line = mRows.at (index); + std::string hint = line.mHint; + + if (hint.empty() || hint[0]!='R') + throw std::logic_error ("trying to flag message as replaced that is not replaceable"); + + hint[0] = 'r'; + + line.mHint = hint; + + emit dataChanged (this->index (index, 0), this->index (index, columnCount())); +} + const CSMWorld::UniversalId& CSMTools::ReportModel::getUniversalId (int row) const { return mRows.at (row).mId; diff --git a/apps/opencs/model/tools/reportmodel.hpp b/apps/opencs/model/tools/reportmodel.hpp index 7e733fab6..4d2d0542f 100644 --- a/apps/opencs/model/tools/reportmodel.hpp +++ b/apps/opencs/model/tools/reportmodel.hpp @@ -49,10 +49,12 @@ namespace CSMTools virtual QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; virtual bool removeRows (int row, int count, const QModelIndex& parent = QModelIndex()); - + void add (const CSMWorld::UniversalId& id, const std::string& message, const std::string& hint = ""); + void flagAsReplaced (int index); + const CSMWorld::UniversalId& getUniversalId (int row) const; std::string getHint (int row) const; diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index db495be11..cb8850754 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -4,14 +4,16 @@ #include #include -#include "../../model/doc/messages.hpp" +#include "../doc/messages.hpp" +#include "../doc/document.hpp" -#include "../../model/world/idtablebase.hpp" -#include "../../model/world/columnbase.hpp" -#include "../../model/world/universalid.hpp" +#include "../world/idtablebase.hpp" +#include "../world/columnbase.hpp" +#include "../world/universalid.hpp" +#include "../world/commands.hpp" void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model, - const QModelIndex& index, const CSMWorld::UniversalId& id, + const QModelIndex& index, const CSMWorld::UniversalId& id, bool writable, CSMDoc::Messages& messages) const { // using QString here for easier handling of case folding. @@ -25,7 +27,8 @@ void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model, { std::ostringstream hint; hint - << "r: " + << (writable ? 'R' : 'r') + <<": " << model->getColumnId (index.column()) << " " << pos << " " << search.length(); @@ -37,7 +40,7 @@ void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model, } void CSMTools::Search::searchRegExCell (const CSMWorld::IdTableBase *model, - const QModelIndex& index, const CSMWorld::UniversalId& id, + const QModelIndex& index, const CSMWorld::UniversalId& id, bool writable, CSMDoc::Messages& messages) const { QString text = model->data (index).toString(); @@ -49,7 +52,12 @@ void CSMTools::Search::searchRegExCell (const CSMWorld::IdTableBase *model, int length = mRegExp.matchedLength(); std::ostringstream hint; - hint << "r: " << model->getColumnId (index.column()) << " " << pos << " " << length; + hint + << (writable ? 'R' : 'r') + <<": " + << model->getColumnId (index.column()) + << " " << pos + << " " << length; messages.add (id, formatDescription (text, pos, length).toUtf8().data(), hint.str()); @@ -58,8 +66,11 @@ void CSMTools::Search::searchRegExCell (const CSMWorld::IdTableBase *model, } void CSMTools::Search::searchRecordStateCell (const CSMWorld::IdTableBase *model, - const QModelIndex& index, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) const + const QModelIndex& index, const CSMWorld::UniversalId& id, bool writable, CSMDoc::Messages& messages) const { + if (writable) + throw std::logic_error ("Record state can not be modified by search and replace"); + int data = model->data (index).toInt(); if (data==mValue) @@ -203,24 +214,26 @@ void CSMTools::Search::searchRow (const CSMWorld::IdTableBase *model, int row, CSMWorld::UniversalId id ( type, model->data (model->index (row, mIdColumn)).toString().toUtf8().data()); - + + bool writable = model->flags (index) & Qt::ItemIsEditable; + switch (mType) { case Type_Text: case Type_Id: - searchTextCell (model, index, id, messages); + searchTextCell (model, index, id, writable, messages); break; case Type_TextRegEx: case Type_IdRegEx: - searchRegExCell (model, index, id, messages); + searchRegExCell (model, index, id, writable, messages); break; case Type_RecordState: - searchRecordStateCell (model, index, id, messages); + searchRecordStateCell (model, index, id, writable, messages); break; case Type_None: @@ -235,3 +248,32 @@ void CSMTools::Search::setPadding (int before, int after) mPaddingBefore = before; mPaddingAfter = after; } + +void CSMTools::Search::replace (CSMDoc::Document& document, CSMWorld::IdTableBase *model, + const CSMWorld::UniversalId& id, const std::string& messageHint, + const std::string& replaceText) const +{ + std::istringstream stream (messageHint.c_str()); + + char hint, ignore; + int columnId, pos, length; + + if (stream >> hint >> ignore >> columnId >> pos >> length) + { + int column = + model->findColumnIndex (static_cast (columnId)); + + QModelIndex index = model->getModelIndex (id.getId(), column); + + std::string text = model->data (index).toString().toUtf8().constData(); + + std::string before = text.substr (0, pos); + std::string after = text.substr (pos+length); + + std::string newText = before + replaceText + after; + + document.getUndoStack().push ( + new CSMWorld::ModifyCommand (*model, index, QString::fromUtf8 (newText.c_str()))); + } +} + diff --git a/apps/opencs/model/tools/search.hpp b/apps/opencs/model/tools/search.hpp index 452b3cad2..c9dfc4c44 100644 --- a/apps/opencs/model/tools/search.hpp +++ b/apps/opencs/model/tools/search.hpp @@ -12,6 +12,7 @@ class QModelIndex; namespace CSMDoc { class Messages; + class Document; } namespace CSMWorld @@ -49,13 +50,13 @@ namespace CSMTools int mPaddingAfter; void searchTextCell (const CSMWorld::IdTableBase *model, const QModelIndex& index, - const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) const; + const CSMWorld::UniversalId& id, bool writable, CSMDoc::Messages& messages) const; void searchRegExCell (const CSMWorld::IdTableBase *model, const QModelIndex& index, - const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) const; + const CSMWorld::UniversalId& id, bool writable, CSMDoc::Messages& messages) const; void searchRecordStateCell (const CSMWorld::IdTableBase *model, - const QModelIndex& index, const CSMWorld::UniversalId& id, + const QModelIndex& index, const CSMWorld::UniversalId& id, bool writable, CSMDoc::Messages& messages) const; QString formatDescription (const QString& description, int pos, int length) const; @@ -82,6 +83,11 @@ namespace CSMTools CSMDoc::Messages& messages) const; void setPadding (int before, int after); + + // Configuring *this for the model is not necessary when calling this function. + void replace (CSMDoc::Document& document, CSMWorld::IdTableBase *model, + const CSMWorld::UniversalId& id, const std::string& messageHint, + const std::string& replaceText) const; }; } diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index 73fee2362..1b07d3c0f 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -56,8 +56,25 @@ void CSVTools::ReportTable::contextMenuEvent (QContextMenuEvent *event) { menu.addAction (mShowAction); menu.addAction (mRemoveAction); - } + bool found = false; + for (QModelIndexList::const_iterator iter (selectedRows.begin()); + iter!=selectedRows.end(); ++iter) + { + QString hint = mModel->data (mModel->index (iter->row(), 2)).toString(); + + if (!hint.isEmpty() && hint[0]=='R') + { + found = true; + break; + } + } + + if (found) + menu.addAction (mReplaceAction); + + } + menu.exec (event->globalPos()); } @@ -129,6 +146,10 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, mRemoveAction = new QAction (tr ("Remove from list"), this); connect (mRemoveAction, SIGNAL (triggered()), this, SLOT (removeSelection())); addAction (mRemoveAction); + + mReplaceAction = new QAction (tr ("Replace"), this); + connect (mReplaceAction, SIGNAL (triggered()), this, SIGNAL (replaceRequest())); + addAction (mReplaceAction); } std::vector CSVTools::ReportTable::getDraggedRecords() const @@ -151,6 +172,42 @@ void CSVTools::ReportTable::updateUserSetting (const QString& name, const QStrin mIdTypeDelegate->updateUserSetting (name, list); } +std::vector CSVTools::ReportTable::getReplaceIndices (bool selection) const +{ + std::vector indices; + + if (selection) + { + QModelIndexList selectedRows = selectionModel()->selectedRows(); + + for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); + ++iter) + { + QString hint = mModel->data (mModel->index (iter->row(), 2)).toString(); + + if (!hint.isEmpty() && hint[0]=='R') + indices.push_back (iter->row()); + } + } + else + { + for (int i=0; irowCount(); ++i) + { + QString hint = mModel->data (mModel->index (i, 2)).toString(); + + if (!hint.isEmpty() && hint[0]=='R') + indices.push_back (i); + } + } + + return indices; +} + +void CSVTools::ReportTable::flagAsReplaced (int index) +{ + mModel->flagAsReplaced (index); +} + void CSVTools::ReportTable::showSelection() { QModelIndexList selectedRows = selectionModel()->selectedRows(); diff --git a/apps/opencs/view/tools/reporttable.hpp b/apps/opencs/view/tools/reporttable.hpp index dde6cc634..c4d5b414e 100644 --- a/apps/opencs/view/tools/reporttable.hpp +++ b/apps/opencs/view/tools/reporttable.hpp @@ -25,6 +25,7 @@ namespace CSVTools CSVWorld::CommandDelegate *mIdTypeDelegate; QAction *mShowAction; QAction *mRemoveAction; + QAction *mReplaceAction; private: @@ -46,6 +47,13 @@ namespace CSVTools void clear(); + // Return indices of rows that are suitable for replacement. + // + // \param selection Only list selected rows. + std::vector getReplaceIndices (bool selection) const; + + void flagAsReplaced (int index); + private slots: void showSelection(); @@ -55,6 +63,8 @@ namespace CSVTools signals: void editRequest (const CSMWorld::UniversalId& id, const std::string& hint); + + void replaceRequest(); }; } diff --git a/apps/opencs/view/tools/searchbox.cpp b/apps/opencs/view/tools/searchbox.cpp index 178dd1f04..1e92acb75 100644 --- a/apps/opencs/view/tools/searchbox.cpp +++ b/apps/opencs/view/tools/searchbox.cpp @@ -38,6 +38,9 @@ void CSVTools::SearchBox::updateSearchButton() CSVTools::SearchBox::SearchBox (QWidget *parent) : QWidget (parent), mSearch ("Search"), mSearchEnabled (false) { + mLayout = new QGridLayout (this); + + // search panel std::vector states = CSMWorld::Columns::getEnums (CSMWorld::Columns::ColumnId_Modification); states.resize (states.size()-1); // ignore erased state @@ -46,8 +49,6 @@ CSVTools::SearchBox::SearchBox (QWidget *parent) ++iter) mRecordState.addItem (QString::fromUtf8 (iter->c_str())); - mLayout = new QGridLayout (this); - mMode.addItem ("Text"); mMode.addItem ("Text (RegEx)"); mMode.addItem ("ID"); @@ -61,13 +62,8 @@ CSVTools::SearchBox::SearchBox (QWidget *parent) mInput.insertWidget (0, &mText); mInput.insertWidget (1, &mRecordState); - mLayout->addWidget (&mInput, 0, 1); - - mLayout->setColumnMinimumWidth (2, 50); - mLayout->setColumnStretch (1, 1); + mLayout->addWidget (&mInput, 0, 1); - mLayout->setContentsMargins (0, 0, 0, 0); - connect (&mMode, SIGNAL (activated (int)), this, SLOT (modeSelected (int))); connect (&mText, SIGNAL (textChanged (const QString&)), @@ -76,7 +72,20 @@ CSVTools::SearchBox::SearchBox (QWidget *parent) connect (&mSearch, SIGNAL (clicked (bool)), this, SLOT (startSearch (bool))); connect (&mText, SIGNAL (returnPressed()), this, SLOT (startSearch())); + + // replace panel + mReplaceInput.insertWidget (0, &mReplaceText); + mReplaceInput.insertWidget (1, &mReplacePlaceholder); + + mLayout->addWidget (&mReplaceInput, 1, 1); + + // layout adjustments + mLayout->setColumnMinimumWidth (2, 50); + mLayout->setColumnStretch (1, 1); + + mLayout->setContentsMargins (0, 0, 0, 0); + // update modeSelected (0); updateSearchButton(); @@ -116,6 +125,25 @@ CSMTools::Search CSVTools::SearchBox::getSearch() const throw std::logic_error ("invalid search mode index"); } +std::string CSVTools::SearchBox::getReplaceText() const +{ + CSMTools::Search::Type type = static_cast (mMode.currentIndex()); + + switch (type) + { + case CSMTools::Search::Type_Text: + case CSMTools::Search::Type_TextRegEx: + case CSMTools::Search::Type_Id: + case CSMTools::Search::Type_IdRegEx: + + return mReplaceText.text().toUtf8().data(); + + default: + + throw std::logic_error ("Invalid search mode for replace"); + } +} + void CSVTools::SearchBox::modeSelected (int index) { switch (index) @@ -126,10 +154,12 @@ void CSVTools::SearchBox::modeSelected (int index) case CSMTools::Search::Type_IdRegEx: mInput.setCurrentIndex (0); + mReplaceInput.setCurrentIndex (0); break; case CSMTools::Search::Type_RecordState: mInput.setCurrentIndex (1); + mReplaceInput.setCurrentIndex (1); break; } diff --git a/apps/opencs/view/tools/searchbox.hpp b/apps/opencs/view/tools/searchbox.hpp index 35c656d16..594788e6c 100644 --- a/apps/opencs/view/tools/searchbox.hpp +++ b/apps/opencs/view/tools/searchbox.hpp @@ -6,6 +6,7 @@ #include #include #include +#include class QGridLayout; @@ -27,6 +28,9 @@ namespace CSVTools QGridLayout *mLayout; QComboBox mMode; bool mSearchEnabled; + QStackedWidget mReplaceInput; + QLineEdit mReplaceText; + QLabel mReplacePlaceholder; private: @@ -40,6 +44,8 @@ namespace CSVTools CSMTools::Search getSearch() const; + std::string getReplaceText() const; + private slots: void modeSelected (int index); diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index 36fd65a2b..64827b737 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -5,6 +5,8 @@ #include "../../model/doc/document.hpp" #include "../../model/tools/search.hpp" +#include "../../model/tools/reportmodel.hpp" +#include "../../model/world/idtablebase.hpp" #include "reporttable.hpp" #include "searchbox.hpp" @@ -31,6 +33,8 @@ CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc: connect (mTable, SIGNAL (editRequest (const CSMWorld::UniversalId&, const std::string&)), SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&))); + connect (mTable, SIGNAL (replaceRequest()), this, SLOT (replaceRequest())); + connect (&document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (stateChanged (int, CSMDoc::Document *))); @@ -63,9 +67,36 @@ void CSVTools::SearchSubView::stateChanged (int state, CSMDoc::Document *documen void CSVTools::SearchSubView::startSearch (const CSMTools::Search& search) { - CSMTools::Search search2 (search); - search2.setPadding (mPaddingBefore, mPaddingAfter); + mSearch = search; + mSearch.setPadding (mPaddingBefore, mPaddingAfter); mTable->clear(); - mDocument.runSearch (getUniversalId(), search2); + mDocument.runSearch (getUniversalId(), mSearch); +} + +void CSVTools::SearchSubView::replaceRequest() +{ + std::vector indices = mTable->getReplaceIndices (true); + + std::string replace = mSearchBox.getReplaceText(); + + const CSMTools::ReportModel& model = + dynamic_cast (*mTable->model()); + + // We are running through the indices in reverse order to avoid messing up multiple results + // in a single string. + for (std::vector::const_reverse_iterator iter (indices.rbegin()); iter!=indices.rend(); ++iter) + { + CSMWorld::UniversalId id = model.getUniversalId (*iter); + + CSMWorld::UniversalId::Type type = CSMWorld::UniversalId::getParentType (id.getType()); + + CSMWorld::IdTableBase *table = &dynamic_cast ( + *mDocument.getData().getTableModel (type)); + + std::string hint = model.getHint (*iter); + + mSearch.replace (mDocument, table, id, hint, replace); + mTable->flagAsReplaced (*iter); + } } diff --git a/apps/opencs/view/tools/searchsubview.hpp b/apps/opencs/view/tools/searchsubview.hpp index b9b24f774..125d0b927 100644 --- a/apps/opencs/view/tools/searchsubview.hpp +++ b/apps/opencs/view/tools/searchsubview.hpp @@ -1,6 +1,8 @@ #ifndef CSV_TOOLS_SEARCHSUBVIEW_H #define CSV_TOOLS_SEARCHSUBVIEW_H +#include "../../model/tools/search.hpp" + #include "../doc/subview.hpp" #include "searchbox.hpp" @@ -26,6 +28,7 @@ namespace CSVTools CSMDoc::Document& mDocument; int mPaddingBefore; int mPaddingAfter; + CSMTools::Search mSearch; public: @@ -40,6 +43,8 @@ namespace CSVTools void stateChanged (int state, CSMDoc::Document *document); void startSearch (const CSMTools::Search& search); + + void replaceRequest(); }; } From 36ce2d61f4aa9afccdceeb9e327ab5393080f37c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 16 Apr 2015 19:02:03 +0200 Subject: [PATCH 718/740] consider lock mode when replacing --- apps/opencs/view/tools/searchsubview.cpp | 8 ++++++-- apps/opencs/view/tools/searchsubview.hpp | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index 64827b737..0bdb9d658 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -12,7 +12,8 @@ #include "searchbox.hpp" CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) -: CSVDoc::SubView (id), mDocument (document), mPaddingBefore (10), mPaddingAfter (10) +: CSVDoc::SubView (id), mDocument (document), mPaddingBefore (10), mPaddingAfter (10), + mLocked (false) { QVBoxLayout *layout = new QVBoxLayout; @@ -44,7 +45,7 @@ CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc: void CSVTools::SearchSubView::setEditLock (bool locked) { - // ignored. We don't change document state anyway. + mLocked = false; } void CSVTools::SearchSubView::updateUserSetting (const QString &name, const QStringList &list) @@ -76,6 +77,9 @@ void CSVTools::SearchSubView::startSearch (const CSMTools::Search& search) void CSVTools::SearchSubView::replaceRequest() { + if (mLocked) + return; + std::vector indices = mTable->getReplaceIndices (true); std::string replace = mSearchBox.getReplaceText(); diff --git a/apps/opencs/view/tools/searchsubview.hpp b/apps/opencs/view/tools/searchsubview.hpp index 125d0b927..59fbfe66e 100644 --- a/apps/opencs/view/tools/searchsubview.hpp +++ b/apps/opencs/view/tools/searchsubview.hpp @@ -29,6 +29,7 @@ namespace CSVTools int mPaddingBefore; int mPaddingAfter; CSMTools::Search mSearch; + bool mLocked; public: From b939fd440ee2ac3a4c1d3d91c8733bfb72694fef Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 16 Apr 2015 20:11:14 +0200 Subject: [PATCH 719/740] added replace all button --- apps/opencs/view/tools/searchbox.cpp | 16 +++++- apps/opencs/view/tools/searchbox.hpp | 7 +++ apps/opencs/view/tools/searchsubview.cpp | 65 ++++++++++++++---------- apps/opencs/view/tools/searchsubview.hpp | 6 +++ 4 files changed, 67 insertions(+), 27 deletions(-) diff --git a/apps/opencs/view/tools/searchbox.cpp b/apps/opencs/view/tools/searchbox.cpp index 1e92acb75..ca5520787 100644 --- a/apps/opencs/view/tools/searchbox.cpp +++ b/apps/opencs/view/tools/searchbox.cpp @@ -36,7 +36,7 @@ void CSVTools::SearchBox::updateSearchButton() } CSVTools::SearchBox::SearchBox (QWidget *parent) -: QWidget (parent), mSearch ("Search"), mSearchEnabled (false) +: QWidget (parent), mSearch ("Search"), mSearchEnabled (false), mReplace ("Replace All") { mLayout = new QGridLayout (this); @@ -78,12 +78,16 @@ CSVTools::SearchBox::SearchBox (QWidget *parent) mReplaceInput.insertWidget (1, &mReplacePlaceholder); mLayout->addWidget (&mReplaceInput, 1, 1); + + mLayout->addWidget (&mReplace, 1, 3); // layout adjustments mLayout->setColumnMinimumWidth (2, 50); mLayout->setColumnStretch (1, 1); mLayout->setContentsMargins (0, 0, 0, 0); + + connect (&mReplace, (SIGNAL (clicked (bool))), this, SLOT (replaceAll (bool))); // update modeSelected (0); @@ -144,6 +148,11 @@ std::string CSVTools::SearchBox::getReplaceText() const } } +void CSVTools::SearchBox::setEditLock (bool locked) +{ + mReplace.setEnabled (!locked); +} + void CSVTools::SearchBox::modeSelected (int index) { switch (index) @@ -176,3 +185,8 @@ void CSVTools::SearchBox::startSearch (bool checked) if (mSearch.isEnabled()) emit startSearch (getSearch()); } + +void CSVTools::SearchBox::replaceAll (bool checked) +{ + emit replaceAll(); +} diff --git a/apps/opencs/view/tools/searchbox.hpp b/apps/opencs/view/tools/searchbox.hpp index 594788e6c..433c09693 100644 --- a/apps/opencs/view/tools/searchbox.hpp +++ b/apps/opencs/view/tools/searchbox.hpp @@ -31,6 +31,7 @@ namespace CSVTools QStackedWidget mReplaceInput; QLineEdit mReplaceText; QLabel mReplacePlaceholder; + QPushButton mReplace; private: @@ -46,6 +47,8 @@ namespace CSVTools std::string getReplaceText() const; + void setEditLock (bool locked); + private slots: void modeSelected (int index); @@ -54,9 +57,13 @@ namespace CSVTools void startSearch (bool checked = true); + void replaceAll (bool checked); + signals: void startSearch (const CSMTools::Search& search); + + void replaceAll(); }; } diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index 0bdb9d658..5743ad761 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -11,6 +11,36 @@ #include "reporttable.hpp" #include "searchbox.hpp" +void CSVTools::SearchSubView::replace (bool selection) +{ + if (mLocked) + return; + + std::vector indices = mTable->getReplaceIndices (selection); + + std::string replace = mSearchBox.getReplaceText(); + + const CSMTools::ReportModel& model = + dynamic_cast (*mTable->model()); + + // We are running through the indices in reverse order to avoid messing up multiple results + // in a single string. + for (std::vector::const_reverse_iterator iter (indices.rbegin()); iter!=indices.rend(); ++iter) + { + CSMWorld::UniversalId id = model.getUniversalId (*iter); + + CSMWorld::UniversalId::Type type = CSMWorld::UniversalId::getParentType (id.getType()); + + CSMWorld::IdTableBase *table = &dynamic_cast ( + *mDocument.getData().getTableModel (type)); + + std::string hint = model.getHint (*iter); + + mSearch.replace (mDocument, table, id, hint, replace); + mTable->flagAsReplaced (*iter); + } +} + CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) : CSVDoc::SubView (id), mDocument (document), mPaddingBefore (10), mPaddingAfter (10), mLocked (false) @@ -41,11 +71,14 @@ CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc: connect (&mSearchBox, SIGNAL (startSearch (const CSMTools::Search&)), this, SLOT (startSearch (const CSMTools::Search&))); + + connect (&mSearchBox, SIGNAL (replaceAll()), this, SLOT (replaceAllRequest())); } void CSVTools::SearchSubView::setEditLock (bool locked) { - mLocked = false; + mLocked = locked; + mSearchBox.setEditLock (locked); } void CSVTools::SearchSubView::updateUserSetting (const QString &name, const QStringList &list) @@ -77,30 +110,10 @@ void CSVTools::SearchSubView::startSearch (const CSMTools::Search& search) void CSVTools::SearchSubView::replaceRequest() { - if (mLocked) - return; - - std::vector indices = mTable->getReplaceIndices (true); - - std::string replace = mSearchBox.getReplaceText(); - - const CSMTools::ReportModel& model = - dynamic_cast (*mTable->model()); - - // We are running through the indices in reverse order to avoid messing up multiple results - // in a single string. - for (std::vector::const_reverse_iterator iter (indices.rbegin()); iter!=indices.rend(); ++iter) - { - CSMWorld::UniversalId id = model.getUniversalId (*iter); - - CSMWorld::UniversalId::Type type = CSMWorld::UniversalId::getParentType (id.getType()); + replace (true); +} - CSMWorld::IdTableBase *table = &dynamic_cast ( - *mDocument.getData().getTableModel (type)); - - std::string hint = model.getHint (*iter); - - mSearch.replace (mDocument, table, id, hint, replace); - mTable->flagAsReplaced (*iter); - } +void CSVTools::SearchSubView::replaceAllRequest() +{ + replace (false); } diff --git a/apps/opencs/view/tools/searchsubview.hpp b/apps/opencs/view/tools/searchsubview.hpp index 59fbfe66e..eeefa9afb 100644 --- a/apps/opencs/view/tools/searchsubview.hpp +++ b/apps/opencs/view/tools/searchsubview.hpp @@ -31,6 +31,10 @@ namespace CSVTools CSMTools::Search mSearch; bool mLocked; + private: + + void replace (bool selection); + public: SearchSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); @@ -46,6 +50,8 @@ namespace CSVTools void startSearch (const CSMTools::Search& search); void replaceRequest(); + + void replaceAllRequest(); }; } From 32e73c3debf67f5cfb64671daca1c32b8d12dd4a Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 17 Apr 2015 11:50:19 +1000 Subject: [PATCH 720/740] Add creature/item levelled lists (non table items) to dialogue subview. --- apps/opencs/model/world/columns.cpp | 88 ++++++------- apps/opencs/model/world/columns.hpp | 2 + apps/opencs/model/world/refidadapterimp.hpp | 131 +++++++++++++++++++- apps/opencs/model/world/refidcollection.cpp | 14 +++ 4 files changed, 191 insertions(+), 44 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 83d6ceb57..81968d114 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -223,49 +223,51 @@ namespace CSMWorld { ColumnId_AreaSound, "Area Sound" }, { ColumnId_BoltSound, "Bolt Sound" }, - { ColumnId_PathgridPoints, "Points"}, - { ColumnId_PathgridIndex, "Index"}, - { ColumnId_PathgridPosX, "X"}, - { ColumnId_PathgridPosY, "Y"}, - { ColumnId_PathgridPosZ, "Z"}, - { ColumnId_PathgridEdges, "Edges"}, - { ColumnId_PathgridEdgeIndex, "Index"}, - { ColumnId_PathgridEdge0, "Point 0"}, - { ColumnId_PathgridEdge1, "Point 1"}, - - { ColumnId_RegionSounds, "Sounds"}, - { ColumnId_SoundName, "Name"}, - { ColumnId_SoundChance, "Chance"}, - - { ColumnId_FactionReactions, "Reactions"}, - //{ ColumnId_FactionID, "Faction ID"}, - { ColumnId_FactionReaction, "Reaction"}, - - { ColumnId_EffectList, "Effects"}, - { ColumnId_EffectId, "Effect"}, - //{ ColumnId_EffectAttribute, "Attrib"}, - { ColumnId_EffectRange, "Range"}, - { ColumnId_EffectArea, "Area"}, - - { ColumnId_AiPackageList, "Ai Packages"}, - { ColumnId_AiPackage, "Package"}, - { ColumnId_AiWanderDist, "Wander Dist"}, - { ColumnId_AiDuration, "Duration"}, - { ColumnId_AiWanderToD, "Wander ToD"}, - { ColumnId_AiWanderIdle, "Wander Idle"}, - { ColumnId_AiWanderRepeat, "Wander Repeat"}, - { ColumnId_AiActivateName, "Activate"}, - { ColumnId_AiTargetId, "Target ID"}, - { ColumnId_AiTargetCell, "Target Cell"}, - - { ColumnId_PartRefList, "Part Reference"}, - { ColumnId_PartRefType, "Type"}, - { ColumnId_PartRefMale, "Male"}, - { ColumnId_PartRefFemale, "Female"}, - - { ColumnId_LevelledList,"Levelled List"}, - { ColumnId_LevelledItemId,"Item ID"}, - { ColumnId_LevelledItemLevel,"Level"}, + { ColumnId_PathgridPoints, "Points" }, + { ColumnId_PathgridIndex, "Index" }, + { ColumnId_PathgridPosX, "X" }, + { ColumnId_PathgridPosY, "Y" }, + { ColumnId_PathgridPosZ, "Z" }, + { ColumnId_PathgridEdges, "Edges" }, + { ColumnId_PathgridEdgeIndex, "Index" }, + { ColumnId_PathgridEdge0, "Point 0" }, + { ColumnId_PathgridEdge1, "Point 1" }, + + { ColumnId_RegionSounds, "Sounds" }, + { ColumnId_SoundName, "Name" }, + { ColumnId_SoundChance, "Chance" }, + + { ColumnId_FactionReactions, "Reactions" }, + //{ ColumnId_FactionID, "Faction ID" }, + { ColumnId_FactionReaction, "Reaction" }, + + { ColumnId_EffectList, "Effects" }, + { ColumnId_EffectId, "Effect" }, + //{ ColumnId_EffectAttribute, "Attrib" }, + { ColumnId_EffectRange, "Range" }, + { ColumnId_EffectArea, "Area" }, + + { ColumnId_AiPackageList, "Ai Packages" }, + { ColumnId_AiPackage, "Package" }, + { ColumnId_AiWanderDist, "Wander Dist" }, + { ColumnId_AiDuration, "Duration" }, + { ColumnId_AiWanderToD, "Wander ToD" }, + { ColumnId_AiWanderIdle, "Wander Idle" }, + { ColumnId_AiWanderRepeat, "Wander Repeat" }, + { ColumnId_AiActivateName, "Activate" }, + { ColumnId_AiTargetId, "Target ID" }, + { ColumnId_AiTargetCell, "Target Cell" }, + + { ColumnId_PartRefList, "Part Reference" }, + { ColumnId_PartRefType, "Type" }, + { ColumnId_PartRefMale, "Male" }, + { ColumnId_PartRefFemale, "Female" }, + + { ColumnId_LevelledList,"Levelled List" }, + { ColumnId_LevelledItemId,"Item ID" }, + { ColumnId_LevelledItemLevel,"Level" }, + { ColumnId_LevelledItemType, "Type" }, + { ColumnId_LevelledItemChanceNone, "Chance None" }, { 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 81cae5e36..986b90df5 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -256,6 +256,8 @@ namespace CSMWorld ColumnId_LevelledList = 233, ColumnId_LevelledItemId = 234, ColumnId_LevelledItemLevel = 235, + ColumnId_LevelledItemType = 236, + ColumnId_LevelledItemChanceNone = 237, // 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/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index d09aaaa45..2b2b189e0 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -1829,9 +1829,11 @@ namespace CSMWorld } }; + struct LevListColumns : public BaseColumns { const RefIdColumn *mLevList; + const RefIdColumn *mNestedListLevList; LevListColumns (const BaseColumns& base) : BaseColumns (base) {} }; @@ -1863,7 +1865,7 @@ namespace CSMWorld QVariant LevelledListRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, int index) const { - if (column==mLevList.mLevList) + if (column==mLevList.mLevList || column == mLevList.mNestedListLevList) return true; // to show nested tables in dialogue subview, see IdTree::hasChildren() return BaseRefIdAdapter::getData (column, data, index); @@ -1877,6 +1879,133 @@ namespace CSMWorld return; } + + template + class NestedListLevListRefIdAdapter : public NestedRefIdAdapterBase + { + + UniversalId::Type mType; + + // not implemented + NestedListLevListRefIdAdapter (const NestedListLevListRefIdAdapter&); + NestedListLevListRefIdAdapter& operator= (const NestedListLevListRefIdAdapter&); + + public: + + NestedListLevListRefIdAdapter(UniversalId::Type type) + :mType(type) {} + + virtual ~NestedListLevListRefIdAdapter() {} + + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const + { + throw std::logic_error ("cannot add a row to a fixed table"); + } + + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const + { + throw std::logic_error ("cannot remove a row to a fixed table"); + } + + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const + { + throw std::logic_error ("table operation not supported"); + } + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const + { + throw std::logic_error ("table operation not supported"); + } + + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const + { + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); + + switch (subColIndex) + { + case 0: + { + if (mType == CSMWorld::UniversalId::Type_CreatureLevelledList && + record.get().mFlags == 0x01) + { + return QString("All Levels"); + } + else if(mType == CSMWorld::UniversalId::Type_ItemLevelledList && + record.get().mFlags == 0x01) + { + return QString("Each"); + } + else if(mType == CSMWorld::UniversalId::Type_ItemLevelledList && + record.get().mFlags == 0x02) + { + return QString("All Levels"); + } + else + throw std::runtime_error("unknown leveled list type"); + } + case 1: return static_cast (record.get().mChanceNone); + default: + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + } + } + + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const + { + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (row, mType))); + ESXRecordT leveled = record.get(); + + switch(subColIndex) + { + case 0: + { + if (mType == CSMWorld::UniversalId::Type_CreatureLevelledList && + value.toString().toStdString() == "All Levels") + { + leveled.mFlags = 0x01; + break; + } + else if(mType == CSMWorld::UniversalId::Type_ItemLevelledList && + value.toString().toStdString() == "Each") + { + leveled.mFlags = 0x01; + break; + } + else if(mType == CSMWorld::UniversalId::Type_ItemLevelledList && + value.toString().toStdString() == "All Levels") + { + leveled.mFlags = 0x02; + break; + } + else + return; // return without saving + } + case 1: leveled.mChanceNone = static_cast(value.toInt()); break; + default: + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + } + + record.setModified (leveled); + } + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const + { + return 2; + } + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const + { + return 1; // fixed at size 1 + } + }; + template class NestedLevListRefIdAdapter : public NestedRefIdAdapterBase { diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index be5d67766..02d876df8 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -503,6 +503,20 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_LevelledItemLevel, CSMWorld::ColumnBase::Display_Integer)); + // Nested list + mColumns.push_back(RefIdColumn (Columns::ColumnId_LevelledList, + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_List)); + levListColumns.mNestedListLevList = &mColumns.back(); + std::map nestedListLevListMap; + nestedListLevListMap.insert(std::make_pair(UniversalId::Type_CreatureLevelledList, + new NestedListLevListRefIdAdapter (UniversalId::Type_CreatureLevelledList))); + nestedListLevListMap.insert(std::make_pair(UniversalId::Type_ItemLevelledList, + new NestedListLevListRefIdAdapter (UniversalId::Type_ItemLevelledList))); + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), nestedListLevListMap)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_LevelledItemType, CSMWorld::ColumnBase::Display_String)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_LevelledItemChanceNone, CSMWorld::ColumnBase::Display_Integer)); mAdapters.insert (std::make_pair (UniversalId::Type_Activator, new NameRefIdAdapter (UniversalId::Type_Activator, nameColumns))); From c41b4b84a6b9421496cc1a66e34a84e1b9434b31 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 17 Apr 2015 13:45:45 +1000 Subject: [PATCH 721/740] Cleanup post merge. --- apps/opencs/model/world/columnbase.hpp | 16 +++++----------- apps/opencs/model/world/columns.cpp | 2 ++ apps/opencs/model/world/columns.hpp | 2 ++ apps/opencs/model/world/data.cpp | 4 ++-- apps/opencs/model/world/refidcollection.cpp | 8 ++++---- 5 files changed, 15 insertions(+), 17 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 197fb5ad3..437d07f97 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -93,15 +93,6 @@ namespace CSMWorld Display_RefRecordType, Display_DialogueType, Display_QuestStatusType, - - //Those are top level columns that nest other columns - Display_NestedItemList, // delete? - Display_NestedSpellList, // delete? - Display_NestedDestinationsList, // delete? - Display_PathgridPointList, // delete? - Display_PathgridEdgeList, // delete? - Display_NestedHeader, - Display_EnchantmentType, Display_BodyPartType, Display_MeshType, @@ -117,7 +108,10 @@ namespace CSMWorld Display_ScriptLines, // console context Display_SoundGeneratorType, Display_School, - Display_Id + Display_Id, + + //top level columns that nest other columns + Display_NestedHeader }; int mColumnId; @@ -135,7 +129,7 @@ namespace CSMWorld virtual std::string getTitle() const; - virtual int getId() const; // FIXME: why have an accessor for a public member? + virtual int getId() const; static bool isId (Display display); diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 81968d114..ff28a1289 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -269,6 +269,8 @@ namespace CSMWorld { ColumnId_LevelledItemType, "Type" }, { ColumnId_LevelledItemChanceNone, "Chance None" }, + { ColumnId_PowerList, "Powers" }, + { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue3, "Use value 3" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 986b90df5..7c28f9589 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -259,6 +259,8 @@ namespace CSMWorld ColumnId_LevelledItemType = 236, ColumnId_LevelledItemChanceNone = 237, + ColumnId_PowerList = 238, + // 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 d7280e354..5733fd83f 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -131,7 +131,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mRaces.addColumn (new WeightHeightColumn (false, true)); mRaces.addColumn (new WeightHeightColumn (false, false)); // Race spells - mRaces.addColumn (new NestedParentColumn (Columns::ColumnId_SpellList)); + mRaces.addColumn (new NestedParentColumn (Columns::ColumnId_PowerList)); index = mRaces.getColumns()-1; mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new SpellListAdapter ())); mRaces.getNestableColumn(index)->addColumn( @@ -172,7 +172,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mBirthsigns.addColumn (new TextureColumn); mBirthsigns.addColumn (new DescriptionColumn); // Birthsign spells - mBirthsigns.addColumn (new NestedParentColumn (Columns::ColumnId_SpellList)); + mBirthsigns.addColumn (new NestedParentColumn (Columns::ColumnId_PowerList)); index = mBirthsigns.getColumns()-1; mBirthsigns.addAdapter (std::make_pair(&mBirthsigns.getColumn(index), new SpellListAdapter ())); diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index d133f3ba9..2e53c2b1c 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -126,7 +126,7 @@ CSMWorld::RefIdCollection::RefIdCollection() // Nested table mColumns.push_back(RefIdColumn (Columns::ColumnId_ActorInventory, - ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue)); + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); actorsColumns.mInventory = &mColumns.back(); std::map inventoryMap; inventoryMap.insert(std::make_pair(UniversalId::Type_Npc, @@ -141,7 +141,7 @@ CSMWorld::RefIdCollection::RefIdCollection() // Nested table mColumns.push_back(RefIdColumn (Columns::ColumnId_SpellList, - ColumnBase::Display_NestedSpellList, ColumnBase::Flag_Dialogue)); + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); actorsColumns.mSpells = &mColumns.back(); std::map spellsMap; spellsMap.insert(std::make_pair(UniversalId::Type_Npc, @@ -154,7 +154,7 @@ CSMWorld::RefIdCollection::RefIdCollection() // Nested table mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcDestinations, - ColumnBase::Display_NestedDestinationsList, ColumnBase::Flag_Dialogue)); + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); actorsColumns.mDestinations = &mColumns.back(); std::map destMap; destMap.insert(std::make_pair(UniversalId::Type_Npc, @@ -281,7 +281,7 @@ CSMWorld::RefIdCollection::RefIdCollection() // Nested table mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent, - ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue)); + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); const RefIdColumn *content = &mColumns.back(); std::map contMap; contMap.insert(std::make_pair(UniversalId::Type_Container, From d6c2cff381a356331ed3852d8799967b4fec9196 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 17 Apr 2015 21:33:25 +1000 Subject: [PATCH 722/740] Convert magic effects Attribute column in the nested tables to use enum delegates. --- apps/opencs/model/world/data.cpp | 4 +-- .../model/world/nestedcoladapterimp.hpp | 34 ++----------------- apps/opencs/model/world/refidcollection.cpp | 2 +- 3 files changed, 5 insertions(+), 35 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 5733fd83f..843d08281 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -197,7 +197,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_String)); mSpells.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_String)); // reuse attribute + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); // reuse attribute mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_Integer)); mSpells.getNestableColumn(index)->addColumn( @@ -271,7 +271,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_String)); mEnchantments.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_String)); // reuse attribute + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); // reuse attribute mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_Integer)); mEnchantments.getNestableColumn(index)->addColumn( diff --git a/apps/opencs/model/world/nestedcoladapterimp.hpp b/apps/opencs/model/world/nestedcoladapterimp.hpp index 2aa1123a3..951c7a610 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.hpp +++ b/apps/opencs/model/world/nestedcoladapterimp.hpp @@ -354,23 +354,7 @@ namespace CSMWorld } case 2: { - switch (effect.mAttribute) - { - // see ESM::Attribute::AttributeID in - case ESM::Attribute::Strength: - case ESM::Attribute::Intelligence: - case ESM::Attribute::Willpower: - case ESM::Attribute::Agility: - case ESM::Attribute::Speed: - case ESM::Attribute::Endurance: - case ESM::Attribute::Personality: - case ESM::Attribute::Luck: - { - return QString(ESM::Attribute::sAttributeNames[effect.mAttribute].c_str()); - } - case -1: return QString("N/A"); - default: return QVariant(); - } + return effect.mAttribute; } case 3: { @@ -431,21 +415,7 @@ namespace CSMWorld } case 2: { - std::string attr = value.toString().toStdString(); - if ("N/A" == attr) - { - effect.mAttribute = -1; - break; - } - - for (unsigned int i = 0; i < ESM::Attribute::Length; ++i) - { - if (ESM::Attribute::sAttributeNames[i] == attr) - { - effect.mAttribute = static_cast(i); - break; - } - } + effect.mAttribute = static_cast(value.toInt()); break; } case 3: diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 2e53c2b1c..92fbfd08e 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -85,7 +85,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_String)); mColumns.back().addColumn( - new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_String)); // reuse attribute + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); // reuse attribute mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_Integer)); mColumns.back().addColumn( From 0aff188d8d0b230e725665bf37dc87d70a0f9398 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 18 Apr 2015 07:13:02 +1000 Subject: [PATCH 723/740] Fix enum delegate from adding a command to the undo stack when the value has not changed. --- apps/opencs/view/world/enumdelegate.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp index 7c305b1b6..eb523f781 100644 --- a/apps/opencs/view/world/enumdelegate.cpp +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -21,7 +21,9 @@ void CSVWorld::EnumDelegate::setModelDataImp (QWidget *editor, QAbstractItemMode iter!=mValues.end(); ++iter) if (iter->second==value) { - addCommands (model, index, iter->first); + // do nothing if the value has not changed + if (model->data(index).toInt() != iter->first) + addCommands (model, index, iter->first); break; } } From befd6fe658fc6969e111762b7ebd9b76db1fb318 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 18 Apr 2015 07:15:40 +1000 Subject: [PATCH 724/740] Convert magic effects Skills column in the nested tables to use enum delegates. --- apps/opencs/model/world/columnbase.cpp | 1 + apps/opencs/model/world/columnbase.hpp | 1 + apps/opencs/model/world/columns.cpp | 13 +++++ apps/opencs/model/world/columns.hpp | 1 + apps/opencs/model/world/data.cpp | 4 +- .../model/world/nestedcoladapterimp.hpp | 53 +------------------ apps/opencs/model/world/refidcollection.cpp | 2 +- apps/opencs/view/doc/viewmanager.cpp | 3 +- apps/opencs/view/world/dialoguesubview.cpp | 3 +- 9 files changed, 25 insertions(+), 56 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 5ef4aa444..045afe04c 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -75,6 +75,7 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_Video, Display_Id, + Display_SkillImpact, Display_None }; diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 437d07f97..f6ebb16b8 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -109,6 +109,7 @@ namespace CSMWorld Display_SoundGeneratorType, Display_School, Display_Id, + Display_SkillImpact, //top level columns that nest other columns Display_NestedHeader diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index ff28a1289..3d15ed4f3 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -270,6 +270,7 @@ namespace CSMWorld { ColumnId_LevelledItemChanceNone, "Chance None" }, { ColumnId_PowerList, "Powers" }, + { ColumnId_SkillImpact, "Skills" }, { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, @@ -423,6 +424,17 @@ namespace "Alteration", "Conjuration", "Destruction", "Illusion", "Mysticism", "Restoration", 0 }; + // impact from magic effects + static const char *sSkills[] = + { + "Block", "Armorer", "MediumArmor", "HeavyArmor", "BluntWeapon", + "LongBlade", "Axe", "Spear", "Athletics", "Enchant", + "Destruction", "Alteration", "Illusion", "Conjuration", "Mysticism", + "Restoration", "Alchemy", "Unarmored", "Security", "Sneak", + "Acrobatics", "LightArmor", "ShortBlade", "Marksman", "Mercantile", + "Speechcraft", "HandToHand", 0 + }; + const char **getEnumNames (CSMWorld::Columns::ColumnId column) { switch (column) @@ -445,6 +457,7 @@ namespace case CSMWorld::Columns::ColumnId_MeshType: return sMeshTypes; case CSMWorld::Columns::ColumnId_SoundGeneratorType: return sSoundGeneratorType; case CSMWorld::Columns::ColumnId_School: return sSchools; + case CSMWorld::Columns::ColumnId_SkillImpact: return sSkills; default: return 0; } diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 7c28f9589..7508c9880 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -260,6 +260,7 @@ namespace CSMWorld ColumnId_LevelledItemChanceNone = 237, ColumnId_PowerList = 238, + ColumnId_SkillImpact = 239, // impact from magic effects // 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 843d08281..f4edb8e57 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -195,7 +195,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_String/*, false*/)); // false means no edit mSpells.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_String)); + new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact)); mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); // reuse attribute mSpells.getNestableColumn(index)->addColumn( @@ -269,7 +269,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_String/*, false*/)); mEnchantments.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_String)); + new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact)); mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); // reuse attribute mEnchantments.getNestableColumn(index)->addColumn( diff --git a/apps/opencs/model/world/nestedcoladapterimp.hpp b/apps/opencs/model/world/nestedcoladapterimp.hpp index 951c7a610..3f8e6d6a9 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.hpp +++ b/apps/opencs/model/world/nestedcoladapterimp.hpp @@ -315,42 +315,7 @@ namespace CSMWorld } case 1: { - switch (effect.mSkill) - { - // see ESM::Skill::SkillEnum in - case ESM::Skill::Block: - case ESM::Skill::Armorer: - case ESM::Skill::MediumArmor: - case ESM::Skill::HeavyArmor: - case ESM::Skill::BluntWeapon: - case ESM::Skill::LongBlade: - case ESM::Skill::Axe: - case ESM::Skill::Spear: - case ESM::Skill::Athletics: - case ESM::Skill::Enchant: - case ESM::Skill::Destruction: - case ESM::Skill::Alteration: - case ESM::Skill::Illusion: - case ESM::Skill::Conjuration: - case ESM::Skill::Mysticism: - case ESM::Skill::Restoration: - case ESM::Skill::Alchemy: - case ESM::Skill::Unarmored: - case ESM::Skill::Security: - case ESM::Skill::Sneak: - case ESM::Skill::Acrobatics: - case ESM::Skill::LightArmor: - case ESM::Skill::ShortBlade: - case ESM::Skill::Marksman: - case ESM::Skill::Mercantile: - case ESM::Skill::Speechcraft: - case ESM::Skill::HandToHand: - { - return QString(ESM::Skill::sSkillNames[effect.mSkill].c_str()); - } - case -1: return QString("N/A"); - default: return QVariant(); - } + return effect.mSkill; } case 2: { @@ -396,21 +361,7 @@ namespace CSMWorld } case 1: { - std::string skillName = value.toString().toStdString(); - if ("N/A" == skillName) - { - effect.mSkill = -1; - break; - } - - for (unsigned int i = 0; i < ESM::Skill::Length; ++i) - { - if (ESM::Skill::sSkillNames[i] == skillName) - { - effect.mSkill = static_cast(i); - break; - } - } + effect.mSkill = static_cast(value.toInt()); break; } case 2: diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 92fbfd08e..a685276f4 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -83,7 +83,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_String/*, false*/)); mColumns.back().addColumn( - new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_String)); + new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact)); mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); // reuse attribute mColumns.back().addColumn( diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 9fee26078..1dfe3a792 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -84,7 +84,8 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) { CSMWorld::ColumnBase::Display_MeshType, CSMWorld::Columns::ColumnId_MeshType, false }, { CSMWorld::ColumnBase::Display_Gender, CSMWorld::Columns::ColumnId_Gender, true }, { CSMWorld::ColumnBase::Display_SoundGeneratorType, CSMWorld::Columns::ColumnId_SoundGeneratorType, false }, - { CSMWorld::ColumnBase::Display_School, CSMWorld::Columns::ColumnId_School, true } + { CSMWorld::ColumnBase::Display_School, CSMWorld::Columns::ColumnId_School, true }, + { CSMWorld::ColumnBase::Display_SkillImpact, CSMWorld::Columns::ColumnId_SkillImpact, true } }; for (std::size_t i=0; iindex(row, i), display, dynamic_cast(mTable))); NestedTable* table = new NestedTable(mDocument, mNestedModels.back(), this); - table->resizeColumnsToContents(); + // FIXME: does not work well when enum delegates are used + //table->resizeColumnsToContents(); QLabel* label = From e00d7f72ace0366cfbe8487521675761c90a3a87 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 18 Apr 2015 08:09:14 +1000 Subject: [PATCH 725/740] Convert magic effects ID and Range columns in the nested tables to use enum delegate --- apps/opencs/model/world/columnbase.cpp | 2 + apps/opencs/model/world/columnbase.hpp | 2 + apps/opencs/model/world/columns.cpp | 45 ++++++++++++++++++- apps/opencs/model/world/data.cpp | 8 ++-- .../model/world/nestedcoladapterimp.hpp | 42 +++++------------ apps/opencs/model/world/refidcollection.cpp | 4 +- apps/opencs/view/doc/viewmanager.cpp | 4 +- 7 files changed, 69 insertions(+), 38 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 045afe04c..5690d9253 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -76,6 +76,8 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_Id, Display_SkillImpact, + Display_EffectRange, + Display_EffectId, Display_None }; diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index f6ebb16b8..8dab0602e 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -110,6 +110,8 @@ namespace CSMWorld Display_School, Display_Id, Display_SkillImpact, + Display_EffectRange, + Display_EffectId, //top level columns that nest other columns Display_NestedHeader diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 3d15ed4f3..19efc8177 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -332,6 +332,7 @@ namespace "Combat", "Magic", "Stealth", 0 }; + // see ESM::Attribute::AttributeID in static const char *sAttributes[] = { "Strength", "Intelligence", "Willpower", "Agility", "Speed", "Endurance", "Personality", @@ -424,7 +425,7 @@ namespace "Alteration", "Conjuration", "Destruction", "Illusion", "Mysticism", "Restoration", 0 }; - // impact from magic effects + // impact from magic effects, see ESM::Skill::SkillEnum in static const char *sSkills[] = { "Block", "Armorer", "MediumArmor", "HeavyArmor", "BluntWeapon", @@ -435,6 +436,46 @@ namespace "Speechcraft", "HandToHand", 0 }; + // range of magic effects, see ESM::RangeType in + static const char *sEffectRange[] = + { + "Self", "Touch", "Target", 0 + }; + + // magic effect names, see ESM::MagicEffect::Effects in + static const char *sEffectId[] = + { + "WaterBreathing", "SwiftSwim", "WaterWalking", "Shield", "FireShield", + "LightningShield", "FrostShield", "Burden", "Feather", "Jump", + "Levitate", "SlowFall", "Lock", "Open", "FireDamage", + "ShockDamage", "FrostDamage", "DrainAttribute", "DrainHealth", "DrainMagicka", + "DrainFatigue", "DrainSkill", "DamageAttribute", "DamageHealth", "DamageMagicka", + "DamageFatigue", "DamageSkill", "Poison", "WeaknessToFire", "WeaknessToFrost", + "WeaknessToShock", "WeaknessToMagicka", "WeaknessToCommonDisease", "WeaknessToBlightDisease", "WeaknessToCorprusDisease", + "WeaknessToPoison", "WeaknessToNormalWeapons", "DisintegrateWeapon", "DisintegrateArmor", "Invisibility", + "Chameleon", "Light", "Sanctuary", "NightEye", "Charm", + "Paralyze", "Silence", "Blind", "Sound", "CalmHumanoid", + "CalmCreature", "FrenzyHumanoid", "FrenzyCreature", "DemoralizeHumanoid", "DemoralizeCreature", + "RallyHumanoid", "RallyCreature", "Dispel", "Soultrap", "Telekinesis", + "Mark", "Recall", "DivineIntervention", "AlmsiviIntervention", "DetectAnimal", + "DetectEnchantment", "DetectKey", "SpellAbsorption", "Reflect", "CureCommonDisease", + "CureBlightDisease", "CureCorprusDisease", "CurePoison", "CureParalyzation", "RestoreAttribute", + "RestoreHealth", "RestoreMagicka", "RestoreFatigue", "RestoreSkill", "FortifyAttribute", + "FortifyHealth", "FortifyMagicka", "FortifyFatigue", "FortifySkill", "FortifyMaximumMagicka", + "AbsorbAttribute", "AbsorbHealth", "AbsorbMagicka", "AbsorbFatigue", "AbsorbSkill", + "ResistFire", "ResistFrost", "ResistShock", "ResistMagicka", "ResistCommonDisease", + "ResistBlightDisease", "ResistCorprusDisease", "ResistPoison", "ResistNormalWeapons", "ResistParalysis", + "RemoveCurse", "TurnUndead", "SummonScamp", "SummonClannfear", "SummonDaedroth", + "SummonDremora", "SummonAncestralGhost", "SummonSkeletalMinion", "SummonBonewalker", "SummonGreaterBonewalker", + "SummonBonelord", "SummonWingedTwilight", "SummonHunger", "SummonGoldenSaint", "SummonFlameAtronach", + "SummonFrostAtronach", "SummonStormAtronach", "FortifyAttack", "CommandCreature", "CommandHumanoid", + "BoundDagger", "BoundLongsword", "BoundMace", "BoundBattleAxe", "BoundSpear", + "BoundLongbow", "ExtraSpell", "BoundCuirass", "BoundHelm", "BoundBoots", + "BoundShield", "BoundGloves", "Corprus", "Vampirism", "SummonCenturionSphere", + "SunDamage", "StuntedMagicka", "SummonFabricant", "SummonWolf", "SummonBear", + "SummonBonewolf", "SummonCreature04", "SummonCreature05", 0 + }; + const char **getEnumNames (CSMWorld::Columns::ColumnId column) { switch (column) @@ -458,6 +499,8 @@ namespace case CSMWorld::Columns::ColumnId_SoundGeneratorType: return sSoundGeneratorType; case CSMWorld::Columns::ColumnId_School: return sSchools; case CSMWorld::Columns::ColumnId_SkillImpact: return sSkills; + case CSMWorld::Columns::ColumnId_EffectRange: return sEffectRange; + case CSMWorld::Columns::ColumnId_EffectId: return sEffectId; default: return 0; } diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index f4edb8e57..0490cbe7a 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -193,13 +193,13 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc index = mSpells.getColumns()-1; mSpells.addAdapter (std::make_pair(&mSpells.getColumn(index), new EffectsListAdapter ())); mSpells.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_String/*, false*/)); // false means no edit + new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId)); // false means no edit mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact)); mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); // reuse attribute mSpells.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_Integer)); + new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_EffectRange)); mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_EffectArea, ColumnBase::Display_String)); mSpells.getNestableColumn(index)->addColumn( @@ -267,13 +267,13 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mEnchantments.addAdapter (std::make_pair(&mEnchantments.getColumn(index), new EffectsListAdapter ())); mEnchantments.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_String/*, false*/)); + new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId)); mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact)); mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); // reuse attribute mEnchantments.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_Integer)); + new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_EffectRange)); mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_EffectArea, ColumnBase::Display_String)); mEnchantments.getNestableColumn(index)->addColumn( diff --git a/apps/opencs/model/world/nestedcoladapterimp.hpp b/apps/opencs/model/world/nestedcoladapterimp.hpp index 3f8e6d6a9..1ee447f34 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.hpp +++ b/apps/opencs/model/world/nestedcoladapterimp.hpp @@ -309,28 +309,19 @@ namespace CSMWorld { case 0: { - // indexToId() prepends "#d+" hence not so user friendly - QString effectId(ESM::MagicEffect::effectIdToString(effect.mEffectID).c_str()); - return effectId.remove(0, 7); // 7 == sizeof("sEffect") - 1 - } - case 1: - { - return effect.mSkill; - } - case 2: - { - return effect.mAttribute; + if (effect.mEffectID >=0 && effect.mEffectID < ESM::MagicEffect::Length) + return effect.mRange; + else + throw std::runtime_error("Magic effects ID unexpected value"); } + case 1: return effect.mSkill; + case 2: return effect.mAttribute; case 3: { - switch (effect.mRange) - { - // see ESM::RangeType in - case ESM::RT_Self: return QString("Self"); - case ESM::RT_Touch: return QString("Touch"); - case ESM::RT_Target: return QString("Target"); - default: return QVariant(); - } + if (effect.mRange >=0 && effect.mRange <=2) + return effect.mRange; + else + throw std::runtime_error("Magic effects range unexpected value"); } case 4: return effect.mArea; case 5: return effect.mDuration; @@ -355,8 +346,7 @@ namespace CSMWorld { case 0: { - effect.mEffectID = - ESM::MagicEffect::effectStringToId("sEffect"+value.toString().toStdString()); + effect.mEffectID = static_cast(value.toInt()); break; } case 1: @@ -371,15 +361,7 @@ namespace CSMWorld } case 3: { - std::string effectId = value.toString().toStdString(); - if (effectId == "Self") - effect.mRange = ESM::RT_Self; - else if (effectId == "Touch") - effect.mRange = ESM::RT_Touch; - else if (effectId == "Target") - effect.mRange = ESM::RT_Target; - else - return; // leave unchanged + effect.mRange = value.toInt(); break; } case 4: effect.mArea = value.toInt(); break; diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index a685276f4..636f9a57f 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -81,13 +81,13 @@ CSMWorld::RefIdCollection::RefIdCollection() new EffectsRefIdAdapter (UniversalId::Type_Potion))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), effectsMap)); mColumns.back().addColumn( - new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_String/*, false*/)); + new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId)); mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact)); mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); // reuse attribute mColumns.back().addColumn( - new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_Integer)); + new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_EffectRange)); mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_EffectArea, ColumnBase::Display_String)); mColumns.back().addColumn( diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 1dfe3a792..1281f89f2 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -85,7 +85,9 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) { CSMWorld::ColumnBase::Display_Gender, CSMWorld::Columns::ColumnId_Gender, true }, { CSMWorld::ColumnBase::Display_SoundGeneratorType, CSMWorld::Columns::ColumnId_SoundGeneratorType, false }, { CSMWorld::ColumnBase::Display_School, CSMWorld::Columns::ColumnId_School, true }, - { CSMWorld::ColumnBase::Display_SkillImpact, CSMWorld::Columns::ColumnId_SkillImpact, true } + { CSMWorld::ColumnBase::Display_SkillImpact, CSMWorld::Columns::ColumnId_SkillImpact, true }, + { CSMWorld::ColumnBase::Display_EffectRange, CSMWorld::Columns::ColumnId_EffectRange, false }, + { CSMWorld::ColumnBase::Display_EffectId, CSMWorld::Columns::ColumnId_EffectId, false } }; for (std::size_t i=0; i Date: Sat, 18 Apr 2015 08:31:08 +1000 Subject: [PATCH 726/740] Convert clothing/armour part reference type column in the nested tables to use enum delegates. --- apps/opencs/model/world/columnbase.cpp | 1 + apps/opencs/model/world/columnbase.hpp | 1 + apps/opencs/model/world/columns.cpp | 12 +++++++ apps/opencs/model/world/refidadapterimp.hpp | 36 +++++---------------- apps/opencs/model/world/refidcollection.cpp | 2 +- apps/opencs/view/doc/viewmanager.cpp | 3 +- 6 files changed, 25 insertions(+), 30 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 5690d9253..cea00b7bc 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -78,6 +78,7 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_SkillImpact, Display_EffectRange, Display_EffectId, + Display_PartRefType, Display_None }; diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 8dab0602e..20e3ccce6 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -112,6 +112,7 @@ namespace CSMWorld Display_SkillImpact, Display_EffectRange, Display_EffectId, + Display_PartRefType, //top level columns that nest other columns Display_NestedHeader diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 19efc8177..fd090d181 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -476,6 +476,17 @@ namespace "SummonBonewolf", "SummonCreature04", "SummonCreature05", 0 }; + // see ESM::PartReferenceType in + static const char *sPartRefType[] = + { + "Head", "Hair", "Neck", "Cuirass", "Groin", + "Skirt", "Right Hand", "Left Hand", "Right Wrist", "Left Wrist", + "Shield", "Right Forearm", "Left Forearm", "Right Upperarm", "Left Upperarm", + "Right Foot", "Left Foot", "Right Ankle", "Left Ankle", "Right Knee", + "Left Knee", "Right Leg", "Left Leg", "Right Pauldron", "Left Pauldron", + "Weapon", "Tail", 0 + }; + const char **getEnumNames (CSMWorld::Columns::ColumnId column) { switch (column) @@ -501,6 +512,7 @@ namespace case CSMWorld::Columns::ColumnId_SkillImpact: return sSkills; case CSMWorld::Columns::ColumnId_EffectRange: return sEffectRange; case CSMWorld::Columns::ColumnId_EffectId: return sEffectId; + case CSMWorld::Columns::ColumnId_PartRefType: return sPartRefType; default: return 0; } diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 2b2b189e0..489808393 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -1665,15 +1665,6 @@ namespace CSMWorld } }; - static const char *sPartRefs[ESM::PRT_Count] = - { - "Head", "Hair", "Neck", "Cuirass", "Groin", - "Skirt", "Right Hand", "Left Hand", "Right Wrist", "Left Wrist", - "Shield", "Right Forearm", "Left Forearm", "Right Upperarm", "Left Upperarm", - "Right Foot", "Left Foot", "Right Ankle", "Left Ankle", "Right Knee", - "Left Knee", "Right Leg", "Left Leg", "Right Pauldron", "Left Pauldron", - "Weapon", "Tail" - }; template class BodyPartRefIdAdapter : public NestedRefIdAdapterBase @@ -1767,7 +1758,13 @@ namespace CSMWorld switch (subColIndex) { - case 0: return QString(sPartRefs[content.mPart]); + case 0: + { + if (content.mPart >=0 && content.mPart < ESM::PRT_Count) + return content.mPart; + else + throw std::runtime_error("Part Reference Type unexpected value"); + } case 1: return QString(content.mMale.c_str()); case 2: return QString(content.mFemale.c_str()); default: @@ -1788,24 +1785,7 @@ namespace CSMWorld switch(subColIndex) { - case 0: - { - std::string part = value.toString().toStdString(); - bool found = false; - for (unsigned int i = 0; i < ESM::PRT_Count; ++i) - { - if (part == sPartRefs[i]) - { - list.at(subRowIndex).mPart = static_cast(i); - found = true; - break; - } - } - if (!found) - return; // return without saving - else - break; - } + case 0: list.at(subRowIndex).mPart = static_cast(value.toInt()); break; case 1: list.at(subRowIndex).mMale = value.toString().toStdString(); break; case 2: list.at(subRowIndex).mFemale = value.toString().toStdString(); break; default: diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 636f9a57f..3bdf8361f 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -480,7 +480,7 @@ CSMWorld::RefIdCollection::RefIdCollection() new BodyPartRefIdAdapter (UniversalId::Type_Clothing))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), partMap)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_PartRefType, CSMWorld::ColumnBase::Display_String)); + new RefIdColumn (Columns::ColumnId_PartRefType, CSMWorld::ColumnBase::Display_PartRefType)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_PartRefMale, CSMWorld::ColumnBase::Display_String)); mColumns.back().addColumn( diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 1281f89f2..3f0c10053 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -87,7 +87,8 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) { CSMWorld::ColumnBase::Display_School, CSMWorld::Columns::ColumnId_School, true }, { CSMWorld::ColumnBase::Display_SkillImpact, CSMWorld::Columns::ColumnId_SkillImpact, true }, { CSMWorld::ColumnBase::Display_EffectRange, CSMWorld::Columns::ColumnId_EffectRange, false }, - { CSMWorld::ColumnBase::Display_EffectId, CSMWorld::Columns::ColumnId_EffectId, false } + { CSMWorld::ColumnBase::Display_EffectId, CSMWorld::Columns::ColumnId_EffectId, false }, + { CSMWorld::ColumnBase::Display_PartRefType, CSMWorld::Columns::ColumnId_PartRefType, false } }; for (std::size_t i=0; i Date: Sat, 18 Apr 2015 09:37:19 +1000 Subject: [PATCH 727/740] Convert AI package type and AI wander repeat columns in the nested tables to use enum delegate --- apps/opencs/model/world/columnbase.cpp | 2 + apps/opencs/model/world/columnbase.hpp | 2 + apps/opencs/model/world/columns.cpp | 15 +++- apps/opencs/model/world/columns.hpp | 2 +- apps/opencs/model/world/refidadapterimp.hpp | 77 +++++++-------------- apps/opencs/model/world/refidcollection.cpp | 4 +- apps/opencs/view/doc/viewmanager.cpp | 4 +- 7 files changed, 48 insertions(+), 58 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index cea00b7bc..659954f48 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -79,6 +79,8 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_EffectRange, Display_EffectId, Display_PartRefType, + Display_AiPackageType, + Display_YesNo, Display_None }; diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 20e3ccce6..4c3f9385a 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -113,6 +113,8 @@ namespace CSMWorld Display_EffectRange, Display_EffectId, Display_PartRefType, + Display_AiPackageType, + Display_YesNo, //top level columns that nest other columns Display_NestedHeader diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index fd090d181..1b5aefee9 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -248,7 +248,7 @@ namespace CSMWorld { ColumnId_EffectArea, "Area" }, { ColumnId_AiPackageList, "Ai Packages" }, - { ColumnId_AiPackage, "Package" }, + { ColumnId_AiPackageType, "Package" }, { ColumnId_AiWanderDist, "Wander Dist" }, { ColumnId_AiDuration, "Duration" }, { ColumnId_AiWanderToD, "Wander ToD" }, @@ -487,6 +487,17 @@ namespace "Weapon", "Tail", 0 }; + // see the enums in + static const char *sAiPackageType[] = + { + "AI Wander", "AI Travel", "AI Follow", "AI Escort", "AI Activate", 0 + }; + + static const char *sAiWanderRepeat[] = + { + "No", "Yes", 0 + }; + const char **getEnumNames (CSMWorld::Columns::ColumnId column) { switch (column) @@ -513,6 +524,8 @@ namespace case CSMWorld::Columns::ColumnId_EffectRange: return sEffectRange; case CSMWorld::Columns::ColumnId_EffectId: return sEffectId; case CSMWorld::Columns::ColumnId_PartRefType: return sPartRefType; + case CSMWorld::Columns::ColumnId_AiPackageType: return sAiPackageType; + case CSMWorld::Columns::ColumnId_AiWanderRepeat: return sAiWanderRepeat; default: return 0; } diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 7508c9880..1760bff30 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -237,7 +237,7 @@ namespace CSMWorld ColumnId_EffectArea = 218, ColumnId_AiPackageList = 219, - ColumnId_AiPackage = 220, + ColumnId_AiPackageType = 220, ColumnId_AiWanderDist = 221, ColumnId_AiDuration = 222, ColumnId_AiWanderToD = 223, diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 489808393..5fd888441 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -1318,34 +1318,13 @@ namespace CSMWorld switch(subColIndex) { - case 0: - list.at(subRowIndex).mCellName = std::string(value.toString().toUtf8().constData()); - break; - - case 1: - list.at(subRowIndex).mPos.pos[0] = value.toFloat(); - break; - - case 2: - list.at(subRowIndex).mPos.pos[1] = value.toFloat(); - break; - - case 3: - list.at(subRowIndex).mPos.pos[2] = value.toFloat(); - break; - - case 4: - list.at(subRowIndex).mPos.rot[0] = value.toFloat(); - break; - - case 5: - list.at(subRowIndex).mPos.rot[1] = value.toFloat(); - break; - - case 6: - list.at(subRowIndex).mPos.rot[2] = value.toFloat(); - break; - + case 0: list.at(subRowIndex).mCellName = std::string(value.toString().toUtf8().constData()); break; + case 1: list.at(subRowIndex).mPos.pos[0] = value.toFloat(); break; + case 2: list.at(subRowIndex).mPos.pos[1] = value.toFloat(); break; + case 3: list.at(subRowIndex).mPos.pos[2] = value.toFloat(); break; + case 4: list.at(subRowIndex).mPos.rot[0] = value.toFloat(); break; + case 5: list.at(subRowIndex).mPos.rot[1] = value.toFloat(); break; + case 6: list.at(subRowIndex).mPos.rot[2] = value.toFloat(); break; default: throw std::runtime_error("Trying to access non-existing column in the nested table!"); } @@ -1461,13 +1440,13 @@ namespace CSMWorld case 0: switch (content.mType) { - case ESM::AI_Wander: return QString("AI Wander"); - case ESM::AI_Travel: return QString("AI Travel"); - case ESM::AI_Follow: return QString("AI Follow"); - case ESM::AI_Escort: return QString("AI Escort"); - case ESM::AI_Activate: return QString("AI Activate"); + case ESM::AI_Wander: return 0; + case ESM::AI_Travel: return 1; + case ESM::AI_Follow: return 2; + case ESM::AI_Escort: return 3; + case ESM::AI_Activate: return 4; case ESM::AI_CNDT: - default: return QString("None"); + default: return QVariant(); } case 1: // wander dist if (content.mType == ESM::AI_Wander) @@ -1494,7 +1473,7 @@ namespace CSMWorld return QVariant(); case 5: // wander repeat if (content.mType == ESM::AI_Wander) - return QString(content.mWander.mShouldRepeat ? "Yes" : "No"); + return content.mWander.mShouldRepeat; else return QVariant(); case 6: // activate name @@ -1554,18 +1533,14 @@ namespace CSMWorld switch(subColIndex) { case 0: // ai package type - if ("AI Wander" == value.toString().toStdString()) - content.mType = ESM::AI_Wander; - else if ("AI Travel" == value.toString().toStdString()) - content.mType = ESM::AI_Travel; - else if ("AI Follow" == value.toString().toStdString()) - content.mType = ESM::AI_Follow; - else if ("AI Escort" == value.toString().toStdString()) - content.mType = ESM::AI_Escort; - else if ("AI Activate" == value.toString().toStdString()) - content.mType = ESM::AI_Activate; - else - content.mType = ESM::AI_CNDT; + switch (value.toInt()) + { + case 0: content.mType = ESM::AI_Wander; + case 1: content.mType = ESM::AI_Travel; + case 2: content.mType = ESM::AI_Follow; + case 3: content.mType = ESM::AI_Escort; + case 4: content.mType = ESM::AI_Activate; + } break; // always save case 1: @@ -1592,12 +1567,8 @@ namespace CSMWorld case 5: if (content.mType == ESM::AI_Wander) { - if ("Yes" == value.toString().toStdString()) - content.mWander.mShouldRepeat = 1; - if ("No" == value.toString().toStdString()) - content.mWander.mShouldRepeat = 0; - else - return; // return without saving + content.mWander.mShouldRepeat = static_cast(value.toInt()); + break; } case 6: // NAME32 if (content.mType == ESM::AI_Activate) diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 3bdf8361f..caf1041c6 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -188,7 +188,7 @@ CSMWorld::RefIdCollection::RefIdCollection() new ActorAiRefIdAdapter (UniversalId::Type_Creature))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), aiMap)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_AiPackage, CSMWorld::ColumnBase::Display_String)); + new RefIdColumn (Columns::ColumnId_AiPackageType, CSMWorld::ColumnBase::Display_AiPackageType)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_AiWanderDist, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( @@ -198,7 +198,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_AiWanderIdle, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_AiWanderRepeat, CSMWorld::ColumnBase::Display_String)); + new RefIdColumn (Columns::ColumnId_AiWanderRepeat, CSMWorld::ColumnBase::Display_YesNo)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_AiActivateName, CSMWorld::ColumnBase::Display_String)); mColumns.back().addColumn( diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 3f0c10053..5908c67a1 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -88,7 +88,9 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) { CSMWorld::ColumnBase::Display_SkillImpact, CSMWorld::Columns::ColumnId_SkillImpact, true }, { CSMWorld::ColumnBase::Display_EffectRange, CSMWorld::Columns::ColumnId_EffectRange, false }, { CSMWorld::ColumnBase::Display_EffectId, CSMWorld::Columns::ColumnId_EffectId, false }, - { CSMWorld::ColumnBase::Display_PartRefType, CSMWorld::Columns::ColumnId_PartRefType, false } + { CSMWorld::ColumnBase::Display_PartRefType, CSMWorld::Columns::ColumnId_PartRefType, false }, + { CSMWorld::ColumnBase::Display_AiPackageType, CSMWorld::Columns::ColumnId_AiPackageType, false }, + { CSMWorld::ColumnBase::Display_YesNo, CSMWorld::Columns::ColumnId_AiWanderRepeat, false } }; for (std::size_t i=0; i Date: Sat, 18 Apr 2015 10:07:53 +1000 Subject: [PATCH 728/740] Change the cell edit selection behaviour of the nested tables. Also auto-expand the enum delegate selections (both main table as well as nested table in the dialogue subview) --- apps/opencs/view/world/dialoguesubview.cpp | 2 ++ apps/opencs/view/world/enumdelegate.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 10a192668..9d718cf81 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -444,6 +444,8 @@ void CSVWorld::EditWidget::remake(int row) NestedTable* table = new NestedTable(mDocument, mNestedModels.back(), this); // FIXME: does not work well when enum delegates are used //table->resizeColumnsToContents(); + table->setEditTriggers(QAbstractItemView::CurrentChanged); + table->setSelectionBehavior(QAbstractItemView::SelectItems); QLabel* label = diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp index eb523f781..c635948a3 100644 --- a/apps/opencs/view/world/enumdelegate.cpp +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -88,6 +88,7 @@ void CSVWorld::EnumDelegate::setEditorData (QWidget *editor, const QModelIndex& if (mValues[i].first==value) { comboBox->setCurrentIndex (i); + comboBox->showPopup(); break; } } From 4607c4b5816e151bca2af6237ed51a682f148c8e Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 18 Apr 2015 15:33:49 +1200 Subject: [PATCH 729/740] Add Modified DateTime to plug-in tooltip. (Fixes #2479) --- components/contentselector/model/esmfile.cpp | 7 ++++--- components/contentselector/model/esmfile.hpp | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/components/contentselector/model/esmfile.cpp b/components/contentselector/model/esmfile.cpp index 1ac1c7500..46a7c9600 100644 --- a/components/contentselector/model/esmfile.cpp +++ b/components/contentselector/model/esmfile.cpp @@ -6,9 +6,10 @@ int ContentSelectorModel::EsmFile::sPropertyCount = 7; QString ContentSelectorModel::EsmFile::sToolTip = QString("Author: %1
\ Version: %2
\ - Path:
%3
\ -
Description:
%4
\ -
Dependencies: %5
"); + Modified: %3
\ + Path:
%4
\ +
Description:
%5
\ +
Dependencies: %6
"); ContentSelectorModel::EsmFile::EsmFile(QString fileName, ModelItem *parent) diff --git a/components/contentselector/model/esmfile.hpp b/components/contentselector/model/esmfile.hpp index d0cebab3c..614eee298 100644 --- a/components/contentselector/model/esmfile.hpp +++ b/components/contentselector/model/esmfile.hpp @@ -59,6 +59,7 @@ namespace ContentSelectorModel inline QString description() const { return mDescription; } inline QString toolTip() const { return sToolTip.arg(mAuthor) .arg(mFormat) + .arg(mModified.toString(Qt::ISODate)) .arg(mPath) .arg(mDescription) .arg(mGameFiles.join(", ")); From 48a6006202a5f8c5c8d006fd616983337b39514e Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 18 Apr 2015 14:16:55 +1000 Subject: [PATCH 730/740] Prevent enum delegates from auto expanding when opening a dialogue subview. --- apps/opencs/view/world/dialoguesubview.cpp | 3 +-- apps/opencs/view/world/enumdelegate.cpp | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 9d718cf81..9358bf6c7 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -444,10 +444,9 @@ void CSVWorld::EditWidget::remake(int row) NestedTable* table = new NestedTable(mDocument, mNestedModels.back(), this); // FIXME: does not work well when enum delegates are used //table->resizeColumnsToContents(); - table->setEditTriggers(QAbstractItemView::CurrentChanged); + table->setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::CurrentChanged); table->setSelectionBehavior(QAbstractItemView::SelectItems); - QLabel* label = new QLabel (mTable->headerData (i, Qt::Horizontal, Qt::DisplayRole).toString(), mMainWidget); diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp index c635948a3..bda93678a 100644 --- a/apps/opencs/view/world/enumdelegate.cpp +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -88,7 +88,8 @@ void CSVWorld::EnumDelegate::setEditorData (QWidget *editor, const QModelIndex& if (mValues[i].first==value) { comboBox->setCurrentIndex (i); - comboBox->showPopup(); + if(!tryDisplay) + comboBox->showPopup(); break; } } From 7561b195abd9e6e08b27fcf7c8a4bb3f5723d41a Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 18 Apr 2015 15:28:34 +1000 Subject: [PATCH 731/740] Revert auto expansion of enums as it was interfering with row based operations. Fix default values of magic effect skill & attributes. --- apps/opencs/model/world/nestedcoladapterimp.hpp | 4 ++-- apps/opencs/view/world/dialoguesubview.cpp | 5 +++-- apps/opencs/view/world/enumdelegate.cpp | 2 -- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/world/nestedcoladapterimp.hpp b/apps/opencs/model/world/nestedcoladapterimp.hpp index 1ee447f34..841c3955a 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.hpp +++ b/apps/opencs/model/world/nestedcoladapterimp.hpp @@ -252,8 +252,8 @@ namespace CSMWorld // blank row ESM::ENAMstruct effect; effect.mEffectID = 0; - effect.mSkill = 0; - effect.mAttribute = 0; + effect.mSkill = -1; + effect.mAttribute = -1; effect.mRange = 0; effect.mArea = 0; effect.mDuration = 0; diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 9358bf6c7..6626d67c3 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -443,9 +443,10 @@ void CSVWorld::EditWidget::remake(int row) NestedTable* table = new NestedTable(mDocument, mNestedModels.back(), this); // FIXME: does not work well when enum delegates are used - //table->resizeColumnsToContents(); + table->setVisible(false); + table->resizeColumnsToContents(); + table->setVisible(true); table->setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::CurrentChanged); - table->setSelectionBehavior(QAbstractItemView::SelectItems); QLabel* label = new QLabel (mTable->headerData (i, Qt::Horizontal, Qt::DisplayRole).toString(), mMainWidget); diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp index bda93678a..eb523f781 100644 --- a/apps/opencs/view/world/enumdelegate.cpp +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -88,8 +88,6 @@ void CSVWorld::EnumDelegate::setEditorData (QWidget *editor, const QModelIndex& if (mValues[i].first==value) { comboBox->setCurrentIndex (i); - if(!tryDisplay) - comboBox->showPopup(); break; } } From dd1e4e8b691c45669669503033b00c972335767b Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 19 Apr 2015 08:58:52 +1000 Subject: [PATCH 732/740] Remove gcc/clang warnings. --- .../model/world/nestedcoladapterimp.cpp | 56 ++++++------- .../model/world/nestedcoladapterimp.hpp | 84 +++++++++---------- .../model/world/nestedcolumnadapter.hpp | 14 ++-- .../opencs/model/world/nestedidcollection.hpp | 14 ++-- apps/opencs/model/world/refidadapterimp.hpp | 16 ++-- 5 files changed, 92 insertions(+), 92 deletions(-) diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index d974a34c7..bd6a5c449 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -10,7 +10,7 @@ namespace CSMWorld { PathgridPointListAdapter::PathgridPointListAdapter () {} - void PathgridPointListAdapter::addNestedRow(Record& record, int position) const + void PathgridPointListAdapter::addRow(Record& record, int position) const { Pathgrid pathgrid = record.get(); @@ -43,7 +43,7 @@ namespace CSMWorld record.setModified (pathgrid); } - void PathgridPointListAdapter::removeNestedRow(Record& record, int rowToRemove) const + void PathgridPointListAdapter::removeRow(Record& record, int rowToRemove) const { Pathgrid pathgrid = record.get(); @@ -78,7 +78,7 @@ namespace CSMWorld record.setModified (pathgrid); } - void PathgridPointListAdapter::setNestedTable(Record& record, + void PathgridPointListAdapter::setTable(Record& record, const NestedTableWrapperBase& nestedTable) const { Pathgrid pathgrid = record.get(); @@ -100,7 +100,7 @@ namespace CSMWorld return new PathgridPointsWrap(record.get()); } - QVariant PathgridPointListAdapter::getNestedData(const Record& record, + QVariant PathgridPointListAdapter::getData(const Record& record, int subRowIndex, int subColIndex) const { ESM::Pathgrid::Point point = record.get().mPoints[subRowIndex]; @@ -114,7 +114,7 @@ namespace CSMWorld } } - void PathgridPointListAdapter::setNestedData(Record& record, + void PathgridPointListAdapter::setData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const { Pathgrid pathgrid = record.get(); @@ -133,12 +133,12 @@ namespace CSMWorld record.setModified (pathgrid); } - int PathgridPointListAdapter::getNestedColumnsCount(const Record& record) const + int PathgridPointListAdapter::getColumnsCount(const Record& record) const { return 4; } - int PathgridPointListAdapter::getNestedRowsCount(const Record& record) const + int PathgridPointListAdapter::getRowsCount(const Record& record) const { return static_cast(record.get().mPoints.size()); } @@ -146,7 +146,7 @@ namespace CSMWorld PathgridEdgeListAdapter::PathgridEdgeListAdapter () {} // ToDo: seems to be auto-sorted in the dialog table display after insertion - void PathgridEdgeListAdapter::addNestedRow(Record& record, int position) const + void PathgridEdgeListAdapter::addRow(Record& record, int position) const { Pathgrid pathgrid = record.get(); @@ -167,7 +167,7 @@ namespace CSMWorld record.setModified (pathgrid); } - void PathgridEdgeListAdapter::removeNestedRow(Record& record, int rowToRemove) const + void PathgridEdgeListAdapter::removeRow(Record& record, int rowToRemove) const { Pathgrid pathgrid = record.get(); @@ -181,7 +181,7 @@ namespace CSMWorld record.setModified (pathgrid); } - void PathgridEdgeListAdapter::setNestedTable(Record& record, + void PathgridEdgeListAdapter::setTable(Record& record, const NestedTableWrapperBase& nestedTable) const { Pathgrid pathgrid = record.get(); @@ -198,7 +198,7 @@ namespace CSMWorld return new NestedTableWrapper(record.get().mEdges); } - QVariant PathgridEdgeListAdapter::getNestedData(const Record& record, + QVariant PathgridEdgeListAdapter::getData(const Record& record, int subRowIndex, int subColIndex) const { Pathgrid pathgrid = record.get(); @@ -217,7 +217,7 @@ namespace CSMWorld } // ToDo: detect duplicates in mEdges - void PathgridEdgeListAdapter::setNestedData(Record& record, + void PathgridEdgeListAdapter::setData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const { Pathgrid pathgrid = record.get(); @@ -239,19 +239,19 @@ namespace CSMWorld record.setModified (pathgrid); } - int PathgridEdgeListAdapter::getNestedColumnsCount(const Record& record) const + int PathgridEdgeListAdapter::getColumnsCount(const Record& record) const { return 3; } - int PathgridEdgeListAdapter::getNestedRowsCount(const Record& record) const + int PathgridEdgeListAdapter::getRowsCount(const Record& record) const { return static_cast(record.get().mEdges.size()); } FactionReactionsAdapter::FactionReactionsAdapter () {} - void FactionReactionsAdapter::addNestedRow(Record& record, int position) const + void FactionReactionsAdapter::addRow(Record& record, int position) const { ESM::Faction faction = record.get(); @@ -263,7 +263,7 @@ namespace CSMWorld record.setModified (faction); } - void FactionReactionsAdapter::removeNestedRow(Record& record, int rowToRemove) const + void FactionReactionsAdapter::removeRow(Record& record, int rowToRemove) const { ESM::Faction faction = record.get(); @@ -282,7 +282,7 @@ namespace CSMWorld record.setModified (faction); } - void FactionReactionsAdapter::setNestedTable(Record& record, + void FactionReactionsAdapter::setTable(Record& record, const NestedTableWrapperBase& nestedTable) const { ESM::Faction faction = record.get(); @@ -299,7 +299,7 @@ namespace CSMWorld return new NestedTableWrapper >(record.get().mReactions); } - QVariant FactionReactionsAdapter::getNestedData(const Record& record, + QVariant FactionReactionsAdapter::getData(const Record& record, int subRowIndex, int subColIndex) const { ESM::Faction faction = record.get(); @@ -322,7 +322,7 @@ namespace CSMWorld } } - void FactionReactionsAdapter::setNestedData(Record& record, + void FactionReactionsAdapter::setData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const { ESM::Faction faction = record.get(); @@ -360,19 +360,19 @@ namespace CSMWorld record.setModified (faction); } - int FactionReactionsAdapter::getNestedColumnsCount(const Record& record) const + int FactionReactionsAdapter::getColumnsCount(const Record& record) const { return 2; } - int FactionReactionsAdapter::getNestedRowsCount(const Record& record) const + int FactionReactionsAdapter::getRowsCount(const Record& record) const { return static_cast(record.get().mReactions.size()); } RegionSoundListAdapter::RegionSoundListAdapter () {} - void RegionSoundListAdapter::addNestedRow(Record& record, int position) const + void RegionSoundListAdapter::addRow(Record& record, int position) const { ESM::Region region = record.get(); @@ -388,7 +388,7 @@ namespace CSMWorld record.setModified (region); } - void RegionSoundListAdapter::removeNestedRow(Record& record, int rowToRemove) const + void RegionSoundListAdapter::removeRow(Record& record, int rowToRemove) const { ESM::Region region = record.get(); @@ -402,7 +402,7 @@ namespace CSMWorld record.setModified (region); } - void RegionSoundListAdapter::setNestedTable(Record& record, + void RegionSoundListAdapter::setTable(Record& record, const NestedTableWrapperBase& nestedTable) const { ESM::Region region = record.get(); @@ -419,7 +419,7 @@ namespace CSMWorld return new NestedTableWrapper >(record.get().mSoundList); } - QVariant RegionSoundListAdapter::getNestedData(const Record& record, + QVariant RegionSoundListAdapter::getData(const Record& record, int subRowIndex, int subColIndex) const { ESM::Region region = record.get(); @@ -438,7 +438,7 @@ namespace CSMWorld } } - void RegionSoundListAdapter::setNestedData(Record& record, + void RegionSoundListAdapter::setData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const { ESM::Region region = record.get(); @@ -461,12 +461,12 @@ namespace CSMWorld record.setModified (region); } - int RegionSoundListAdapter::getNestedColumnsCount(const Record& record) const + int RegionSoundListAdapter::getColumnsCount(const Record& record) const { return 2; } - int RegionSoundListAdapter::getNestedRowsCount(const Record& record) const + int RegionSoundListAdapter::getRowsCount(const Record& record) const { return static_cast(record.get().mSoundList.size()); } diff --git a/apps/opencs/model/world/nestedcoladapterimp.hpp b/apps/opencs/model/world/nestedcoladapterimp.hpp index 841c3955a..8d0b0ce7a 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.hpp +++ b/apps/opencs/model/world/nestedcoladapterimp.hpp @@ -42,24 +42,24 @@ namespace CSMWorld public: PathgridPointListAdapter (); - virtual void addNestedRow(Record& record, int position) const; + virtual void addRow(Record& record, int position) const; - virtual void removeNestedRow(Record& record, int rowToRemove) const; + virtual void removeRow(Record& record, int rowToRemove) const; - virtual void setNestedTable(Record& record, + virtual void setTable(Record& record, const NestedTableWrapperBase& nestedTable) const; virtual NestedTableWrapperBase* nestedTable(const Record& record) const; - virtual QVariant getNestedData(const Record& record, + virtual QVariant getData(const Record& record, int subRowIndex, int subColIndex) const; - virtual void setNestedData(Record& record, + virtual void setData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const; - virtual int getNestedColumnsCount(const Record& record) const; + virtual int getColumnsCount(const Record& record) const; - virtual int getNestedRowsCount(const Record& record) const; + virtual int getRowsCount(const Record& record) const; }; class PathgridEdgeListAdapter : public NestedColumnAdapter @@ -67,24 +67,24 @@ namespace CSMWorld public: PathgridEdgeListAdapter (); - virtual void addNestedRow(Record& record, int position) const; + virtual void addRow(Record& record, int position) const; - virtual void removeNestedRow(Record& record, int rowToRemove) const; + virtual void removeRow(Record& record, int rowToRemove) const; - virtual void setNestedTable(Record& record, + virtual void setTable(Record& record, const NestedTableWrapperBase& nestedTable) const; virtual NestedTableWrapperBase* nestedTable(const Record& record) const; - virtual QVariant getNestedData(const Record& record, + virtual QVariant getData(const Record& record, int subRowIndex, int subColIndex) const; - virtual void setNestedData(Record& record, + virtual void setData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const; - virtual int getNestedColumnsCount(const Record& record) const; + virtual int getColumnsCount(const Record& record) const; - virtual int getNestedRowsCount(const Record& record) const; + virtual int getRowsCount(const Record& record) const; }; class FactionReactionsAdapter : public NestedColumnAdapter @@ -92,24 +92,24 @@ namespace CSMWorld public: FactionReactionsAdapter (); - virtual void addNestedRow(Record& record, int position) const; + virtual void addRow(Record& record, int position) const; - virtual void removeNestedRow(Record& record, int rowToRemove) const; + virtual void removeRow(Record& record, int rowToRemove) const; - virtual void setNestedTable(Record& record, + virtual void setTable(Record& record, const NestedTableWrapperBase& nestedTable) const; virtual NestedTableWrapperBase* nestedTable(const Record& record) const; - virtual QVariant getNestedData(const Record& record, + virtual QVariant getData(const Record& record, int subRowIndex, int subColIndex) const; - virtual void setNestedData(Record& record, + virtual void setData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const; - virtual int getNestedColumnsCount(const Record& record) const; + virtual int getColumnsCount(const Record& record) const; - virtual int getNestedRowsCount(const Record& record) const; + virtual int getRowsCount(const Record& record) const; }; class RegionSoundListAdapter : public NestedColumnAdapter @@ -117,24 +117,24 @@ namespace CSMWorld public: RegionSoundListAdapter (); - virtual void addNestedRow(Record& record, int position) const; + virtual void addRow(Record& record, int position) const; - virtual void removeNestedRow(Record& record, int rowToRemove) const; + virtual void removeRow(Record& record, int rowToRemove) const; - virtual void setNestedTable(Record& record, + virtual void setTable(Record& record, const NestedTableWrapperBase& nestedTable) const; virtual NestedTableWrapperBase* nestedTable(const Record& record) const; - virtual QVariant getNestedData(const Record& record, + virtual QVariant getData(const Record& record, int subRowIndex, int subColIndex) const; - virtual void setNestedData(Record& record, + virtual void setData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const; - virtual int getNestedColumnsCount(const Record& record) const; + virtual int getColumnsCount(const Record& record) const; - virtual int getNestedRowsCount(const Record& record) const; + virtual int getRowsCount(const Record& record) const; }; template @@ -143,7 +143,7 @@ namespace CSMWorld public: SpellListAdapter () {} - virtual void addNestedRow(Record& record, int position) const + virtual void addRow(Record& record, int position) const { ESXRecordT raceOrBthSgn = record.get(); @@ -157,7 +157,7 @@ namespace CSMWorld record.setModified (raceOrBthSgn); } - virtual void removeNestedRow(Record& record, int rowToRemove) const + virtual void removeRow(Record& record, int rowToRemove) const { ESXRecordT raceOrBthSgn = record.get(); @@ -171,7 +171,7 @@ namespace CSMWorld record.setModified (raceOrBthSgn); } - virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const + virtual void setTable(Record& record, const NestedTableWrapperBase& nestedTable) const { ESXRecordT raceOrBthSgn = record.get(); @@ -187,7 +187,7 @@ namespace CSMWorld return new NestedTableWrapper >(record.get().mPowers.mList); } - virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const + virtual QVariant getData(const Record& record, int subRowIndex, int subColIndex) const { ESXRecordT raceOrBthSgn = record.get(); @@ -204,7 +204,7 @@ namespace CSMWorld } } - virtual void setNestedData(Record& record, const QVariant& value, + virtual void setData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const { ESXRecordT raceOrBthSgn = record.get(); @@ -226,12 +226,12 @@ namespace CSMWorld record.setModified (raceOrBthSgn); } - virtual int getNestedColumnsCount(const Record& record) const + virtual int getColumnsCount(const Record& record) const { return 1; } - virtual int getNestedRowsCount(const Record& record) const + virtual int getRowsCount(const Record& record) const { return static_cast(record.get().mPowers.mList.size()); } @@ -243,7 +243,7 @@ namespace CSMWorld public: EffectsListAdapter () {} - virtual void addNestedRow(Record& record, int position) const + virtual void addRow(Record& record, int position) const { ESXRecordT magic = record.get(); @@ -265,7 +265,7 @@ namespace CSMWorld record.setModified (magic); } - virtual void removeNestedRow(Record& record, int rowToRemove) const + virtual void removeRow(Record& record, int rowToRemove) const { ESXRecordT magic = record.get(); @@ -279,7 +279,7 @@ namespace CSMWorld record.setModified (magic); } - virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const + virtual void setTable(Record& record, const NestedTableWrapperBase& nestedTable) const { ESXRecordT magic = record.get(); @@ -295,7 +295,7 @@ namespace CSMWorld return new NestedTableWrapper >(record.get().mEffects.mList); } - virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const + virtual QVariant getData(const Record& record, int subRowIndex, int subColIndex) const { ESXRecordT magic = record.get(); @@ -331,7 +331,7 @@ namespace CSMWorld } } - virtual void setNestedData(Record& record, const QVariant& value, + virtual void setData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const { ESXRecordT magic = record.get(); @@ -376,12 +376,12 @@ namespace CSMWorld record.setModified (magic); } - virtual int getNestedColumnsCount(const Record& record) const + virtual int getColumnsCount(const Record& record) const { return 8; } - virtual int getNestedRowsCount(const Record& record) const + virtual int getRowsCount(const Record& record) const { return static_cast(record.get().mEffects.mList.size()); } diff --git a/apps/opencs/model/world/nestedcolumnadapter.hpp b/apps/opencs/model/world/nestedcolumnadapter.hpp index e7e66ed4d..5e7256fa7 100644 --- a/apps/opencs/model/world/nestedcolumnadapter.hpp +++ b/apps/opencs/model/world/nestedcolumnadapter.hpp @@ -19,21 +19,21 @@ namespace CSMWorld virtual ~NestedColumnAdapter() {} - virtual void addNestedRow(Record& record, int position) const = 0; + virtual void addRow(Record& record, int position) const = 0; - virtual void removeNestedRow(Record& record, int rowToRemove) const = 0; + virtual void removeRow(Record& record, int rowToRemove) const = 0; - virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const = 0; + virtual void setTable(Record& record, const NestedTableWrapperBase& nestedTable) const = 0; virtual NestedTableWrapperBase* nestedTable(const Record& record) const = 0; - virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const = 0; + virtual QVariant getData(const Record& record, int subRowIndex, int subColIndex) const = 0; - virtual void setNestedData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const = 0; + virtual void setData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const = 0; - virtual int getNestedColumnsCount(const Record& record) const = 0; + virtual int getColumnsCount(const Record& record) const = 0; - virtual int getNestedRowsCount(const Record& record) const = 0; + virtual int getRowsCount(const Record& record) const = 0; }; } diff --git a/apps/opencs/model/world/nestedidcollection.hpp b/apps/opencs/model/world/nestedidcollection.hpp index 0cf51b9d8..2b795f9c6 100644 --- a/apps/opencs/model/world/nestedidcollection.hpp +++ b/apps/opencs/model/world/nestedidcollection.hpp @@ -93,7 +93,7 @@ namespace CSMWorld Record record; record.assign(Collection::getRecord(row)); - getAdapter(Collection::getColumn(column)).addNestedRow(record, position); + getAdapter(Collection::getColumn(column)).addRow(record, position); Collection::setRecord(row, record); } @@ -104,7 +104,7 @@ namespace CSMWorld Record record; record.assign(Collection::getRecord(row)); - getAdapter(Collection::getColumn(column)).removeNestedRow(record, subRow); + getAdapter(Collection::getColumn(column)).removeRow(record, subRow); Collection::setRecord(row, record); } @@ -113,7 +113,7 @@ namespace CSMWorld QVariant NestedIdCollection::getNestedData (int row, int column, int subRow, int subColumn) const { - return getAdapter(Collection::getColumn(column)).getNestedData( + return getAdapter(Collection::getColumn(column)).getData( Collection::getRecord(row), subRow, subColumn); } @@ -124,7 +124,7 @@ namespace CSMWorld Record record; record.assign(Collection::getRecord(row)); - getAdapter(Collection::getColumn(column)).setNestedData( + getAdapter(Collection::getColumn(column)).setData( record, data, subRow, subColumn); Collection::setRecord(row, record); @@ -145,7 +145,7 @@ namespace CSMWorld Record record; record.assign(Collection::getRecord(row)); - getAdapter(Collection::getColumn(column)).setNestedTable( + getAdapter(Collection::getColumn(column)).setTable( record, nestedTable); Collection::setRecord(row, record); @@ -154,14 +154,14 @@ namespace CSMWorld template int NestedIdCollection::getNestedRowsCount(int row, int column) const { - return getAdapter(Collection::getColumn(column)).getNestedRowsCount( + return getAdapter(Collection::getColumn(column)).getRowsCount( Collection::getRecord(row)); } template int NestedIdCollection::getNestedColumnsCount(int row, int column) const { - return getAdapter(Collection::getColumn(column)).getNestedColumnsCount( + return getAdapter(Collection::getColumn(column)).getColumnsCount( Collection::getRecord(row)); } diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 5fd888441..9556c83e3 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -867,7 +867,7 @@ namespace CSMWorld { Record& record = static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); - EffectsListAdapter::addNestedRow(record, position); + EffectsListAdapter::addRow(record, position); } using NestedRefIdAdapterBase::removeNestedRow; @@ -876,7 +876,7 @@ namespace CSMWorld { Record& record = static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); - EffectsListAdapter::removeNestedRow(record, rowToRemove); + EffectsListAdapter::removeRow(record, rowToRemove); } using NestedRefIdAdapterBase::setNestedTable; @@ -885,7 +885,7 @@ namespace CSMWorld { Record& record = static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); - EffectsListAdapter::setNestedTable(record, nestedTable); + EffectsListAdapter::setTable(record, nestedTable); } using NestedRefIdAdapterBase::nestedTable; @@ -903,7 +903,7 @@ namespace CSMWorld { const Record& record = static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); - return EffectsListAdapter::getNestedData(record, subRowIndex, subColIndex); + return EffectsListAdapter::getData(record, subRowIndex, subColIndex); } using NestedRefIdAdapterBase::setNestedData; @@ -912,14 +912,14 @@ namespace CSMWorld { Record& record = static_cast&> (data.getRecord (RefIdData::LocalIndex (row, mType))); - EffectsListAdapter::setNestedData(record, value, subRowIndex, subColIndex); + EffectsListAdapter::setData(record, value, subRowIndex, subColIndex); } using NestedRefIdAdapterBase::getNestedColumnsCount; virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const { const Record record; // not used, just a dummy - return EffectsListAdapter::getNestedColumnsCount(record); + return EffectsListAdapter::getColumnsCount(record); } using NestedRefIdAdapterBase::getNestedRowsCount; @@ -927,7 +927,7 @@ namespace CSMWorld { const Record& record = static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); - return EffectsListAdapter::getNestedRowsCount(record); + return EffectsListAdapter::getRowsCount(record); } }; @@ -1731,7 +1731,7 @@ namespace CSMWorld { case 0: { - if (content.mPart >=0 && content.mPart < ESM::PRT_Count) + if (content.mPart < ESM::PRT_Count) return content.mPart; else throw std::runtime_error("Part Reference Type unexpected value"); From 8b1ac451acd0b5f3838d0a46e2cd7dd150d25f73 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 19 Apr 2015 09:42:44 +1000 Subject: [PATCH 733/740] More warning fixes. --- apps/opencs/model/world/nestedcoladapterimp.cpp | 8 ++++---- apps/opencs/model/world/nestedcoladapterimp.hpp | 12 ++++++------ apps/opencs/model/world/nestedcolumnadapter.hpp | 2 +- apps/opencs/model/world/nestedidcollection.hpp | 2 +- apps/opencs/model/world/refidadapterimp.hpp | 10 +--------- 5 files changed, 13 insertions(+), 21 deletions(-) diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index bd6a5c449..bfb2fb578 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -94,7 +94,7 @@ namespace CSMWorld record.setModified (pathgrid); } - NestedTableWrapperBase* PathgridPointListAdapter::nestedTable(const Record& record) const + NestedTableWrapperBase* PathgridPointListAdapter::table(const Record& record) const { // deleted by dtor of NestedTableStoring return new PathgridPointsWrap(record.get()); @@ -192,7 +192,7 @@ namespace CSMWorld record.setModified (pathgrid); } - NestedTableWrapperBase* PathgridEdgeListAdapter::nestedTable(const Record& record) const + NestedTableWrapperBase* PathgridEdgeListAdapter::table(const Record& record) const { // deleted by dtor of NestedTableStoring return new NestedTableWrapper(record.get().mEdges); @@ -293,7 +293,7 @@ namespace CSMWorld record.setModified (faction); } - NestedTableWrapperBase* FactionReactionsAdapter::nestedTable(const Record& record) const + NestedTableWrapperBase* FactionReactionsAdapter::table(const Record& record) const { // deleted by dtor of NestedTableStoring return new NestedTableWrapper >(record.get().mReactions); @@ -413,7 +413,7 @@ namespace CSMWorld record.setModified (region); } - NestedTableWrapperBase* RegionSoundListAdapter::nestedTable(const Record& record) const + NestedTableWrapperBase* RegionSoundListAdapter::table(const Record& record) const { // deleted by dtor of NestedTableStoring return new NestedTableWrapper >(record.get().mSoundList); diff --git a/apps/opencs/model/world/nestedcoladapterimp.hpp b/apps/opencs/model/world/nestedcoladapterimp.hpp index 8d0b0ce7a..4a7101cba 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.hpp +++ b/apps/opencs/model/world/nestedcoladapterimp.hpp @@ -49,7 +49,7 @@ namespace CSMWorld virtual void setTable(Record& record, const NestedTableWrapperBase& nestedTable) const; - virtual NestedTableWrapperBase* nestedTable(const Record& record) const; + virtual NestedTableWrapperBase* table(const Record& record) const; virtual QVariant getData(const Record& record, int subRowIndex, int subColIndex) const; @@ -74,7 +74,7 @@ namespace CSMWorld virtual void setTable(Record& record, const NestedTableWrapperBase& nestedTable) const; - virtual NestedTableWrapperBase* nestedTable(const Record& record) const; + virtual NestedTableWrapperBase* table(const Record& record) const; virtual QVariant getData(const Record& record, int subRowIndex, int subColIndex) const; @@ -99,7 +99,7 @@ namespace CSMWorld virtual void setTable(Record& record, const NestedTableWrapperBase& nestedTable) const; - virtual NestedTableWrapperBase* nestedTable(const Record& record) const; + virtual NestedTableWrapperBase* table(const Record& record) const; virtual QVariant getData(const Record& record, int subRowIndex, int subColIndex) const; @@ -124,7 +124,7 @@ namespace CSMWorld virtual void setTable(Record& record, const NestedTableWrapperBase& nestedTable) const; - virtual NestedTableWrapperBase* nestedTable(const Record& record) const; + virtual NestedTableWrapperBase* table(const Record& record) const; virtual QVariant getData(const Record& record, int subRowIndex, int subColIndex) const; @@ -181,7 +181,7 @@ namespace CSMWorld record.setModified (raceOrBthSgn); } - virtual NestedTableWrapperBase* nestedTable(const Record& record) const + virtual NestedTableWrapperBase* table(const Record& record) const { // deleted by dtor of NestedTableStoring return new NestedTableWrapper >(record.get().mPowers.mList); @@ -289,7 +289,7 @@ namespace CSMWorld record.setModified (magic); } - virtual NestedTableWrapperBase* nestedTable(const Record& record) const + virtual NestedTableWrapperBase* table(const Record& record) const { // deleted by dtor of NestedTableStoring return new NestedTableWrapper >(record.get().mEffects.mList); diff --git a/apps/opencs/model/world/nestedcolumnadapter.hpp b/apps/opencs/model/world/nestedcolumnadapter.hpp index 5e7256fa7..462b5a5ab 100644 --- a/apps/opencs/model/world/nestedcolumnadapter.hpp +++ b/apps/opencs/model/world/nestedcolumnadapter.hpp @@ -25,7 +25,7 @@ namespace CSMWorld virtual void setTable(Record& record, const NestedTableWrapperBase& nestedTable) const = 0; - virtual NestedTableWrapperBase* nestedTable(const Record& record) const = 0; + virtual NestedTableWrapperBase* table(const Record& record) const = 0; virtual QVariant getData(const Record& record, int subRowIndex, int subColIndex) const = 0; diff --git a/apps/opencs/model/world/nestedidcollection.hpp b/apps/opencs/model/world/nestedidcollection.hpp index 2b795f9c6..792a13b7d 100644 --- a/apps/opencs/model/world/nestedidcollection.hpp +++ b/apps/opencs/model/world/nestedidcollection.hpp @@ -134,7 +134,7 @@ namespace CSMWorld CSMWorld::NestedTableWrapperBase* NestedIdCollection::nestedTable(int row, int column) const { - return getAdapter(Collection::getColumn(column)).nestedTable( + return getAdapter(Collection::getColumn(column)).table( Collection::getRecord(row)); } diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 9556c83e3..d3d52d2e1 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -861,7 +861,6 @@ namespace CSMWorld virtual ~EffectsRefIdAdapter() {} - using NestedRefIdAdapterBase::addNestedRow; virtual void addNestedRow (const RefIdColumn *column, RefIdData& data, int index, int position) const { @@ -870,7 +869,6 @@ namespace CSMWorld EffectsListAdapter::addRow(record, position); } - using NestedRefIdAdapterBase::removeNestedRow; virtual void removeNestedRow (const RefIdColumn *column, RefIdData& data, int index, int rowToRemove) const { @@ -879,7 +877,6 @@ namespace CSMWorld EffectsListAdapter::removeRow(record, rowToRemove); } - using NestedRefIdAdapterBase::setNestedTable; virtual void setNestedTable (const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const { @@ -888,16 +885,14 @@ namespace CSMWorld EffectsListAdapter::setTable(record, nestedTable); } - using NestedRefIdAdapterBase::nestedTable; virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, const RefIdData& data, int index) const { const Record& record = static_cast&> (data.getRecord (RefIdData::LocalIndex (index, mType))); - return EffectsListAdapter::nestedTable(record); + return EffectsListAdapter::table(record); } - using NestedRefIdAdapterBase::getNestedData; virtual QVariant getNestedData (const RefIdColumn *column, const RefIdData& data, int index, int subRowIndex, int subColIndex) const { @@ -906,7 +901,6 @@ namespace CSMWorld return EffectsListAdapter::getData(record, subRowIndex, subColIndex); } - using NestedRefIdAdapterBase::setNestedData; virtual void setNestedData (const RefIdColumn *column, RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const { @@ -915,14 +909,12 @@ namespace CSMWorld EffectsListAdapter::setData(record, value, subRowIndex, subColIndex); } - using NestedRefIdAdapterBase::getNestedColumnsCount; virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const { const Record record; // not used, just a dummy return EffectsListAdapter::getColumnsCount(record); } - using NestedRefIdAdapterBase::getNestedRowsCount; virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const { const Record& record = From cb3396643b44d07d95df7d17a396103c1959bf58 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 19 Apr 2015 10:32:06 +1000 Subject: [PATCH 734/740] Back to the old layout of dialoguesubview. --- apps/opencs/view/world/dialoguesubview.cpp | 39 ++++++++++------------ 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 6626d67c3..2e800b56f 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -405,21 +405,22 @@ void CSVWorld::EditWidget::remake(int row) line->setGeometry(QRect(320, 150, 118, 3)); line->setFrameShape(QFrame::HLine); line->setFrameShadow(QFrame::Sunken); + + QFrame* line2 = new QFrame(mMainWidget); + line2->setObjectName(QString::fromUtf8("line")); + line2->setGeometry(QRect(320, 150, 118, 3)); + line2->setFrameShape(QFrame::HLine); + line2->setFrameShadow(QFrame::Sunken); + QVBoxLayout *mainLayout = new QVBoxLayout(mMainWidget); QGridLayout *lockedLayout = new QGridLayout(); - QScrollArea *scroll = new QScrollArea(mMainWidget); - QWidget *unlockedWidget = new QWidget(scroll); - QVBoxLayout *overLayout = new QVBoxLayout(unlockedWidget); QGridLayout *unlockedLayout = new QGridLayout(); QVBoxLayout *tablesLayout = new QVBoxLayout(); mainLayout->addLayout(lockedLayout, QSizePolicy::Fixed); - mainLayout->addSpacing(5); // FIXME: arbitrary number mainLayout->addWidget(line, 1); - mainLayout->addWidget(scroll, QSizePolicy::Preferred); - overLayout->addLayout(unlockedLayout, QSizePolicy::Preferred); - overLayout->addStretch(1); - mainLayout->addSpacing(5); // FIXME: arbitrary number + mainLayout->addLayout(unlockedLayout, QSizePolicy::Preferred); + mainLayout->addWidget(line2, 1); mainLayout->addLayout(tablesLayout, QSizePolicy::Preferred); mainLayout->addStretch(1); @@ -443,11 +444,15 @@ void CSVWorld::EditWidget::remake(int row) NestedTable* table = new NestedTable(mDocument, mNestedModels.back(), this); // FIXME: does not work well when enum delegates are used - table->setVisible(false); - table->resizeColumnsToContents(); - table->setVisible(true); + //table->resizeColumnsToContents(); table->setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::CurrentChanged); + int rows = mNestedModels.back()->rowCount(mTable->index(row, i)); + int rowHeight = (rows == 0) ? table->horizontalHeader()->height() : table->rowHeight(0); + int tableMaxHeight = (5 * rowHeight) + + table->horizontalHeader()->height() + 2 * table->frameWidth(); + table->setMinimumHeight(tableMaxHeight); + QLabel* label = new QLabel (mTable->headerData (i, Qt::Horizontal, Qt::DisplayRole).toString(), mMainWidget); @@ -538,18 +543,8 @@ void CSVWorld::EditWidget::remake(int row) mWidgetMapper->setCurrentModelIndex(mTable->index(row, 0)); - if (unlocked != 0) - { + if (unlocked == 0) mainLayout->removeWidget(line); - scroll->setWidget(unlockedWidget); - scroll->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Minimum); - scroll->setWidgetResizable(true); - } - else - { - delete unlockedWidget; - delete scroll; - } this->setWidget(mMainWidget); this->setWidgetResizable(true); From 18162557b00c1c72436e0f4746cfc020a8efd3ba Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 19 Apr 2015 13:31:16 +1000 Subject: [PATCH 735/740] TopicInfos result script are now displayed in dialogue subviews. --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/columnbase.hpp | 4 +- apps/opencs/model/world/columns.cpp | 2 + apps/opencs/model/world/columns.hpp | 2 + apps/opencs/model/world/data.cpp | 16 ++- apps/opencs/model/world/data.hpp | 3 +- .../model/world/nestedcoladapterimp.cpp | 58 +++++++++ .../model/world/nestedcoladapterimp.hpp | 26 +++++ .../model/world/nestedinfocollection.cpp | 110 ++++++++++++++++++ .../model/world/nestedinfocollection.hpp | 50 ++++++++ apps/opencs/model/world/refidcollection.cpp | 2 +- 11 files changed, 266 insertions(+), 9 deletions(-) create mode 100644 apps/opencs/model/world/nestedinfocollection.cpp create mode 100644 apps/opencs/model/world/nestedinfocollection.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 9a5fc1933..9fb80324e 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -25,7 +25,7 @@ opencs_units (model/world opencs_units_noqt (model/world universalid record commands columnbase scriptcontext cell refidcollection refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope - pathgrid landtexture land nestedtablewrapper nestedcollection nestedcoladapterimp + pathgrid landtexture land nestedtablewrapper nestedcollection nestedcoladapterimp nestedinfocollection ) opencs_hdrs_noqt (model/world diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 4c3f9385a..0e954ecca 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -178,8 +178,8 @@ namespace CSMWorld template struct NestedParentColumn : public Column { - NestedParentColumn (int id) : Column (id, - ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue) + NestedParentColumn (int id, int flags = ColumnBase::Flag_Dialogue) : Column (id, + ColumnBase::Display_NestedHeader, flags) {} virtual QVariant get (const Record& record) const diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 1b5aefee9..1ea7da647 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -272,6 +272,8 @@ namespace CSMWorld { ColumnId_PowerList, "Powers" }, { ColumnId_SkillImpact, "Skills" }, + { ColumnId_InfoList, "Info List" }, + { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue3, "Use value 3" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 1760bff30..5a1577ddb 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -262,6 +262,8 @@ namespace CSMWorld ColumnId_PowerList = 238, ColumnId_SkillImpact = 239, // impact from magic effects + ColumnId_InfoList = 240, + // 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 0490cbe7a..873d8b78a 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -193,11 +193,11 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc index = mSpells.getColumns()-1; mSpells.addAdapter (std::make_pair(&mSpells.getColumn(index), new EffectsListAdapter ())); mSpells.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId)); // false means no edit + new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId)); mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact)); mSpells.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); // reuse attribute + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_EffectRange)); mSpells.getNestableColumn(index)->addColumn( @@ -235,6 +235,13 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mTopicInfos.addColumn (new PcRankColumn); mTopicInfos.addColumn (new SoundFileColumn); mTopicInfos.addColumn (new ResponseColumn); + // Result script + mTopicInfos.addColumn (new NestedParentColumn (Columns::ColumnId_InfoList, + ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_List)); + index = mTopicInfos.getColumns()-1; + mTopicInfos.addAdapter (std::make_pair(&mTopicInfos.getColumn(index), new InfoListAdapter ())); + mTopicInfos.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_ScriptText, ColumnBase::Display_ScriptLines)); mJournalInfos.addColumn (new StringIdColumn (true)); mJournalInfos.addColumn (new RecordStateColumn); @@ -271,7 +278,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact)); mEnchantments.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); // reuse attribute + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_EffectRange)); mEnchantments.getNestableColumn(index)->addColumn( @@ -423,7 +430,8 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc addModel (new IdTree (&mSpells, &mSpells), UniversalId::Type_Spell); addModel (new IdTable (&mTopics), UniversalId::Type_Topic); addModel (new IdTable (&mJournals), UniversalId::Type_Journal); - addModel (new IdTable (&mTopicInfos, IdTable::Feature_ReorderWithinTopic), UniversalId::Type_TopicInfo); + addModel (new IdTree (&mTopicInfos, &mTopicInfos, IdTable::Feature_ReorderWithinTopic), + UniversalId::Type_TopicInfo); addModel (new IdTable (&mJournalInfos, IdTable::Feature_ReorderWithinTopic), UniversalId::Type_JournalInfo); addModel (new IdTable (&mCells, IdTable::Feature_ViewId), UniversalId::Type_Cell); addModel (new IdTree (&mEnchantments, &mEnchantments), UniversalId::Type_Enchantment); diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 5ab69ac10..8689b98c0 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -42,6 +42,7 @@ #include "refidcollection.hpp" #include "refcollection.hpp" #include "infocollection.hpp" +#include "nestedinfocollection.hpp" #include "pathgrid.hpp" #ifndef Q_MOC_RUN #include "subcellcollection.hpp" @@ -85,7 +86,7 @@ namespace CSMWorld IdCollection mDebugProfiles; IdCollection mSoundGens; IdCollection mStartScripts; - InfoCollection mTopicInfos; + NestedInfoCollection mTopicInfos; InfoCollection mJournalInfos; IdCollection mCells; IdCollection mLandTextures; diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index bfb2fb578..d29155a47 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -5,6 +5,7 @@ #include "idcollection.hpp" #include "pathgrid.hpp" +#include "info.hpp" namespace CSMWorld { @@ -470,4 +471,61 @@ namespace CSMWorld { return static_cast(record.get().mSoundList.size()); } + + InfoListAdapter::InfoListAdapter () {} + + void InfoListAdapter::addRow(Record& record, int position) const + { + throw std::logic_error ("cannot add a row to a fixed table"); + } + + void InfoListAdapter::removeRow(Record& record, int rowToRemove) const + { + throw std::logic_error ("cannot add a row to a fixed table"); + } + + void InfoListAdapter::setTable(Record& record, + const NestedTableWrapperBase& nestedTable) const + { + throw std::logic_error ("table operation not supported"); + } + + NestedTableWrapperBase* InfoListAdapter::table(const Record& record) const + { + throw std::logic_error ("table operation not supported"); + } + + QVariant InfoListAdapter::getData(const Record& record, + int subRowIndex, int subColIndex) const + { + Info info = record.get(); + + if (subColIndex == 0) + return QString(info.mResultScript.c_str()); + else + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + } + + void InfoListAdapter::setData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const + { + Info info = record.get(); + + if (subColIndex == 0) + info.mResultScript = value.toString().toStdString(); + else + throw std::runtime_error("Trying to access non-existing column in the nested table!"); + + record.setModified (info); + } + + int InfoListAdapter::getColumnsCount(const Record& record) const + { + return 1; + } + + int InfoListAdapter::getRowsCount(const Record& record) const + { + return 1; // fixed at size 1 + } } diff --git a/apps/opencs/model/world/nestedcoladapterimp.hpp b/apps/opencs/model/world/nestedcoladapterimp.hpp index 4a7101cba..96dcd943d 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.hpp +++ b/apps/opencs/model/world/nestedcoladapterimp.hpp @@ -21,6 +21,7 @@ namespace ESM namespace CSMWorld { struct Pathgrid; + struct Info; struct PathgridPointsWrap : public NestedTableWrapperBase { @@ -386,6 +387,31 @@ namespace CSMWorld return static_cast(record.get().mEffects.mList.size()); } }; + + class InfoListAdapter : public NestedColumnAdapter + { + public: + InfoListAdapter (); + + virtual void addRow(Record& record, int position) const; + + virtual void removeRow(Record& record, int rowToRemove) const; + + virtual void setTable(Record& record, + const NestedTableWrapperBase& nestedTable) const; + + virtual NestedTableWrapperBase* table(const Record& record) const; + + virtual QVariant getData(const Record& record, + int subRowIndex, int subColIndex) const; + + virtual void setData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const; + + virtual int getColumnsCount(const Record& record) const; + + virtual int getRowsCount(const Record& record) const; + }; } #endif // CSM_WOLRD_NESTEDCOLADAPTERIMP_H diff --git a/apps/opencs/model/world/nestedinfocollection.cpp b/apps/opencs/model/world/nestedinfocollection.cpp new file mode 100644 index 000000000..4abaaf9c0 --- /dev/null +++ b/apps/opencs/model/world/nestedinfocollection.cpp @@ -0,0 +1,110 @@ +#include "nestedinfocollection.hpp" + +#include "nestedcoladapterimp.hpp" + +namespace CSMWorld +{ + NestedInfoCollection::NestedInfoCollection () + {} + + NestedInfoCollection::~NestedInfoCollection() + { + for (std::map* >::iterator + iter (mAdapters.begin()); iter!=mAdapters.end(); ++iter) + { + delete (*iter).second; + } + } + + void NestedInfoCollection::addAdapter(std::pair* > adapter) + { + mAdapters.insert(adapter); + } + + const NestedColumnAdapter& NestedInfoCollection::getAdapter(const ColumnBase &column) const + { + std::map* >::const_iterator iter = + mAdapters.find (&column); + + if (iter==mAdapters.end()) + throw std::logic_error("No such column in the nestedidadapter"); + + return *iter->second; + } + + void NestedInfoCollection::addNestedRow(int row, int column, int position) + { + Record record; + record.assign(Collection >::getRecord(row)); + + getAdapter(Collection >::getColumn(column)).addRow(record, position); + + Collection >::setRecord(row, record); + } + + void NestedInfoCollection::removeNestedRows(int row, int column, int subRow) + { + Record record; + record.assign(Collection >::getRecord(row)); + + getAdapter(Collection >::getColumn(column)).removeRow(record, subRow); + + Collection >::setRecord(row, record); + } + + QVariant NestedInfoCollection::getNestedData (int row, + int column, int subRow, int subColumn) const + { + return getAdapter(Collection >::getColumn(column)).getData( + Collection >::getRecord(row), subRow, subColumn); + } + + void NestedInfoCollection::setNestedData(int row, + int column, const QVariant& data, int subRow, int subColumn) + { + Record record; + record.assign(Collection >::getRecord(row)); + + getAdapter(Collection >::getColumn(column)).setData( + record, data, subRow, subColumn); + + Collection >::setRecord(row, record); + } + + CSMWorld::NestedTableWrapperBase* NestedInfoCollection::nestedTable(int row, + int column) const + { + return getAdapter(Collection >::getColumn(column)).table( + Collection >::getRecord(row)); + } + + void NestedInfoCollection::setNestedTable(int row, + int column, const CSMWorld::NestedTableWrapperBase& nestedTable) + { + Record record; + record.assign(Collection >::getRecord(row)); + + getAdapter(Collection >::getColumn(column)).setTable( + record, nestedTable); + + Collection >::setRecord(row, record); + } + + int NestedInfoCollection::getNestedRowsCount(int row, int column) const + { + return getAdapter(Collection >::getColumn(column)).getRowsCount( + Collection >::getRecord(row)); + } + + int NestedInfoCollection::getNestedColumnsCount(int row, int column) const + { + return getAdapter(Collection >::getColumn(column)).getColumnsCount( + Collection >::getRecord(row)); + } + + CSMWorld::NestableColumn *NestedInfoCollection::getNestableColumn(int column) + { + return Collection >::getNestableColumn(column); + } +} diff --git a/apps/opencs/model/world/nestedinfocollection.hpp b/apps/opencs/model/world/nestedinfocollection.hpp new file mode 100644 index 000000000..03c0c2349 --- /dev/null +++ b/apps/opencs/model/world/nestedinfocollection.hpp @@ -0,0 +1,50 @@ +#ifndef CSM_WOLRD_NESTEDINFOCOLLECTION_H +#define CSM_WOLRD_NESTEDINFOCOLLECTION_H + +#include + +#include "infocollection.hpp" +#include "nestedcollection.hpp" + +namespace CSMWorld +{ + struct NestedTableWrapperBase; + + template + class NestedColumnAdapter; + + class NestedInfoCollection : public InfoCollection, public NestedCollection + { + std::map* > mAdapters; + + const NestedColumnAdapter& getAdapter(const ColumnBase &column) const; + + public: + + NestedInfoCollection (); + ~NestedInfoCollection(); + + virtual void addNestedRow(int row, int column, int position); + + virtual void removeNestedRows(int row, int column, int subRow); + + virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const; + + virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn); + + virtual NestedTableWrapperBase* nestedTable(int row, int column) const; + + virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable); + + virtual int getNestedRowsCount(int row, int column) const; + + virtual int getNestedColumnsCount(int row, int column) const; + + // this method is inherited from NestedCollection, not from Collection > + virtual NestableColumn *getNestableColumn(int column); + + void addAdapter(std::pair* > adapter); + }; +} + +#endif // CSM_WOLRD_NESTEDINFOCOLLECTION_H diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index caf1041c6..4a8f398cd 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -85,7 +85,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact)); mColumns.back().addColumn( - new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); // reuse attribute + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_EffectRange)); mColumns.back().addColumn( From a836446d223462378767ed39730149ceb3f33624 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 19 Apr 2015 21:07:45 +1000 Subject: [PATCH 736/740] Fix assert() triggering due to bad index being passed. --- apps/opencs/view/world/dialoguesubview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 2e800b56f..f067c3225 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -447,7 +447,7 @@ void CSVWorld::EditWidget::remake(int row) //table->resizeColumnsToContents(); table->setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::CurrentChanged); - int rows = mNestedModels.back()->rowCount(mTable->index(row, i)); + int rows = mTable->rowCount(mTable->index(row, i)); int rowHeight = (rows == 0) ? table->horizontalHeader()->height() : table->rowHeight(0); int tableMaxHeight = (5 * rowHeight) + table->horizontalHeader()->height() + 2 * table->frameWidth(); From f326b14604048b26722966add5d49bf02aa9db4c Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 21 Apr 2015 10:25:19 +1000 Subject: [PATCH 737/740] Allow Qt to cleanup its signals. --- apps/opencs/model/doc/documentmanager.cpp | 2 +- apps/opencs/view/doc/view.cpp | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/doc/documentmanager.cpp b/apps/opencs/model/doc/documentmanager.cpp index 7a1a86153..2d444f245 100644 --- a/apps/opencs/model/doc/documentmanager.cpp +++ b/apps/opencs/model/doc/documentmanager.cpp @@ -69,7 +69,7 @@ void CSMDoc::DocumentManager::removeDocument (CSMDoc::Document *document) throw std::runtime_error ("removing invalid document"); mDocuments.erase (iter); - delete document; + document->deleteLater(); if (mDocuments.empty()) emit lastDocumentDeleted(); diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index aaf8f2d6a..e430bfa5e 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -32,10 +32,6 @@ void CSVDoc::View::closeEvent (QCloseEvent *event) event->ignore(); else { - // delete the subviews first - for (QList::iterator iter = mSubViews.begin(); iter != mSubViews.end(); ++iter) - delete *iter; - // closeRequest() returns true if last document mViewManager.removeDocAndView(mDocument); } @@ -98,7 +94,7 @@ void CSVDoc::View::setupEditMenu() QAction *search = new QAction (tr ("Search"), this); connect (search, SIGNAL (triggered()), this, SLOT (addSearchSubView())); - edit->addAction (search); + edit->addAction (search); } void CSVDoc::View::setupViewMenu() From f7c7aeecb3c188db6b5274acef45ac717976d966 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 21 Apr 2015 14:44:51 +0200 Subject: [PATCH 738/740] fixed missing state update when starting a global search --- apps/opencs/model/doc/document.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index cb3b4ba18..31d0aaccd 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2382,7 +2382,8 @@ CSMWorld::UniversalId CSMDoc::Document::newSearch() void CSMDoc::Document::runSearch (const CSMWorld::UniversalId& searchId, const CSMTools::Search& search) { - return mTools.runSearch (searchId, search); + mTools.runSearch (searchId, search); + emit stateChanged (getState(), this); } void CSMDoc::Document::abortOperation (int type) From 82bc666e002af107a32dbc1f06bce8b4de9cf1b7 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 22 Apr 2015 09:25:55 +1000 Subject: [PATCH 739/740] Make AI package items to be editable when a new row is added. --- apps/opencs/model/world/refidadapterimp.hpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index d3d52d2e1..41d8c65d5 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -1363,7 +1363,13 @@ namespace CSMWorld std::vector& list = actor.mAiPackage.mList; ESM::AIPackage newRow; - newRow.mType = ESM::AI_CNDT; + newRow.mType = ESM::AI_Wander; + newRow.mWander.mDistance = 0; + newRow.mWander.mDuration = 0; + newRow.mWander.mTimeOfDay = 0; + for (int i = 0; i < 8; ++i) + newRow.mWander.mIdle[i] = 0; + newRow.mWander.mShouldRepeat = 0; newRow.mCellName = ""; if (position >= (int)list.size()) From 6fcf4ea9e3fdf445ba282a029f63b4d84ac1d8c4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 23 Apr 2015 14:24:43 +0200 Subject: [PATCH 740/740] In ModifyCommand replace proxy model with the source model (Fixes #2498) --- apps/opencs/model/world/commands.cpp | 21 +++++++++++++++------ apps/opencs/model/world/commands.hpp | 2 +- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index d12c5d228..ce82e07bf 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -1,28 +1,37 @@ #include "commands.hpp" +#include + #include +#include #include "idtable.hpp" #include "idtree.hpp" -#include #include "nestedtablewrapper.hpp" CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelIndex& index, const QVariant& new_, QUndoCommand* parent) -: QUndoCommand (parent), mModel (model), mIndex (index), mNew (new_) +: QUndoCommand (parent), mModel (&model), mIndex (index), mNew (new_) { - setText ("Modify " + mModel.headerData (mIndex.column(), Qt::Horizontal, Qt::DisplayRole).toString()); + if (QAbstractProxyModel *proxy = dynamic_cast (&model)) + { + // Replace proxy with actual model + mIndex = proxy->mapToSource (index); + mModel = proxy->sourceModel(); + } + + setText ("Modify " + mModel->headerData (mIndex.column(), Qt::Horizontal, Qt::DisplayRole).toString()); } void CSMWorld::ModifyCommand::redo() { - mOld = mModel.data (mIndex, Qt::EditRole); - mModel.setData (mIndex, mNew); + mOld = mModel->data (mIndex, Qt::EditRole); + mModel->setData (mIndex, mNew); } void CSMWorld::ModifyCommand::undo() { - mModel.setData (mIndex, mOld); + mModel->setData (mIndex, mOld); } diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index a70b36178..2bd47ae91 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -26,7 +26,7 @@ namespace CSMWorld class ModifyCommand : public QUndoCommand { - QAbstractItemModel& mModel; + QAbstractItemModel *mModel; QModelIndex mIndex; QVariant mNew; QVariant mOld;