diff --git a/apps/opencs/model/doc/saving.cpp b/apps/opencs/model/doc/saving.cpp index 45b53f4fe8..95631eea9c 100644 --- a/apps/opencs/model/doc/saving.cpp +++ b/apps/opencs/model/doc/saving.cpp @@ -59,6 +59,12 @@ CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& proje appendStage (new WriteCollectionStage > (mDocument.getData().getSpells(), mState)); + appendStage (new WriteCollectionStage > + (mDocument.getData().getEnchantments(), mState)); + + appendStage (new WriteCollectionStage > + (mDocument.getData().getBodyParts(), mState)); + appendStage (new WriteDialogueCollectionStage (mDocument, mState, false)); appendStage (new WriteDialogueCollectionStage (mDocument, mState, true)); diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index fe310d0aa4..39c700fa14 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -89,6 +89,9 @@ namespace CSMWorld Display_RefRecordType, Display_DialogueType, Display_QuestStatusType, + Display_EnchantmentType, + Display_BodyPartType, + Display_MeshType, Display_Gender }; diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 6976b454d9..72f2099fae 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -463,14 +463,21 @@ namespace CSMWorld struct FlagColumn : public Column { int mMask; + bool mInverted; - FlagColumn (int columnId, int mask) - : Column (columnId, ColumnBase::Display_Boolean), mMask (mask) + FlagColumn (int columnId, int mask, bool inverted = false) + : Column (columnId, ColumnBase::Display_Boolean), mMask (mask), + mInverted (inverted) {} virtual QVariant get (const Record& record) const { - return (record.get().mData.mFlags & mMask)!=0; + bool flag = (record.get().mData.mFlags & mMask)!=0; + + if (mInverted) + flag = !flag; + + return flag; } virtual void set (Record& record, const QVariant& data) @@ -479,7 +486,7 @@ namespace CSMWorld int flags = record2.mData.mFlags & ~mMask; - if (data.toInt()) + if ((data.toInt()!=0)!=mInverted) flags |= mMask; record2.mData.mFlags = flags; @@ -1682,6 +1689,187 @@ namespace CSMWorld return true; } }; + + template + struct EnchantmentTypeColumn : public Column + { + EnchantmentTypeColumn() + : Column (Columns::ColumnId_EnchantmentType, ColumnBase::Display_EnchantmentType) + {} + + virtual QVariant get (const Record& record) const + { + return static_cast (record.get().mData.mType); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mData.mType = data.toInt(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; + + template + struct ChargesColumn2 : public Column + { + ChargesColumn2() : Column (Columns::ColumnId_Charges, ColumnBase::Display_Integer) {} + + virtual QVariant get (const Record& record) const + { + return record.get().mData.mCharge; + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + record2.mData.mCharge = data.toInt(); + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; + + template + struct AutoCalcColumn : public Column + { + AutoCalcColumn() : Column (Columns::ColumnId_AutoCalc, ColumnBase::Display_Boolean) + {} + + virtual QVariant get (const Record& record) const + { + return record.get().mData.mAutocalc!=0; + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mData.mAutocalc = data.toInt(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; + + template + struct ModelColumn : public Column + { + ModelColumn() : Column (Columns::ColumnId_Model, ColumnBase::Display_String) {} + + virtual QVariant get (const Record& record) const + { + return QString::fromUtf8 (record.get().mModel.c_str()); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mModel = data.toString().toUtf8().constData(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; + + template + struct VampireColumn : public Column + { + VampireColumn() : Column (Columns::ColumnId_Vampire, ColumnBase::Display_Boolean) + {} + + virtual QVariant get (const Record& record) const + { + return record.get().mData.mVampire!=0; + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mData.mVampire = data.toInt(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; + + template + struct BodyPartTypeColumn : public Column + { + BodyPartTypeColumn() + : Column (Columns::ColumnId_BodyPartType, ColumnBase::Display_BodyPartType) + {} + + virtual QVariant get (const Record& record) const + { + return static_cast (record.get().mData.mPart); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mData.mPart = data.toInt(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; + + template + struct MeshTypeColumn : public Column + { + MeshTypeColumn() + : Column (Columns::ColumnId_MeshType, ColumnBase::Display_MeshType) + {} + + virtual QVariant get (const Record& record) const + { + return static_cast (record.get().mData.mType); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mData.mType = data.toInt(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 7a2e93edfa..05df0b7358 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -177,6 +177,10 @@ namespace CSMWorld { ColumnId_CombatState, "Combat" }, { ColumnId_MagicState, "Magic" }, { ColumnId_StealthState, "Stealth" }, + { ColumnId_EnchantmentType, "Enchantment Type" }, + { ColumnId_Vampire, "Vampire" }, + { ColumnId_BodyPartType, "Bodypart Type" }, + { ColumnId_MeshType, "Mesh Type" }, { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, @@ -302,6 +306,22 @@ namespace "Male", "Female", 0 }; + static const char *sEnchantmentTypes[] = + { + "Cast Once", "When Strikes", "When Used", "Constant Effect", 0 + }; + + static const char *sBodyPartTypes[] = + { + "Head", "Hair", "Neck", "Chest", "Groin", "Hand", "Wrist", "Forearm", "Upper Arm", + "Foot", "Ankle", "Knee", "Upper Leg", "Clavicle", "Tail", 0 + }; + + static const char *sMeshTypes[] = + { + "Skin", "Clothing", "Armour", 0 + }; + const char **getEnumNames (CSMWorld::Columns::ColumnId column) { switch (column) @@ -319,6 +339,9 @@ namespace case CSMWorld::Columns::ColumnId_DialogueType: return sDialogueTypeEnums; case CSMWorld::Columns::ColumnId_QuestStatusType: return sQuestStatusTypes; case CSMWorld::Columns::ColumnId_Gender: return sGenderEnums; + case CSMWorld::Columns::ColumnId_EnchantmentType: return sEnchantmentTypes; + case CSMWorld::Columns::ColumnId_BodyPartType: return sBodyPartTypes; + case CSMWorld::Columns::ColumnId_MeshType: return sMeshTypes; default: return 0; } diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index db31113e1d..326a025965 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -170,6 +170,10 @@ namespace CSMWorld ColumnId_CombatState = 157, ColumnId_MagicState = 158, ColumnId_StealthState = 159, + ColumnId_EnchantmentType = 160, + ColumnId_Vampire = 161, + ColumnId_BodyPartType = 162, + ColumnId_MeshType = 163, // 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 0319d71acc..d07e8784e3 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -198,6 +198,25 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding) mCells.addColumn (new FlagColumn (Columns::ColumnId_InteriorSky, ESM::Cell::QuasiEx)); mCells.addColumn (new RegionColumn); + mEnchantments.addColumn (new StringIdColumn); + mEnchantments.addColumn (new RecordStateColumn); + mEnchantments.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Enchantment)); + mEnchantments.addColumn (new EnchantmentTypeColumn); + mEnchantments.addColumn (new CostColumn); + mEnchantments.addColumn (new ChargesColumn2); + mEnchantments.addColumn (new AutoCalcColumn); + + mBodyParts.addColumn (new StringIdColumn); + mBodyParts.addColumn (new RecordStateColumn); + mBodyParts.addColumn (new FixedRecordTypeColumn (UniversalId::Type_BodyPart)); + mBodyParts.addColumn (new BodyPartTypeColumn); + mBodyParts.addColumn (new VampireColumn); + mBodyParts.addColumn (new FlagColumn (Columns::ColumnId_Female, ESM::BodyPart::BPF_Female)); + mBodyParts.addColumn (new FlagColumn (Columns::ColumnId_Playable, ESM::BodyPart::BPF_NotPlayable, true)); + mBodyParts.addColumn (new MeshTypeColumn); + mBodyParts.addColumn (new ModelColumn); + mBodyParts.addColumn (new RaceColumn); + mRefs.addColumn (new StringIdColumn (true)); mRefs.addColumn (new RecordStateColumn); mRefs.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Reference)); @@ -252,6 +271,8 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding) 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 IdTable (&mBodyParts), UniversalId::Type_BodyPart); addModel (new IdTable (&mReferenceables, IdTable::Feature_Preview), UniversalId::Type_Referenceable); addModel (new IdTable (&mRefs, IdTable::Feature_ViewCell | IdTable::Feature_Preview), UniversalId::Type_Reference); @@ -457,6 +478,26 @@ CSMWorld::IdCollection& CSMWorld::Data::getFilters() return mFilters; } +const CSMWorld::IdCollection& CSMWorld::Data::getEnchantments() const +{ + return mEnchantments; +} + +CSMWorld::IdCollection& CSMWorld::Data::getEnchantments() +{ + return mEnchantments; +} + +const CSMWorld::IdCollection& CSMWorld::Data::getBodyParts() const +{ + return mBodyParts; +} + +CSMWorld::IdCollection& CSMWorld::Data::getBodyParts() +{ + return mBodyParts; +} + QAbstractItemModel *CSMWorld::Data::getTableModel (const CSMWorld::UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); @@ -534,6 +575,8 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Stage::Messages& messages) case ESM::REC_REGN: mRegions.load (*mReader, mBase); break; case ESM::REC_BSGN: mBirthsigns.load (*mReader, mBase); break; case ESM::REC_SPEL: mSpells.load (*mReader, mBase); break; + case ESM::REC_ENCH: mEnchantments.load (*mReader, mBase); break; + case ESM::REC_BODY: mBodyParts.load (*mReader, mBase); break; case ESM::REC_CELL: { @@ -668,6 +711,8 @@ bool CSMWorld::Data::hasId (const std::string& id) const getTopics().searchId (id)!=-1 || getJournals().searchId (id)!=-1 || getCells().searchId (id)!=-1 || + getEnchantments().searchId (id)!=-1 || + getBodyParts().searchId (id)!=-1 || getReferenceables().searchId (id)!=-1; } @@ -686,6 +731,8 @@ int CSMWorld::Data::count (RecordBase::State state) const count (state, mBirthsigns) + count (state, mSpells) + count (state, mCells) + + count (state, mEnchantments) + + count (state, mBodyParts) + count (state, mReferenceables); } @@ -726,6 +773,8 @@ std::vector CSMWorld::Data::getIds (bool listDeleted) const appendIds (ids, mTopics, listDeleted); appendIds (ids, mJournals, listDeleted); appendIds (ids, mCells, listDeleted); + appendIds (ids, mEnchantments, listDeleted); + appendIds (ids, mBodyParts, listDeleted); appendIds (ids, mReferenceables, listDeleted); std::sort (ids.begin(), ids.end()); diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index edca9fdbcf..9bdb449e0a 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include @@ -63,6 +65,8 @@ namespace CSMWorld IdCollection mSpells; IdCollection mTopics; IdCollection mJournals; + IdCollection mEnchantments; + IdCollection mBodyParts; InfoCollection mTopicInfos; InfoCollection mJournalInfos; IdCollection mCells; @@ -174,6 +178,14 @@ namespace CSMWorld IdCollection& getFilters(); + const IdCollection& getEnchantments() const; + + IdCollection& getEnchantments(); + + const IdCollection& getBodyParts() const; + + IdCollection& getBodyParts(); + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 88e649ace4..3a5f3f0439 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -35,6 +35,8 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_TopicInfos, "Topic Infos", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_JournalInfos, "Journal Infos", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Cells, "Cells", 0 }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Enchantments, "Enchantments", 0 }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_BodyParts, "Body Parts", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Referenceables, "Referenceables", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_References, @@ -92,8 +94,9 @@ namespace { CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_Reference, "Reference", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Filter, "Filter", ":./filter.png" }, { CSMWorld::UniversalId::Class_Collection, CSMWorld::UniversalId::Type_Scene, "Scene", 0 }, - { CSMWorld::UniversalId::Class_Collection, CSMWorld::UniversalId::Type_Preview, "Preview", 0 }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Enchantment, "Enchantment", 0 }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_BodyPart, "Body Part", 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 3bef71c75f..c7514336f1 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -100,10 +100,14 @@ namespace CSMWorld Type_JournalInfo, Type_Scene, Type_Preview, - Type_LoadErrorLog + Type_LoadErrorLog, + Type_Enchantments, + Type_Enchantment, + Type_BodyParts, + Type_BodyPart }; - enum { NumberOfTypes = Type_LoadErrorLog+1 }; + enum { NumberOfTypes = Type_BodyPart+1 }; private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index e71b8435ab..6a807f086a 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -146,6 +146,10 @@ void CSVDoc::View::setupMechanicsMenu() QAction *spells = new QAction (tr ("Spells"), this); connect (spells, SIGNAL (triggered()), this, SLOT (addSpellsSubView())); mechanics->addAction (spells); + + QAction *enchantments = new QAction (tr ("Enchantments"), this); + connect (enchantments, SIGNAL (triggered()), this, SLOT (addEnchantmentsSubView())); + mechanics->addAction (enchantments); } void CSVDoc::View::setupCharacterMenu() @@ -187,6 +191,10 @@ void CSVDoc::View::setupCharacterMenu() QAction *journalInfos = new QAction (tr ("Journal Infos"), this); connect (journalInfos, SIGNAL (triggered()), this, SLOT (addJournalInfosSubView())); characters->addAction (journalInfos); + + QAction *bodyParts = new QAction (tr ("Body Parts"), this); + connect (bodyParts, SIGNAL (triggered()), this, SLOT (addBodyPartsSubView())); + characters->addAction (bodyParts); } void CSVDoc::View::setupAssetsMenu() @@ -469,6 +477,16 @@ void CSVDoc::View::addJournalInfosSubView() addSubView (CSMWorld::UniversalId::Type_JournalInfos); } +void CSVDoc::View::addEnchantmentsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Enchantments); +} + +void CSVDoc::View::addBodyPartsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_BodyParts); +} + 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 686c001dc1..a227997c21 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -178,6 +178,10 @@ namespace CSVDoc void addJournalInfosSubView(); + void addEnchantmentsSubView(); + + void addBodyPartsSubView(); + void toggleShowStatusBar (bool show); void loadErrorLog(); diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index f4d6fc6cb5..6f4217aa8c 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -78,6 +78,9 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) { CSMWorld::ColumnBase::Display_WeaponType, CSMWorld::Columns::ColumnId_WeaponType, false }, { CSMWorld::ColumnBase::Display_DialogueType, CSMWorld::Columns::ColumnId_DialogueType, false }, { CSMWorld::ColumnBase::Display_QuestStatusType, CSMWorld::Columns::ColumnId_QuestStatusType, false }, + { CSMWorld::ColumnBase::Display_EnchantmentType, CSMWorld::Columns::ColumnId_EnchantmentType, false }, + { CSMWorld::ColumnBase::Display_BodyPartType, CSMWorld::Columns::ColumnId_BodyPartType, false }, + { CSMWorld::ColumnBase::Display_MeshType, CSMWorld::Columns::ColumnId_MeshType, false }, { CSMWorld::ColumnBase::Display_Gender, CSMWorld::Columns::ColumnId_Gender, true } }; diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 022d5d02e4..8c666c1fed 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -39,6 +39,8 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_Regions, CSMWorld::UniversalId::Type_Birthsigns, CSMWorld::UniversalId::Type_Spells, + CSMWorld::UniversalId::Type_Enchantments, + CSMWorld::UniversalId::Type_BodyParts, CSMWorld::UniversalId::Type_None // end marker }; @@ -92,6 +94,8 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_Filter, CSMWorld::UniversalId::Type_Sound, CSMWorld::UniversalId::Type_Faction, + CSMWorld::UniversalId::Type_Enchantment, + CSMWorld::UniversalId::Type_BodyPart, CSMWorld::UniversalId::Type_None // end marker }; diff --git a/components/esm/loadbody.cpp b/components/esm/loadbody.cpp index c45f8d252d..9a1164d041 100644 --- a/components/esm/loadbody.cpp +++ b/components/esm/loadbody.cpp @@ -22,4 +22,14 @@ void BodyPart::save(ESMWriter &esm) const esm.writeHNT("BYDT", mData, 4); } + void BodyPart::blank() + { + mData.mPart = 0; + mData.mVampire = 0; + mData.mFlags = 0; + mData.mType = 0; + + mModel.clear(); + mRace.clear(); + } } diff --git a/components/esm/loadbody.hpp b/components/esm/loadbody.hpp index 9623caa31e..286e3f96e3 100644 --- a/components/esm/loadbody.hpp +++ b/components/esm/loadbody.hpp @@ -60,6 +60,9 @@ struct BodyPart void load(ESMReader &esm); void save(ESMWriter &esm) const; + + void blank(); + ///< Set record to default state (does not touch the ID). }; } #endif diff --git a/components/esm/loadench.cpp b/components/esm/loadench.cpp index a1e885f23b..2438038337 100644 --- a/components/esm/loadench.cpp +++ b/components/esm/loadench.cpp @@ -20,4 +20,13 @@ void Enchantment::save(ESMWriter &esm) const mEffects.save(esm); } + void Enchantment::blank() + { + mData.mType = 0; + mData.mCost = 0; + mData.mCharge = 0; + mData.mAutocalc = 0; + + mEffects.mList.clear(); + } } diff --git a/components/esm/loadench.hpp b/components/esm/loadench.hpp index f6ba8c6ab3..3b7746812a 100644 --- a/components/esm/loadench.hpp +++ b/components/esm/loadench.hpp @@ -42,6 +42,9 @@ struct Enchantment void load(ESMReader &esm); void save(ESMWriter &esm) const; + + void blank(); + ///< Set record to default state (does not touch the ID). }; } #endif