diff --git a/CHANGELOG.md b/CHANGELOG.md index 873d7c7488..e97693047b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -59,6 +59,7 @@ Bug #7134: Saves with an invalid last generated RefNum can be loaded Bug #7163: Myar Aranath: Wheat breaks the GUI Bug #7172: Current music playlist continues playing indefinitely if next playlist is empty + Bug #7204: Missing actor scripts freeze the game Bug #7229: Error marker loading failure is not handled Bug #7243: Supporting loading external files from VFS from esm files Bug #7284: "Your weapon has no effect." message doesn't always show when the player character attempts to attack diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index f9b53cf21f..ad3d1f8d43 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -84,7 +84,8 @@ namespace } std::vector getNPCsToReplace(const MWWorld::Store& factions, - const MWWorld::Store& classes, const std::unordered_map& npcs) + const MWWorld::Store& classes, const MWWorld::Store& scripts, + const std::unordered_map& npcs) { // Cache first class from store - we will use it if current class is not found const ESM::RefId& defaultCls = getDefaultClass(classes); @@ -122,6 +123,14 @@ namespace changed = true; } + if (!npc.mScript.empty() && !scripts.search(npc.mScript)) + { + Log(Debug::Verbose) << "NPC " << npc.mId << " (" << npc.mName << ") has nonexistent script " + << npc.mScript << ", ignoring it."; + npc.mScript = ESM::RefId(); + changed = true; + } + if (changed) npcsToReplace.push_back(npc); } @@ -138,9 +147,9 @@ namespace { if (!item.mScript.empty() && !scripts.search(item.mScript)) { + Log(Debug::Verbose) << MapT::mapped_type::getRecordType() << ' ' << id << " (" << item.mName + << ") has nonexistent script " << item.mScript << ", ignoring it."; item.mScript = ESM::RefId(); - Log(Debug::Verbose) << "Item " << id << " (" << item.mName << ") has nonexistent script " - << item.mScript << ", ignoring it."; } } } @@ -517,8 +526,8 @@ namespace MWWorld void ESMStore::validate() { auto& npcs = getWritable(); - std::vector npcsToReplace - = getNPCsToReplace(getWritable(), getWritable(), npcs.mStatic); + std::vector npcsToReplace = getNPCsToReplace( + getWritable(), getWritable(), getWritable(), npcs.mStatic); for (const ESM::NPC& npc : npcsToReplace) { @@ -526,6 +535,8 @@ namespace MWWorld npcs.insertStatic(npc); } + removeMissingScripts(getWritable(), getWritable().mStatic); + // Validate spell effects for invalid arguments std::vector spellsToReplace; auto& spells = getWritable(); @@ -605,8 +616,8 @@ namespace MWWorld auto& npcs = getWritable(); auto& scripts = getWritable(); - std::vector npcsToReplace - = getNPCsToReplace(getWritable(), getWritable(), npcs.mDynamic); + std::vector npcsToReplace = getNPCsToReplace( + getWritable(), getWritable(), getWritable(), npcs.mDynamic); for (const ESM::NPC& npc : npcsToReplace) npcs.insert(npc); @@ -614,6 +625,7 @@ namespace MWWorld removeMissingScripts(scripts, getWritable().mDynamic); removeMissingScripts(scripts, getWritable().mDynamic); removeMissingScripts(scripts, getWritable().mDynamic); + removeMissingScripts(scripts, getWritable().mDynamic); removeMissingScripts(scripts, getWritable().mDynamic); removeMissingObjects(getWritable());