diff --git a/CHANGELOG.md b/CHANGELOG.md index a438c1d889..326bafa6f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,8 +17,8 @@ Bug #6129: Player avatar not displayed correctly for large window sizes when GUI scaling active Bug #6131: Item selection in the avatar window not working correctly for large window sizes Bug #6133: Cannot reliably sneak or steal in the sight of the NPCs siding with player - Editor: For consistency with TES CS make DELE records 4 bytes long - + Feature #6017: Separate persistent and temporary cell references when saving + 0.47.0 ------ diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index 44698cd2e3..8c17a3b8c1 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -253,10 +253,71 @@ int CSMDoc::WriteCellCollectionStage::setup() return mDocument.getData().getCells().getSize(); } +void CSMDoc::WriteCellCollectionStage::writeReferences (const std::deque& references, bool interior, unsigned int& newRefNum) +{ + ESM::ESMWriter& writer = mState.getWriter(); + + for (std::deque::const_iterator iter (references.begin()); + iter!=references.end(); ++iter) + { + const CSMWorld::Record& ref = + mDocument.getData().getReferences().getRecord (*iter); + + if (ref.isModified() || ref.mState == CSMWorld::RecordBase::State_Deleted) + { + CSMWorld::CellRef refRecord = ref.get(); + + // Check for uninitialized content file + if (!refRecord.mRefNum.hasContentFile()) + refRecord.mRefNum.mContentFile = 0; + + // recalculate the ref's cell location + std::ostringstream stream; + if (!interior) + { + std::pair index = refRecord.getCellIndex(); + stream << "#" << index.first << " " << index.second; + } + + if (refRecord.mNew || refRecord.mRefNum.mIndex == 0 || + (!interior && ref.mState==CSMWorld::RecordBase::State_ModifiedOnly && + refRecord.mCell!=stream.str())) + { + refRecord.mRefNum.mIndex = newRefNum++; + } + else if ((refRecord.mOriginalCell.empty() ? refRecord.mCell : refRecord.mOriginalCell) + != stream.str() && !interior) + { + // An empty mOriginalCell is meant to indicate that it is the same as + // the current cell. It is possible that a moved ref is moved again. + + ESM::MovedCellRef moved; + moved.mRefNum = refRecord.mRefNum; + + // Need to fill mTarget with the ref's new position. + std::istringstream istream (stream.str().c_str()); + + char ignore; + istream >> ignore >> moved.mTarget[0] >> moved.mTarget[1]; + + refRecord.mRefNum.save (writer, false, "MVRF"); + writer.writeHNT ("CNDT", moved.mTarget); + } + + refRecord.save (writer, false, false, ref.mState == CSMWorld::RecordBase::State_Deleted); + } + } +} + void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages) { ESM::ESMWriter& writer = mState.getWriter(); const CSMWorld::Record& cell = mDocument.getData().getCells().getRecord (stage); + const CSMWorld::RefIdCollection& referenceables = mDocument.getData().getReferenceables(); + const CSMWorld::RefIdData& refIdData = referenceables.getDataSet(); + + std::deque tempRefs; + std::deque persistentRefs; std::map >::const_iterator references = mState.getSubRecords().find (Misc::StringUtils::lowerCase (cell.get().mId)); @@ -281,6 +342,18 @@ void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages) CSMWorld::CellRef refRecord = ref.get(); + CSMWorld::RefIdData::LocalIndex localIndex = refIdData.searchId(refRecord.mRefID); + unsigned int recordFlags = refIdData.getRecordFlags(refRecord.mRefID); + bool isPersistent = ((recordFlags & ESM::FLAG_Persistent) != 0) + || refRecord.mTeleport + || localIndex.second == CSMWorld::UniversalId::Type_Creature + || localIndex.second == CSMWorld::UniversalId::Type_Npc; + + if (isPersistent) + persistentRefs.push_back(*iter); + else + tempRefs.push_back(*iter); + if (refRecord.mNew || (!interior && ref.mState==CSMWorld::RecordBase::State_ModifiedOnly && /// \todo consider worldspace @@ -289,7 +362,6 @@ void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages) if (refRecord.mRefNum.mIndex >= newRefNum) newRefNum = refRecord.mRefNum.mIndex + 1; - } } @@ -312,56 +384,9 @@ void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages) // write references if (references!=mState.getSubRecords().end()) { - for (std::deque::const_iterator iter (references->second.begin()); - iter!=references->second.end(); ++iter) - { - const CSMWorld::Record& ref = - mDocument.getData().getReferences().getRecord (*iter); - - if (ref.isModified() || ref.mState == CSMWorld::RecordBase::State_Deleted) - { - CSMWorld::CellRef refRecord = ref.get(); - - // Check for uninitialized content file - if (!refRecord.mRefNum.hasContentFile()) - refRecord.mRefNum.mContentFile = 0; - - // recalculate the ref's cell location - std::ostringstream stream; - if (!interior) - { - std::pair index = refRecord.getCellIndex(); - stream << "#" << index.first << " " << index.second; - } - - if (refRecord.mNew || refRecord.mRefNum.mIndex == 0 || - (!interior && ref.mState==CSMWorld::RecordBase::State_ModifiedOnly && - refRecord.mCell!=stream.str())) - { - refRecord.mRefNum.mIndex = newRefNum++; - } - else if ((refRecord.mOriginalCell.empty() ? refRecord.mCell : refRecord.mOriginalCell) - != stream.str() && !interior) - { - // An empty mOriginalCell is meant to indicate that it is the same as - // the current cell. It is possible that a moved ref is moved again. - - ESM::MovedCellRef moved; - moved.mRefNum = refRecord.mRefNum; - - // Need to fill mTarget with the ref's new position. - std::istringstream istream (stream.str().c_str()); - - char ignore; - istream >> ignore >> moved.mTarget[0] >> moved.mTarget[1]; - - refRecord.mRefNum.save (writer, false, "MVRF"); - writer.writeHNT ("CNDT", moved.mTarget); - } - - refRecord.save (writer, false, false, ref.mState == CSMWorld::RecordBase::State_Deleted); - } - } + writeReferences(persistentRefs, interior, newRefNum); + cellRecord.saveTempMarker(writer, int(references->second.size()) - persistentRefs.size()); + writeReferences(tempRefs, interior, newRefNum); } writer.endRecord (cellRecord.sRecordId); diff --git a/apps/opencs/model/doc/savingstages.hpp b/apps/opencs/model/doc/savingstages.hpp index d3a0cc9b31..d59a1efe5e 100644 --- a/apps/opencs/model/doc/savingstages.hpp +++ b/apps/opencs/model/doc/savingstages.hpp @@ -171,6 +171,8 @@ namespace CSMDoc Document& mDocument; SavingState& mState; + void writeReferences (const std::deque& references, bool interior, unsigned int& newRefNum); + public: WriteCellCollectionStage (Document& document, SavingState& state); diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index eaea66c2f9..cf04d96753 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -294,7 +294,6 @@ namespace CSMWorld { ColumnId_NpcReputation, "Reputation" }, { ColumnId_NpcRank, "NPC Rank" }, { ColumnId_Gold, "Gold" }, - { ColumnId_NpcPersistence, "Persistent" }, { ColumnId_RaceAttributes, "Race Attributes" }, { ColumnId_Male, "Male" }, @@ -371,6 +370,8 @@ namespace CSMWorld { ColumnId_Skill6, "Skill 6" }, { ColumnId_Skill7, "Skill 7" }, + { ColumnId_Persistent, "Persistent" }, + { -1, 0 } // end marker }; } diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index c85eaac5f1..16482d4898 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -280,7 +280,7 @@ namespace CSMWorld ColumnId_NpcReputation = 258, ColumnId_NpcRank = 259, ColumnId_Gold = 260, - ColumnId_NpcPersistence = 261, + // unused ColumnId_RaceAttributes = 262, ColumnId_Male = 263, @@ -343,6 +343,8 @@ namespace CSMWorld ColumnId_FactionAttrib1 = 311, ColumnId_FactionAttrib2 = 312, + ColumnId_Persistent = 313, + // 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.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 644092f164..0dfc9945f7 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -1108,7 +1108,6 @@ QVariant CSMWorld::NpcMiscRefIdAdapter::getNestedData (const RefIdColumn *column case 5: return static_cast(record.get().mNpdt.mReputation); case 6: return static_cast(record.get().mNpdt.mRank); case 7: return record.get().mNpdt.mGold; - case 8: return record.get().mPersistent == true; default: return QVariant(); // throw an exception here? } else @@ -1122,7 +1121,6 @@ QVariant CSMWorld::NpcMiscRefIdAdapter::getNestedData (const RefIdColumn *column case 5: return static_cast(record.get().mNpdt.mReputation); case 6: return static_cast(record.get().mNpdt.mRank); case 7: return record.get().mNpdt.mGold; - case 8: return record.get().mPersistent == true; default: return QVariant(); // throw an exception here? } } @@ -1147,7 +1145,6 @@ void CSMWorld::NpcMiscRefIdAdapter::setNestedData (const RefIdColumn *column, case 5: npc.mNpdt.mReputation = static_cast(value.toInt()); break; case 6: npc.mNpdt.mRank = static_cast(value.toInt()); break; case 7: npc.mNpdt.mGold = value.toInt(); break; - case 8: npc.mPersistent = value.toBool(); break; default: return; // throw an exception here? } else @@ -1161,7 +1158,6 @@ void CSMWorld::NpcMiscRefIdAdapter::setNestedData (const RefIdColumn *column, case 5: npc.mNpdt.mReputation = static_cast(value.toInt()); break; case 6: npc.mNpdt.mRank = static_cast(value.toInt()); break; case 7: npc.mNpdt.mGold = value.toInt(); break; - case 8: npc.mPersistent = value.toBool(); break; default: return; // throw an exception here? } @@ -1170,7 +1166,7 @@ void CSMWorld::NpcMiscRefIdAdapter::setNestedData (const RefIdColumn *column, int CSMWorld::NpcMiscRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const { - return 9; // Level, Health, Mana, Fatigue, Disposition, Reputation, Rank, Gold, Persist + return 8; // Level, Health, Mana, Fatigue, Disposition, Reputation, Rank, Gold } int CSMWorld::NpcMiscRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 3d784f1b2b..1d1b5a94a6 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -114,8 +114,9 @@ namespace CSMWorld struct ModelColumns : public BaseColumns { const RefIdColumn *mModel; + const RefIdColumn *mPersistence; - ModelColumns (const BaseColumns& base) : BaseColumns (base), mModel(nullptr) {} + ModelColumns (const BaseColumns& base) : BaseColumns (base), mModel(nullptr), mPersistence(nullptr) {} }; /// \brief Adapter for IDs with models (all but levelled lists) @@ -151,6 +152,9 @@ namespace CSMWorld if (column==mModel.mModel) return QString::fromUtf8 (record.get().mModel.c_str()); + if (column==mModel.mPersistence) + return (record.get().mRecordFlags & ESM::FLAG_Persistent) != 0; + return BaseRefIdAdapter::getData (column, data, index); } @@ -164,6 +168,13 @@ namespace CSMWorld RecordT record2 = record.get(); if (column==mModel.mModel) record2.mModel = value.toString().toUtf8().constData(); + else if (column==mModel.mPersistence) + { + if (value.toInt() != 0) + record2.mRecordFlags |= ESM::FLAG_Persistent; + else + record2.mRecordFlags &= ~ESM::FLAG_Persistent; + } else { BaseRefIdAdapter::setData (column, data, index, value); diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index cd2dd89dff..0cf9a4e6dc 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -54,6 +54,8 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.emplace_back(Columns::ColumnId_Model, ColumnBase::Display_Mesh); modelColumns.mModel = &mColumns.back(); + mColumns.emplace_back(Columns::ColumnId_Persistent, ColumnBase::Display_Boolean); + modelColumns.mPersistence = &mColumns.back(); NameColumns nameColumns (modelColumns); @@ -549,8 +551,6 @@ CSMWorld::RefIdCollection::RefIdCollection() new RefIdColumn (Columns::ColumnId_NpcRank, CSMWorld::ColumnBase::Display_UnsignedInteger8)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_Gold, CSMWorld::ColumnBase::Display_Integer)); - mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_NpcPersistence, CSMWorld::ColumnBase::Display_Boolean)); WeaponColumns weaponColumns (enchantableColumns); diff --git a/apps/opencs/model/world/refiddata.cpp b/apps/opencs/model/world/refiddata.cpp index e2ffbcca6b..79a2efdcc8 100644 --- a/apps/opencs/model/world/refiddata.cpp +++ b/apps/opencs/model/world/refiddata.cpp @@ -87,6 +87,39 @@ CSMWorld::RefIdData::LocalIndex CSMWorld::RefIdData::searchId ( return iter->second; } +unsigned int CSMWorld::RefIdData::getRecordFlags (const std::string& id) const +{ + LocalIndex localIndex = searchId (id); + + switch (localIndex.second) + { + case UniversalId::Type_Activator: return mActivators.getRecordFlags(localIndex.first); + case UniversalId::Type_Potion: return mPotions.getRecordFlags(localIndex.first); + case UniversalId::Type_Apparatus: return mApparati.getRecordFlags(localIndex.first); + case UniversalId::Type_Armor: return mArmors.getRecordFlags(localIndex.first); + case UniversalId::Type_Book: return mBooks.getRecordFlags(localIndex.first); + case UniversalId::Type_Clothing: return mClothing.getRecordFlags(localIndex.first); + case UniversalId::Type_Container: return mContainers.getRecordFlags(localIndex.first); + case UniversalId::Type_Creature: return mCreatures.getRecordFlags(localIndex.first); + case UniversalId::Type_Door: return mDoors.getRecordFlags(localIndex.first); + case UniversalId::Type_Ingredient: return mIngredients.getRecordFlags(localIndex.first); + case UniversalId::Type_CreatureLevelledList: return mCreatureLevelledLists.getRecordFlags(localIndex.first); + case UniversalId::Type_ItemLevelledList: return mItemLevelledLists.getRecordFlags(localIndex.first); + case UniversalId::Type_Light: return mLights.getRecordFlags(localIndex.first); + case UniversalId::Type_Lockpick: return mLockpicks.getRecordFlags(localIndex.first); + case UniversalId::Type_Miscellaneous: return mMiscellaneous.getRecordFlags(localIndex.first); + case UniversalId::Type_Npc: return mNpcs.getRecordFlags(localIndex.first); + case UniversalId::Type_Probe: return mProbes.getRecordFlags(localIndex.first); + case UniversalId::Type_Repair: return mRepairs.getRecordFlags(localIndex.first); + case UniversalId::Type_Static: return mStatics.getRecordFlags(localIndex.first); + case UniversalId::Type_Weapon: return mWeapons.getRecordFlags(localIndex.first); + default: + break; + } + + return 0; +} + void CSMWorld::RefIdData::erase (int index, int count) { LocalIndex localIndex = globalToLocalIndex (index); diff --git a/apps/opencs/model/world/refiddata.hpp b/apps/opencs/model/world/refiddata.hpp index 1480bb71d9..ab5269b390 100644 --- a/apps/opencs/model/world/refiddata.hpp +++ b/apps/opencs/model/world/refiddata.hpp @@ -47,6 +47,8 @@ namespace CSMWorld virtual RecordBase& getRecord (int index)= 0; + virtual unsigned int getRecordFlags (int index) const = 0; + virtual void appendRecord (const std::string& id, bool base) = 0; virtual void insertRecord (RecordBase& record) = 0; @@ -72,6 +74,8 @@ namespace CSMWorld RecordBase& getRecord (int index) override; + unsigned int getRecordFlags (int index) const override; + void appendRecord (const std::string& id, bool base) override; void insertRecord (RecordBase& record) override; @@ -111,6 +115,12 @@ namespace CSMWorld return mContainer.at (index); } + template + unsigned int RefIdDataContainer::getRecordFlags (int index) const + { + return mContainer.at (index).get().mRecordFlags; + } + template void RefIdDataContainer::appendRecord (const std::string& id, bool base) { @@ -209,7 +219,7 @@ namespace CSMWorld if (record.isModified() || record.mState == RecordBase::State_Deleted) { RecordT esmRecord = record.get(); - writer.startRecord(esmRecord.sRecordId); + writer.startRecord(esmRecord.sRecordId, esmRecord.mRecordFlags); esmRecord.save(writer, record.mState == RecordBase::State_Deleted); writer.endRecord(esmRecord.sRecordId); } @@ -273,6 +283,8 @@ namespace CSMWorld RecordBase& getRecord (const LocalIndex& index); + unsigned int getRecordFlags(const std::string& id) const; + void appendRecord (UniversalId::Type type, const std::string& id, bool base); int getAppendIndex (UniversalId::Type type) const; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index acf969bd3a..141bf99e92 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -588,7 +588,7 @@ namespace MWClass bool Creature::isPersistent(const MWWorld::ConstPtr &actor) const { const MWWorld::LiveCellRef* ref = actor.get(); - return ref->mBase->mPersistent; + return (ref->mBase->mRecordFlags & ESM::FLAG_Persistent) != 0; } std::string Creature::getSoundIdFromSndGen(const MWWorld::Ptr &ptr, const std::string &name) const diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 933ba5cd38..6131f86269 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -403,7 +403,7 @@ namespace MWClass bool Npc::isPersistent(const MWWorld::ConstPtr &actor) const { const MWWorld::LiveCellRef* ref = actor.get(); - return ref->mBase->mPersistent; + return (ref->mBase->mRecordFlags & ESM::FLAG_Persistent) != 0; } std::string Npc::getModel(const MWWorld::ConstPtr &ptr) const diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index 733547216b..7ec7e00f1a 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -118,8 +118,10 @@ void ESM::CellRef::loadData(ESMReader &esm, bool &isDeleted) esm.getHT(mPos, 24); break; case ESM::FourCC<'N','A','M','0'>::value: + { esm.skipHSub(); break; + } case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; diff --git a/components/esm/esmcommon.hpp b/components/esm/esmcommon.hpp index 749e9a85d6..10e05de905 100644 --- a/components/esm/esmcommon.hpp +++ b/components/esm/esmcommon.hpp @@ -16,6 +16,11 @@ enum Version VER_13 = 0x3fa66666 }; +enum RecordFlag + { + FLAG_Persistent = 0x00000400, + FLAG_Blocked = 0x00002000 + }; // CRTP for FIXED_STRING class, a structure used for holding fixed-length strings template< template class DERIVED, size_t SIZE> diff --git a/components/esm/loadacti.cpp b/components/esm/loadacti.cpp index 57c55d6760..6a08bca749 100644 --- a/components/esm/loadacti.cpp +++ b/components/esm/loadacti.cpp @@ -11,6 +11,7 @@ namespace ESM void Activator::load(ESMReader &esm, bool &isDeleted) { isDeleted = false; + mRecordFlags = esm.getRecordFlags(); bool hasName = false; while (esm.hasMoreSubs()) diff --git a/components/esm/loadacti.hpp b/components/esm/loadacti.hpp index 4cc72d5283..5b88ad379f 100644 --- a/components/esm/loadacti.hpp +++ b/components/esm/loadacti.hpp @@ -15,6 +15,7 @@ struct Activator /// Return a string descriptor for this record type. Currently used for debugging / error logs only. static std::string getRecordType() { return "Activator"; } + unsigned int mRecordFlags; std::string mId, mName, mScript, mModel; void load(ESMReader &esm, bool &isDeleted); diff --git a/components/esm/loadalch.cpp b/components/esm/loadalch.cpp index ba904f5037..b7c81ebdb4 100644 --- a/components/esm/loadalch.cpp +++ b/components/esm/loadalch.cpp @@ -11,6 +11,7 @@ namespace ESM void Potion::load(ESMReader &esm, bool &isDeleted) { isDeleted = false; + mRecordFlags = esm.getRecordFlags(); mEffects.mList.clear(); diff --git a/components/esm/loadalch.hpp b/components/esm/loadalch.hpp index 9ef390ebd9..d573531134 100644 --- a/components/esm/loadalch.hpp +++ b/components/esm/loadalch.hpp @@ -30,6 +30,7 @@ struct Potion }; ALDTstruct mData; + unsigned int mRecordFlags; std::string mId, mName, mModel, mIcon, mScript; EffectList mEffects; diff --git a/components/esm/loadappa.cpp b/components/esm/loadappa.cpp index b448e778cf..e9ff3ea86c 100644 --- a/components/esm/loadappa.cpp +++ b/components/esm/loadappa.cpp @@ -11,6 +11,7 @@ namespace ESM void Apparatus::load(ESMReader &esm, bool &isDeleted) { isDeleted = false; + mRecordFlags = esm.getRecordFlags(); bool hasName = false; bool hasData = false; diff --git a/components/esm/loadappa.hpp b/components/esm/loadappa.hpp index 74f8dd6aea..fcd9100be4 100644 --- a/components/esm/loadappa.hpp +++ b/components/esm/loadappa.hpp @@ -36,6 +36,7 @@ struct Apparatus }; AADTstruct mData; + unsigned int mRecordFlags; std::string mId, mModel, mIcon, mScript, mName; void load(ESMReader &esm, bool &isDeleted); diff --git a/components/esm/loadarmo.cpp b/components/esm/loadarmo.cpp index 9e2eca9a2c..902d4a4467 100644 --- a/components/esm/loadarmo.cpp +++ b/components/esm/loadarmo.cpp @@ -41,6 +41,7 @@ namespace ESM void Armor::load(ESMReader &esm, bool &isDeleted) { isDeleted = false; + mRecordFlags = esm.getRecordFlags(); mParts.mParts.clear(); diff --git a/components/esm/loadarmo.hpp b/components/esm/loadarmo.hpp index ef3bb734c0..195230fbf2 100644 --- a/components/esm/loadarmo.hpp +++ b/components/esm/loadarmo.hpp @@ -94,6 +94,7 @@ struct Armor AODTstruct mData; PartReferenceList mParts; + unsigned int mRecordFlags; std::string mId, mName, mModel, mIcon, mScript, mEnchant; void load(ESMReader &esm, bool &isDeleted); diff --git a/components/esm/loadbook.cpp b/components/esm/loadbook.cpp index c6d1d618de..756f01da9c 100644 --- a/components/esm/loadbook.cpp +++ b/components/esm/loadbook.cpp @@ -11,6 +11,7 @@ namespace ESM void Book::load(ESMReader &esm, bool &isDeleted) { isDeleted = false; + mRecordFlags = esm.getRecordFlags(); bool hasName = false; bool hasData = false; diff --git a/components/esm/loadbook.hpp b/components/esm/loadbook.hpp index bb2d7912f7..60b03f7a36 100644 --- a/components/esm/loadbook.hpp +++ b/components/esm/loadbook.hpp @@ -26,6 +26,7 @@ struct Book BKDTstruct mData; std::string mName, mModel, mIcon, mScript, mEnchant, mText; + unsigned int mRecordFlags; std::string mId; void load(ESMReader &esm, bool &isDeleted); diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 0356cc646b..d43911135a 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -146,7 +146,7 @@ namespace ESM } } - if (saveContext) + if (saveContext) { mContextList.push_back(esm.getContext()); esm.skipRecord(); @@ -197,9 +197,12 @@ namespace ESM if (mMapColor != 0) esm.writeHNT("NAM5", mMapColor); } + } - if (mRefNumCounter != 0) - esm.writeHNT("NAM0", mRefNumCounter); + void Cell::saveTempMarker(ESMWriter &esm, int tempCount) const + { + if (tempCount != 0) + esm.writeHNT("NAM0", tempCount); } void Cell::restore(ESMReader &esm, int iCtx) const @@ -251,6 +254,8 @@ namespace ESM { ref.load (esm, isDeleted); + // TODO: should count the number of temp refs and validate the number + // Identify references belonging to a parent file and adapt the ID accordingly. adjustRefNum (ref.mRefNum, esm); return true; @@ -275,7 +280,7 @@ namespace ESM mWater = 0; mWaterInt = false; mMapColor = 0; - mRefNumCounter = 0; + mRefNumCounter = -1; mData.mFlags = 0; mData.mX = 0; diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index d06b509c5a..c49dc20c59 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -94,7 +94,7 @@ struct Cell mWater(0), mWaterInt(false), mMapColor(0), - mRefNumCounter(0) + mRefNumCounter(-1) {} // Interior cells are indexed by this (it's the 'id'), for exterior @@ -133,6 +133,7 @@ struct Cell void loadCell(ESMReader &esm, bool saveContext = true); // Load everything, except NAME, DATAstruct and references void save(ESMWriter &esm, bool isDeleted = false) const; + void saveTempMarker(ESMWriter &esm, int tempCount) const; bool isExterior() const { @@ -183,7 +184,7 @@ struct Cell /// \param ignoreMoves ignore MVRF record and read reference like a regular CellRef. static bool getNextRef(ESMReader &esm, CellRef &ref, - bool &isDeleted, + bool &isDeleted, bool ignoreMoves = false, MovedCellRef *mref = nullptr); diff --git a/components/esm/loadclot.cpp b/components/esm/loadclot.cpp index 9546eec2dd..cf03dbad36 100644 --- a/components/esm/loadclot.cpp +++ b/components/esm/loadclot.cpp @@ -11,6 +11,7 @@ namespace ESM void Clothing::load(ESMReader &esm, bool &isDeleted) { isDeleted = false; + mRecordFlags = esm.getRecordFlags(); mParts.mParts.clear(); diff --git a/components/esm/loadclot.hpp b/components/esm/loadclot.hpp index 4db791c0c1..bbc8449a95 100644 --- a/components/esm/loadclot.hpp +++ b/components/esm/loadclot.hpp @@ -46,6 +46,7 @@ struct Clothing PartReferenceList mParts; + unsigned int mRecordFlags; std::string mId, mName, mModel, mIcon, mEnchant, mScript; void load(ESMReader &esm, bool &isDeleted); diff --git a/components/esm/loadcont.cpp b/components/esm/loadcont.cpp index 077fc2145a..03092571a4 100644 --- a/components/esm/loadcont.cpp +++ b/components/esm/loadcont.cpp @@ -32,6 +32,7 @@ namespace ESM void Container::load(ESMReader &esm, bool &isDeleted) { isDeleted = false; + mRecordFlags = esm.getRecordFlags(); mInventory.mList.clear(); diff --git a/components/esm/loadcont.hpp b/components/esm/loadcont.hpp index 0cac580748..ade9004214 100644 --- a/components/esm/loadcont.hpp +++ b/components/esm/loadcont.hpp @@ -46,6 +46,7 @@ struct Container Unknown = 8 }; + unsigned int mRecordFlags; std::string mId, mName, mModel, mScript; float mWeight; // Not sure, might be max total weight allowed? diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index ecb080f75e..02d664e1f2 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -13,8 +13,7 @@ namespace ESM { void Creature::load(ESMReader &esm, bool &isDeleted) { isDeleted = false; - - mPersistent = (esm.getRecordFlags() & 0x0400) != 0; + mRecordFlags = esm.getRecordFlags(); mAiPackage.mList.clear(); mInventory.mList.clear(); diff --git a/components/esm/loadcrea.hpp b/components/esm/loadcrea.hpp index 0ab09ee122..f6b188d96e 100644 --- a/components/esm/loadcrea.hpp +++ b/components/esm/loadcrea.hpp @@ -76,10 +76,9 @@ struct Creature int mBloodType; unsigned char mFlags; - bool mPersistent; - float mScale; + unsigned int mRecordFlags; std::string mId, mModel, mName, mScript; std::string mOriginal; // Base creature that this is a modification of diff --git a/components/esm/loaddoor.cpp b/components/esm/loaddoor.cpp index d99418add2..3c446789b7 100644 --- a/components/esm/loaddoor.cpp +++ b/components/esm/loaddoor.cpp @@ -11,6 +11,7 @@ namespace ESM void Door::load(ESMReader &esm, bool &isDeleted) { isDeleted = false; + mRecordFlags = esm.getRecordFlags(); bool hasName = false; while (esm.hasMoreSubs()) diff --git a/components/esm/loaddoor.hpp b/components/esm/loaddoor.hpp index 3afe5d5e4b..167eda20f5 100644 --- a/components/esm/loaddoor.hpp +++ b/components/esm/loaddoor.hpp @@ -15,6 +15,7 @@ struct Door /// Return a string descriptor for this record type. Currently used for debugging / error logs only. static std::string getRecordType() { return "Door"; } + unsigned int mRecordFlags; std::string mId, mName, mModel, mScript, mOpenSound, mCloseSound; void load(ESMReader &esm, bool &isDeleted); diff --git a/components/esm/loadingr.cpp b/components/esm/loadingr.cpp index a19a9d5dd9..26873a6eea 100644 --- a/components/esm/loadingr.cpp +++ b/components/esm/loadingr.cpp @@ -11,6 +11,7 @@ namespace ESM void Ingredient::load(ESMReader &esm, bool &isDeleted) { isDeleted = false; + mRecordFlags = esm.getRecordFlags(); bool hasName = false; bool hasData = false; diff --git a/components/esm/loadingr.hpp b/components/esm/loadingr.hpp index c0f4450238..34e05da2c1 100644 --- a/components/esm/loadingr.hpp +++ b/components/esm/loadingr.hpp @@ -29,6 +29,7 @@ struct Ingredient }; IRDTstruct mData; + unsigned int mRecordFlags; std::string mId, mName, mModel, mIcon, mScript; void load(ESMReader &esm, bool &isDeleted); diff --git a/components/esm/loadlevlist.cpp b/components/esm/loadlevlist.cpp index 26751b8925..450bf06ecb 100644 --- a/components/esm/loadlevlist.cpp +++ b/components/esm/loadlevlist.cpp @@ -9,6 +9,7 @@ namespace ESM void LevelledListBase::load(ESMReader &esm, bool &isDeleted) { isDeleted = false; + mRecordFlags = esm.getRecordFlags(); bool hasName = false; bool hasList = false; diff --git a/components/esm/loadlevlist.hpp b/components/esm/loadlevlist.hpp index ed4131c165..d3451b70ae 100644 --- a/components/esm/loadlevlist.hpp +++ b/components/esm/loadlevlist.hpp @@ -22,6 +22,7 @@ struct LevelledListBase { int mFlags; unsigned char mChanceNone; // Chance that none are selected (0-100) + unsigned int mRecordFlags; std::string mId; // Record name used to read references. Must be set before load() is diff --git a/components/esm/loadligh.cpp b/components/esm/loadligh.cpp index 2e3f711eb7..e53c82cc3f 100644 --- a/components/esm/loadligh.cpp +++ b/components/esm/loadligh.cpp @@ -11,6 +11,7 @@ namespace ESM void Light::load(ESMReader &esm, bool &isDeleted) { isDeleted = false; + mRecordFlags = esm.getRecordFlags(); bool hasName = false; bool hasData = false; diff --git a/components/esm/loadligh.hpp b/components/esm/loadligh.hpp index 8509c64b6d..901fe6ec85 100644 --- a/components/esm/loadligh.hpp +++ b/components/esm/loadligh.hpp @@ -45,6 +45,7 @@ struct Light LHDTstruct mData; + unsigned int mRecordFlags; std::string mSound, mScript, mModel, mIcon, mName, mId; void load(ESMReader &esm, bool &isDeleted); diff --git a/components/esm/loadlock.cpp b/components/esm/loadlock.cpp index 6f02909b98..88ce77e34e 100644 --- a/components/esm/loadlock.cpp +++ b/components/esm/loadlock.cpp @@ -11,6 +11,7 @@ namespace ESM void Lockpick::load(ESMReader &esm, bool &isDeleted) { isDeleted = false; + mRecordFlags = esm.getRecordFlags(); bool hasName = false; bool hasData = false; diff --git a/components/esm/loadlock.hpp b/components/esm/loadlock.hpp index 9db41af978..9cd40c0d4f 100644 --- a/components/esm/loadlock.hpp +++ b/components/esm/loadlock.hpp @@ -25,6 +25,7 @@ struct Lockpick }; // Size = 16 Data mData; + unsigned int mRecordFlags; std::string mId, mName, mModel, mIcon, mScript; void load(ESMReader &esm, bool &isDeleted); diff --git a/components/esm/loadmisc.cpp b/components/esm/loadmisc.cpp index 90fcd618e8..39d589eac8 100644 --- a/components/esm/loadmisc.cpp +++ b/components/esm/loadmisc.cpp @@ -11,6 +11,7 @@ namespace ESM void Miscellaneous::load(ESMReader &esm, bool &isDeleted) { isDeleted = false; + mRecordFlags = esm.getRecordFlags(); bool hasName = false; bool hasData = false; diff --git a/components/esm/loadmisc.hpp b/components/esm/loadmisc.hpp index e7a3239042..72aaa5de3b 100644 --- a/components/esm/loadmisc.hpp +++ b/components/esm/loadmisc.hpp @@ -30,6 +30,7 @@ struct Miscellaneous }; MCDTstruct mData; + unsigned int mRecordFlags; std::string mId, mName, mModel, mIcon, mScript; void load(ESMReader &esm, bool &isDeleted); diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index 34d806072d..e1fb9b5931 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -11,8 +11,7 @@ namespace ESM void NPC::load(ESMReader &esm, bool &isDeleted) { isDeleted = false; - - mPersistent = (esm.getRecordFlags() & 0x0400) != 0; + mRecordFlags = esm.getRecordFlags(); mSpells.mList.clear(); mInventory.mList.clear(); diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index 687afeaf64..ba9f415760 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -116,8 +116,6 @@ struct NPC int mBloodType; unsigned char mFlags; - bool mPersistent; - InventoryList mInventory; SpellList mSpells; @@ -129,6 +127,7 @@ struct NPC AIPackageList mAiPackage; + unsigned int mRecordFlags; std::string mId, mName, mModel, mRace, mClass, mFaction, mScript; // body parts diff --git a/components/esm/loadprob.cpp b/components/esm/loadprob.cpp index ceb19a77b6..8f03189686 100644 --- a/components/esm/loadprob.cpp +++ b/components/esm/loadprob.cpp @@ -11,6 +11,7 @@ namespace ESM void Probe::load(ESMReader &esm, bool &isDeleted) { isDeleted = false; + mRecordFlags = esm.getRecordFlags(); bool hasName = false; bool hasData = false; diff --git a/components/esm/loadprob.hpp b/components/esm/loadprob.hpp index da203b456b..930e31a971 100644 --- a/components/esm/loadprob.hpp +++ b/components/esm/loadprob.hpp @@ -25,6 +25,7 @@ struct Probe }; // Size = 16 Data mData; + unsigned int mRecordFlags; std::string mId, mName, mModel, mIcon, mScript; void load(ESMReader &esm, bool &isDeleted); diff --git a/components/esm/loadrepa.cpp b/components/esm/loadrepa.cpp index c86227a045..ecb693c0c5 100644 --- a/components/esm/loadrepa.cpp +++ b/components/esm/loadrepa.cpp @@ -11,6 +11,7 @@ namespace ESM void Repair::load(ESMReader &esm, bool &isDeleted) { isDeleted = false; + mRecordFlags = esm.getRecordFlags(); bool hasName = false; bool hasData = false; diff --git a/components/esm/loadrepa.hpp b/components/esm/loadrepa.hpp index 2537c53cb6..312c87b7b4 100644 --- a/components/esm/loadrepa.hpp +++ b/components/esm/loadrepa.hpp @@ -25,6 +25,7 @@ struct Repair }; // Size = 16 Data mData; + unsigned int mRecordFlags; std::string mId, mName, mModel, mIcon, mScript; void load(ESMReader &esm, bool &isDeleted); diff --git a/components/esm/loadstat.cpp b/components/esm/loadstat.cpp index 14bac10f95..1073ab48e2 100644 --- a/components/esm/loadstat.cpp +++ b/components/esm/loadstat.cpp @@ -11,6 +11,9 @@ namespace ESM void Static::load(ESMReader &esm, bool &isDeleted) { isDeleted = false; + mRecordFlags = esm.getRecordFlags(); + //bool isBlocked = (mRecordFlags & ESM::FLAG_Blocked) != 0; + //bool isPersistent = (mRecordFlags & ESM::FLAG_Persistent) != 0; bool hasName = false; while (esm.hasMoreSubs()) diff --git a/components/esm/loadstat.hpp b/components/esm/loadstat.hpp index 3d91440402..038fb9f52b 100644 --- a/components/esm/loadstat.hpp +++ b/components/esm/loadstat.hpp @@ -26,6 +26,7 @@ struct Static /// Return a string descriptor for this record type. Currently used for debugging / error logs only. static std::string getRecordType() { return "Static"; } + unsigned int mRecordFlags; std::string mId, mModel; void load(ESMReader &esm, bool &isDeleted); diff --git a/components/esm/loadweap.cpp b/components/esm/loadweap.cpp index b57359e29d..78b9bb4073 100644 --- a/components/esm/loadweap.cpp +++ b/components/esm/loadweap.cpp @@ -11,6 +11,7 @@ namespace ESM void Weapon::load(ESMReader &esm, bool &isDeleted) { isDeleted = false; + mRecordFlags = esm.getRecordFlags(); bool hasName = false; bool hasData = false; diff --git a/components/esm/loadweap.hpp b/components/esm/loadweap.hpp index 90431756d7..8d1591854b 100644 --- a/components/esm/loadweap.hpp +++ b/components/esm/loadweap.hpp @@ -73,6 +73,7 @@ struct Weapon WPDTstruct mData; + unsigned int mRecordFlags; std::string mId, mName, mModel, mIcon, mEnchant, mScript; void load(ESMReader &esm, bool &isDeleted);