diff --git a/CHANGELOG.md b/CHANGELOG.md index 1276a449f0..fbc6c30adb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ Bug #6992: Crossbow reloading doesn't look the same as in Morrowind Bug #6993: Shooting your last round of ammunition causes the attack animation to cancel Bug #7009: Falling actors teleport to the ground without receiving any damage on cell loading + Bug #7034: Misc items defined in one content file are not treated as keys if another content file uses them as such Feature #6933: Support high-resolution cursor textures Feature #6945: Support S3TC-compressed and BGR/BGRA NiPixelData Feature #6979: Add support of loading and displaying LOD assets purely based on their filename extension diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 78c55343c4..78b14d4894 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -1042,7 +1042,7 @@ namespace EsmTool std::cout << " Script: " << mData.mScript << std::endl; std::cout << " Weight: " << mData.mData.mWeight << std::endl; std::cout << " Value: " << mData.mData.mValue << std::endl; - std::cout << " Is Key: " << mData.mData.mIsKey << std::endl; + std::cout << " Is Key: " << (mData.mData.mFlags & ESM::Miscellaneous::Key) << std::endl; std::cout << " Deleted: " << mIsDeleted << std::endl; } diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 54917fd0d9..4e9c5d3c78 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -726,7 +726,7 @@ QVariant CSMWorld::MiscRefIdAdapter::getData(const RefIdColumn* column, const Re data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Miscellaneous))); if (column == mKey) - return record.get().mData.mIsKey != 0; + return bool(record.get().mData.mFlags & ESM::Miscellaneous::Key); return InventoryRefIdAdapter::getData(column, data, index); } @@ -740,7 +740,7 @@ void CSMWorld::MiscRefIdAdapter::setData( ESM::Miscellaneous misc = record.get(); if (column == mKey) - misc.mData.mIsKey = value.toInt(); + misc.mData.mFlags = value.toInt(); else { InventoryRefIdAdapter::setData(column, data, index, value); diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 8ddf6f6522..c0b9ecdd8f 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -155,7 +155,7 @@ namespace MWClass std::string text; text += MWGui::ToolTips::getWeightString(ref->mBase->mData.mWeight, "#{sWeight}"); - if (!gold && !ref->mBase->mData.mIsKey) + if (!gold && !(ref->mBase->mData.mFlags & ESM::Miscellaneous::Key)) text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}"); if (MWBase::Environment::get().getWindowManager()->getFullHelp()) @@ -221,7 +221,7 @@ namespace MWClass { const MWWorld::LiveCellRef* ref = item.get(); - return !ref->mBase->mData.mIsKey && (npcServices & ESM::NPC::Misc) && !isGold(item); + return !(ref->mBase->mData.mFlags & ESM::Miscellaneous::Key) && (npcServices & ESM::NPC::Misc) && !isGold(item); } float Miscellaneous::getWeight(const MWWorld::ConstPtr& ptr) const @@ -233,7 +233,7 @@ namespace MWClass bool Miscellaneous::isKey(const MWWorld::ConstPtr& ptr) const { const MWWorld::LiveCellRef* ref = ptr.get(); - return ref->mBase->mData.mIsKey != 0; + return ref->mBase->mData.mFlags & ESM::Miscellaneous::Key; } bool Miscellaneous::isSoulGem(const MWWorld::ConstPtr& ptr) const diff --git a/apps/openmw/mwlua/types/misc.cpp b/apps/openmw/mwlua/types/misc.cpp index 0b3f66a327..cfb2a89ad5 100644 --- a/apps/openmw/mwlua/types/misc.cpp +++ b/apps/openmw/mwlua/types/misc.cpp @@ -42,8 +42,8 @@ namespace MWLua record["icon"] = sol::readonly_property([vfs](const ESM::Miscellaneous& rec) -> std::string { return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs); }); - record["isKey"] - = sol::readonly_property([](const ESM::Miscellaneous& rec) -> bool { return rec.mData.mIsKey; }); + record["isKey"] = sol::readonly_property( + [](const ESM::Miscellaneous& rec) -> bool { return rec.mData.mFlags & ESM::Miscellaneous::Key; }); record["value"] = sol::readonly_property([](const ESM::Miscellaneous& rec) -> int { return rec.mData.mValue; }); record["weight"] = sol::readonly_property([](const ESM::Miscellaneous& rec) -> float { return rec.mData.mWeight; }); diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 3fd5980abe..520b60abf6 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -34,8 +34,8 @@ namespace constexpr std::size_t deletedRefID = std::numeric_limits::max(); - void readRefs( - const ESM::Cell& cell, std::vector& refs, std::vector& refIDs, ESM::ReadersCache& readers) + void readRefs(const ESM::Cell& cell, std::vector& refs, std::vector& refIDs, + std::set& keyIDs, ESM::ReadersCache& readers) { // TODO: we have many similar copies of this code. for (size_t i = 0; i < cell.mContextList.size(); i++) @@ -53,6 +53,8 @@ namespace else if (std::find(cell.mMovedRefs.begin(), cell.mMovedRefs.end(), ref.mRefNum) == cell.mMovedRefs.end()) { + if (!ref.mKey.empty()) + keyIDs.insert(std::move(ref.mKey)); refs.emplace_back(ref.mRefNum, refIDs.size()); refIDs.push_back(std::move(ref.mRefID)); } @@ -64,6 +66,8 @@ namespace refs.emplace_back(value.mRefNum, deletedRefID); else { + if (!value.mKey.empty()) + keyIDs.insert(std::move(value.mKey)); refs.emplace_back(value.mRefNum, refIDs.size()); refIDs.push_back(value.mRefID); } @@ -403,10 +407,10 @@ namespace MWWorld void ESMStore::validateRecords(ESM::ReadersCache& readers) { validate(); - countAllCellRefs(readers); + countAllCellRefsAndMarkKeys(readers); } - void ESMStore::countAllCellRefs(ESM::ReadersCache& readers) + void ESMStore::countAllCellRefsAndMarkKeys(ESM::ReadersCache& readers) { // TODO: We currently need to read entire files here again. // We should consider consolidating or deferring this reading. @@ -414,11 +418,12 @@ namespace MWWorld return; std::vector refs; std::vector refIDs; - Store Cells = getWritable(); + std::set keyIDs; + Store Cells = get(); for (auto it = Cells.intBegin(); it != Cells.intEnd(); ++it) - readRefs(*it, refs, refIDs, readers); + readRefs(*it, refs, refIDs, keyIDs, readers); for (auto it = Cells.extBegin(); it != Cells.extEnd(); ++it) - readRefs(*it, refs, refIDs, readers); + readRefs(*it, refs, refIDs, keyIDs, readers); const auto lessByRefNum = [](const Ref& l, const Ref& r) { return l.mRefNum < r.mRefNum; }; std::stable_sort(refs.begin(), refs.end(), lessByRefNum); const auto equalByRefNum = [](const Ref& l, const Ref& r) { return l.mRefNum == r.mRefNum; }; @@ -432,6 +437,13 @@ namespace MWWorld } }; Misc::forEachUnique(refs.rbegin(), refs.rend(), equalByRefNum, incrementRefCount); + auto& store = getWritable().mStatic; + for (const std::string& id : keyIDs) + { + auto it = store.find(id); + if (it != store.end()) + it->second.mData.mFlags |= ESM::Miscellaneous::Key; + } } int ESMStore::getRefCount(std::string_view id) const diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index d41312ac4e..a4a714af91 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -125,7 +125,7 @@ namespace MWWorld /// Validate entries in store after setup void validate(); - void countAllCellRefs(ESM::ReadersCache& readers); + void countAllCellRefsAndMarkKeys(ESM::ReadersCache& readers); template void removeMissingObjects(Store& store); diff --git a/components/esm3/loadmisc.cpp b/components/esm3/loadmisc.cpp index 6e0ed03b22..74022b2e99 100644 --- a/components/esm3/loadmisc.cpp +++ b/components/esm3/loadmisc.cpp @@ -75,7 +75,7 @@ namespace ESM mRecordFlags = 0; mData.mWeight = 0; mData.mValue = 0; - mData.mIsKey = 0; + mData.mFlags = 0; mName.clear(); mModel.clear(); mIcon.clear(); diff --git a/components/esm3/loadmisc.hpp b/components/esm3/loadmisc.hpp index 7a203443cf..ddd0561c6b 100644 --- a/components/esm3/loadmisc.hpp +++ b/components/esm3/loadmisc.hpp @@ -27,10 +27,14 @@ namespace ESM { float mWeight; int mValue; - int mIsKey; // There are many keys in Morrowind.esm that has this - // set to 0. TODO: Check what this field corresponds to - // in the editor. + int mFlags; }; + + enum Flags + { + Key = 0x1 // Assigned as a key in the content file that defined the record + }; + MCDTstruct mData; unsigned int mRecordFlags;