diff --git a/CHANGELOG.md b/CHANGELOG.md index 07f16ac81b..eff35bfa53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ Bug #6657: Distant terrain tiles become black when using FWIW mod Bug #6661: Saved games that have no preview screenshot cause issues or crashes Bug #6716: mwscript comparison operator handling is too restrictive + Bug #6754: Beast to Non-beast transformation mod is not working on OpenMW Bug #6807: Ultimate Galleon is not working properly Bug #6893: Lua: Inconsistent behavior with actors affected by Disable and SetDelete commands Bug #6894: Added item combines with equipped stack instead of creating a new unequipped stack diff --git a/apps/openmw/mwrender/actorutil.cpp b/apps/openmw/mwrender/actorutil.cpp index 6cef42d60f..8da921e532 100644 --- a/apps/openmw/mwrender/actorutil.cpp +++ b/apps/openmw/mwrender/actorutil.cpp @@ -1,6 +1,7 @@ #include "actorutil.hpp" #include +#include namespace MWRender { @@ -29,4 +30,11 @@ namespace MWRender return Settings::models().mXbaseanim1st; } } + + bool isDefaultActorSkeleton(std::string_view model) + { + return VFS::Path::pathEqual(Settings::models().mBaseanimkna.get(), model) + || VFS::Path::pathEqual(Settings::models().mBaseanimfemale.get(), model) + || VFS::Path::pathEqual(Settings::models().mBaseanim.get(), model); + } } diff --git a/apps/openmw/mwrender/actorutil.hpp b/apps/openmw/mwrender/actorutil.hpp index bbffc4ad24..3107bf0183 100644 --- a/apps/openmw/mwrender/actorutil.hpp +++ b/apps/openmw/mwrender/actorutil.hpp @@ -2,10 +2,12 @@ #define OPENMW_APPS_OPENMW_MWRENDER_ACTORUTIL_H #include +#include namespace MWRender { const std::string& getActorSkeleton(bool firstPerson, bool female, bool beast, bool werewolf); + bool isDefaultActorSkeleton(std::string_view model); } #endif diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 900d0d9ae1..e17a1f34a3 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -493,8 +493,16 @@ namespace MWRender std::string smodel = defaultSkeleton; if (!is1stPerson && !isWerewolf && !mNpc->mModel.empty()) - smodel = Misc::ResourceHelpers::correctActorModelPath( - Misc::ResourceHelpers::correctMeshPath(mNpc->mModel), mResourceSystem->getVFS()); + { + // TESCS sometimes writes the default animation nif to the animation subrecord. This harmless (as it + // will match the NPC's race) until the NPC's race is changed. If the player record contains a default + // non-beast race animation and the player selects a beast race in chargen, animations aren't applied + // properly. Morrowind.exe appears to handle an NPC using any of the base animations as not having custom + // animations. + std::string model = Misc::ResourceHelpers::correctMeshPath(mNpc->mModel); + if (!isDefaultActorSkeleton(model)) + smodel = Misc::ResourceHelpers::correctActorModelPath(model, mResourceSystem->getVFS()); + } setObjectRoot(smodel, true, true, false); @@ -511,7 +519,7 @@ namespace MWRender addAnimSource(smodel, smodel); - if (!isWerewolf && mNpc->mRace.contains("argonian")) + if (!isWerewolf && isBeast && mNpc->mRace.contains("argonian")) addAnimSource("meshes\\xargonian_swimkna.nif", smodel); } else diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index d5d2c03b8b..7ecaaa217d 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -17,11 +17,8 @@ #include #include #include -#include -#include #include "../mwmechanics/spelllist.hpp" -#include "../mwrender/actorutil.hpp" namespace { @@ -136,32 +133,11 @@ namespace } const ESM::Race* race = races.search(npc.mRace); - if (race) - { - // TESCS sometimes writes the default animation nif to the animation subrecord. This harmless (as it - // will match the NPC's race) until the NPC's race is changed. If the player record contains a default - // non-beast race animation and the player selects a beast race in chargen, animations aren't applied - // properly. Morrowind.exe handles this gracefully, so we clear the animation here to force the default - // values to be used. - if (!npc.mModel.empty() && npc.mId == "player") - { - const bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0; - const std::string& defaultModel = MWRender::getActorSkeleton(false, !npc.isMale(), isBeast, false); - std::string model = Misc::ResourceHelpers::correctMeshPath(npc.mModel); - if (VFS::Path::pathEqual(defaultModel, model)) - { - npc.mModel.clear(); - changed = true; - } - } - } - else + if (!race) { Log(Debug::Verbose) << "NPC " << npc.mId << " (" << npc.mName << ") has nonexistent race " << npc.mRace << ", using " << defaultRace << " race as replacement."; npc.mRace = defaultRace; - // Remove animations that might be race specific - npc.mModel.clear(); changed = true; } diff --git a/apps/openmw_test_suite/CMakeLists.txt b/apps/openmw_test_suite/CMakeLists.txt index 421e9e82f1..967511953d 100644 --- a/apps/openmw_test_suite/CMakeLists.txt +++ b/apps/openmw_test_suite/CMakeLists.txt @@ -7,7 +7,6 @@ file(GLOB UNITTEST_SRC_FILES ../openmw/mwworld/store.cpp ../openmw/mwworld/esmstore.cpp ../openmw/mwworld/timestamp.cpp - ../openmw/mwrender/actorutil.cpp mwworld/test_store.cpp mwworld/testduration.cpp