diff --git a/CHANGELOG.md b/CHANGELOG.md index 285933ad4f..23814425a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ Bug #3737: Scripts from The Underground 2 .esp do not play (all patched versions) Bug #3846: Strings starting with "-" fail to compile if not enclosed in quotes + Bug #5453: Magic effect VFX are offset for creatures Bug #5483: AutoCalc flag is not used to calculate spells cost Bug #6101: Disarming trapped unlocked owned objects isn't considered a crime diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 47225bc6f7..6b07fdbb86 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -737,12 +737,31 @@ namespace MWMechanics else { // If the caster has no animation, add the effect directly to the effectManager - // We should scale it manually - osg::Vec3f bounds (MWBase::Environment::get().getWorld()->getHalfExtents(mCaster) * 2.f / Constants::UnitsPerFoot); - float scale = std::max({ bounds.x()/3.f, bounds.y()/3.f, bounds.z()/6.f }); - float meshScale = !mCaster.getClass().isActor() ? mCaster.getCellRef().getScale() : 1.0f; + // We must scale and position it manually + float scale = mCaster.getCellRef().getScale(); osg::Vec3f pos (mCaster.getRefData().getPosition().asVec3()); - MWBase::Environment::get().getWorld()->spawnEffect("meshes\\" + castStatic->mModel, effect->mParticle, pos, scale * meshScale); + if (!mCaster.getClass().isNpc()) + { + osg::Vec3f bounds (MWBase::Environment::get().getWorld()->getHalfExtents(mCaster) * 2.f); + scale *= std::max({bounds.x(), bounds.y(), bounds.z() / 2.f}) / 64.f; + float offset = 0.f; + if (bounds.z() < 128.f) + offset = bounds.z() - 128.f; + else if (bounds.z() < bounds.x() + bounds.y()) + offset = 128.f - bounds.z(); + if (MWBase::Environment::get().getWorld()->isFlying(mCaster)) + offset /= 20.f; + pos.z() += offset * scale; + } + else + { + // Additionally use the NPC's height + osg::Vec3f npcScaleVec (1.f, 1.f, 1.f); + mCaster.getClass().adjustScale(mCaster, npcScaleVec, true); + scale *= npcScaleVec.z(); + } + scale = std::max(scale, 1.f); + MWBase::Environment::get().getWorld()->spawnEffect("meshes\\" + castStatic->mModel, effect->mParticle, pos, scale); } if (animation && !mCaster.getClass().isActor()) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b578ee25ba..a11d97779c 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include @@ -1655,12 +1654,21 @@ namespace MWRender parentNode = found->second; } - osg::ref_ptr trans = new osg::PositionAttitudeTransform; + osg::ref_ptr trans = new SceneUtil::PositionAttitudeTransform; if (!mPtr.getClass().isNpc()) { - osg::Vec3f bounds (MWBase::Environment::get().getWorld()->getHalfExtents(mPtr) * 2.f / Constants::UnitsPerFoot); - float scale = std::max({ bounds.x()/3.f, bounds.y()/3.f, bounds.z()/6.f }); - trans->setScale(osg::Vec3f(scale, scale, scale)); + osg::Vec3f bounds (MWBase::Environment::get().getWorld()->getHalfExtents(mPtr) * 2.f); + float scale = std::max({bounds.x(), bounds.y(), bounds.z() / 2.f}) / 64.f; + if (scale > 1.f) + trans->setScale(osg::Vec3f(scale, scale, scale)); + float offset = 0.f; + if (bounds.z() < 128.f) + offset = bounds.z() - 128.f; + else if (bounds.z() < bounds.x() + bounds.y()) + offset = 128.f - bounds.z(); + if (MWBase::Environment::get().getWorld()->isFlying(mPtr)) + offset /= 20.f; + trans->setPosition(osg::Vec3f(0.f, 0.f, offset * scale)); } parentNode->addChild(trans);