From bbe5adb8601dd56ca76fb3f69ee1a9590b928861 Mon Sep 17 00:00:00 2001 From: capostrophic Date: Fri, 10 Jan 2020 13:00:57 +0300 Subject: [PATCH] Use shield body part model for creatures (bug #5250) --- CHANGELOG.md | 1 + apps/openmw/mwrender/actoranimation.cpp | 26 ++++++++++++++++++++++ apps/openmw/mwrender/creatureanimation.cpp | 24 +++++++++++++++++++- apps/openmw/mwrender/npcanimation.cpp | 17 +++++++++----- 4 files changed, 61 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3178c609b..3ca82279e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -191,6 +191,7 @@ Bug #5239: OpenMW-CS does not support non-ASCII characters in path names Bug #5241: On-self absorb spells cannot be detected Bug #5242: ExplodeSpell behavior differs from Cast behavior + Bug #5250: Creatures display shield ground mesh instead of shield body part Feature #1774: Handle AvoidNode Feature #2229: Improve pathfinding AI Feature #3025: Analogue gamepad movement controls diff --git a/apps/openmw/mwrender/actoranimation.cpp b/apps/openmw/mwrender/actoranimation.cpp index 71811db68..fcffe220b 100644 --- a/apps/openmw/mwrender/actoranimation.cpp +++ b/apps/openmw/mwrender/actoranimation.cpp @@ -27,6 +27,7 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwmechanics/actorutil.hpp" #include "../mwmechanics/weapontype.hpp" @@ -87,6 +88,31 @@ PartHolderPtr ActorAnimation::attachMesh(const std::string& model, const std::st std::string ActorAnimation::getShieldMesh(MWWorld::ConstPtr shield) const { std::string mesh = shield.getClass().getModel(shield); + const ESM::Armor *armor = shield.get()->mBase; + const std::vector& bodyparts = armor->mParts.mParts; + if (!bodyparts.empty()) + { + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const MWWorld::Store &partStore = store.get(); + + // Try to get shield model from bodyparts first, with ground model as fallback + for (const auto& part : bodyparts) + { + // Assume all creatures use the male mesh. + if (part.mPart != ESM::PRT_Shield || part.mMale.empty()) + continue; + const ESM::BodyPart *bodypart = partStore.search(part.mMale); + if (bodypart && bodypart->mData.mType == ESM::BodyPart::MT_Armor && !bodypart->mModel.empty()) + { + mesh = "meshes\\" + bodypart->mModel; + break; + } + } + } + + if (mesh.empty()) + return mesh; + std::string holsteredName = mesh; holsteredName = holsteredName.replace(holsteredName.size()-4, 4, "_sh.nif"); if(mResourceSystem->getVFS()->exists(holsteredName)) diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index baa695cda..8e7f30687 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -13,11 +13,13 @@ #include +#include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwmechanics/weapontype.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/esmstore.hpp" namespace MWRender { @@ -114,6 +116,7 @@ void CreatureWeaponAnimation::updatePart(PartHolderPtr& scene, int slot) MWWorld::ConstPtr item = *it; std::string bonename; + std::string itemModel = item.getClass().getModel(item); if (slot == MWWorld::InventoryStore::Slot_CarriedRight) { if(item.getTypeName() == typeid(ESM::Weapon).name()) @@ -132,11 +135,30 @@ void CreatureWeaponAnimation::updatePart(PartHolderPtr& scene, int slot) bonename = "Weapon Bone"; } else + { bonename = "Shield Bone"; + if (item.getTypeName() == typeid(ESM::Armor).name()) + { + // Shield body part model should be used if possible. + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + for (const auto& part : item.get()->mBase->mParts.mParts) + { + // Assume all creatures use the male mesh. + if (part.mPart != ESM::PRT_Shield || part.mMale.empty()) + continue; + const ESM::BodyPart *bodypart = store.get().search(part.mMale); + if (bodypart && bodypart->mData.mType == ESM::BodyPart::MT_Armor && !bodypart->mModel.empty()) + { + itemModel = "meshes\\" + bodypart->mModel; + break; + } + } + } + } try { - osg::ref_ptr node = mResourceSystem->getSceneManager()->getInstance(item.getClass().getModel(item)); + osg::ref_ptr node = mResourceSystem->getSceneManager()->getInstance(itemModel); const NodeMap& nodeMap = getNodeMap(); NodeMap::const_iterator found = nodeMap.find(Misc::StringUtils::lowerCase(bonename)); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index e9f62e25c..b63962b3e 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -518,14 +518,14 @@ std::string NpcAnimation::getShieldMesh(MWWorld::ConstPtr shield) const { std::string mesh = shield.getClass().getModel(shield); const ESM::Armor *armor = shield.get()->mBase; - std::vector bodyparts = armor->mParts.mParts; + const std::vector& bodyparts = armor->mParts.mParts; if (!bodyparts.empty()) { const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); const MWWorld::Store &partStore = store.get(); - // For NPCs try to get shield model from bodyparts first, with ground model as fallback - for (auto & part : bodyparts) + // Try to get shield model from bodyparts first, with ground model as fallback + for (const auto& part : bodyparts) { if (part.mPart != ESM::PRT_Shield) continue; @@ -538,16 +538,21 @@ std::string NpcAnimation::getShieldMesh(MWWorld::ConstPtr shield) const if (!bodypartName.empty()) { - const ESM::BodyPart *bodypart = 0; - bodypart = partStore.search(bodypartName); + const ESM::BodyPart *bodypart = partStore.search(bodypartName); if (bodypart == nullptr || bodypart->mData.mType != ESM::BodyPart::MT_Armor) - return ""; + return std::string(); else if (!bodypart->mModel.empty()) + { mesh = "meshes\\" + bodypart->mModel; + break; + } } } } + if (mesh.empty()) + return std::string(); + std::string holsteredName = mesh; holsteredName = holsteredName.replace(holsteredName.size()-4, 4, "_sh.nif"); if(mResourceSystem->getVFS()->exists(holsteredName))