From 513c3a47cb8d54b6dea46bdb5816bde1f5739aa8 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 13 Apr 2015 21:08:23 +1000 Subject: [PATCH] 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,