diff --git a/CHANGELOG.md b/CHANGELOG.md index c6c510fa16..d0965aea8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ Bug #3623: Fix HiDPI on Windows Bug #3733: Normal maps are inverted on mirrored UVs Bug #3765: DisableTeleporting makes Mark/Recall/Intervention effects undetectable + Bug #3778: [Mod] Improved Thrown Weapon Projectiles - weapons have wrong transformation during throw animation Bug #4329: Removed birthsign abilities are restored after reloading the save Bug #4383: Bow model obscures crosshair when arrow is drawn Bug #4384: Resist Normal Weapons only checks ammunition for ranged weapons diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 44a0f87ff4..d1f8562f4f 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -917,7 +917,10 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim if(mWeaponType != WeapType_None && mWeaponType != WeapType_Spell && mWeaponType != WeapType_HandToHand) { mAnimation->showWeapons(true); - mAnimation->setWeaponGroup(mCurrentWeapon); + // Note: controllers for ranged weapon should use time for beginning of animation to play shooting properly, + // for other weapons they should use absolute time. Some mods rely on this behaviour (to rotate throwing projectiles, for example) + bool useRelativeDuration = mWeaponType == WeapType_BowAndArrow || mWeaponType == WeapType_Crossbow; + mAnimation->setWeaponGroup(mCurrentWeapon, useRelativeDuration); } mAnimation->showCarriedLeft(updateCarriedLeftVisible(mWeaponType)); @@ -1375,7 +1378,10 @@ bool CharacterController::updateWeaponState(CharacterState& idle) mAnimation->showCarriedLeft(updateCarriedLeftVisible(weaptype)); getWeaponGroup(weaptype, weapgroup); - mAnimation->setWeaponGroup(weapgroup); + // Note: controllers for ranged weapon should use time for beginning of animation to play shooting properly, + // for other weapons they should use absolute time. Some mods rely on this behaviour (to rotate throwing projectiles, for example) + bool useRelativeDuration = weaptype == WeapType_BowAndArrow || weaptype == WeapType_Crossbow; + mAnimation->setWeaponGroup(weapgroup, useRelativeDuration); if (!isStillWeapon) { diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 153f2ead95..f638a4db79 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -457,7 +457,7 @@ public: virtual void showWeapons(bool showWeapon) {} virtual void showCarriedLeft(bool show) {} - virtual void setWeaponGroup(const std::string& group) {} + virtual void setWeaponGroup(const std::string& group, bool relativeDuration) {} virtual void setVampire(bool vampire) {} /// A value < 1 makes the animation translucent, 1.f = fully opaque void setAlpha(float alpha); diff --git a/apps/openmw/mwrender/creatureanimation.hpp b/apps/openmw/mwrender/creatureanimation.hpp index d0fd5bdb4f..5242725847 100644 --- a/apps/openmw/mwrender/creatureanimation.hpp +++ b/apps/openmw/mwrender/creatureanimation.hpp @@ -44,7 +44,7 @@ namespace MWRender virtual osg::Node* getWeaponNode(); virtual Resource::ResourceSystem* getResourceSystem(); virtual void showWeapon(bool show) { showWeapons(show); } - virtual void setWeaponGroup(const std::string& group) { mWeaponAnimationTime->setGroup(group); } + virtual void setWeaponGroup(const std::string& group, bool relativeDuration) { mWeaponAnimationTime->setGroup(group, relativeDuration); } virtual void addControllers(); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index a775f9391d..f1ebc80dfd 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -1030,9 +1030,9 @@ void NpcAnimation::enableHeadAnimation(bool enable) mHeadAnimationTime->setEnabled(enable); } -void NpcAnimation::setWeaponGroup(const std::string &group) +void NpcAnimation::setWeaponGroup(const std::string &group, bool relativeDuration) { - mWeaponAnimationTime->setGroup(group); + mWeaponAnimationTime->setGroup(group, relativeDuration); } void NpcAnimation::equipmentChanged() diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 1fbdd863cd..1ec0dfa591 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -117,7 +117,7 @@ public: /// 0: the first person meshes follow the camera with a reduced factor, so you can look down at your own hands virtual void setAccurateAiming(bool enabled); - virtual void setWeaponGroup(const std::string& group); + virtual void setWeaponGroup(const std::string& group, bool relativeDuration); virtual osg::Vec3f runAnimation(float timepassed); diff --git a/apps/openmw/mwrender/weaponanimation.cpp b/apps/openmw/mwrender/weaponanimation.cpp index d5a8cb10d9..1b51f04623 100644 --- a/apps/openmw/mwrender/weaponanimation.cpp +++ b/apps/openmw/mwrender/weaponanimation.cpp @@ -33,15 +33,20 @@ float WeaponAnimationTime::getValue(osg::NodeVisitor*) return current - mStartTime; } -void WeaponAnimationTime::setGroup(const std::string &group) +void WeaponAnimationTime::setGroup(const std::string &group, bool relativeTime) { mWeaponGroup = group; - mStartTime = mAnimation->getStartTime(mWeaponGroup); + mRelativeTime = relativeTime; + + if (mRelativeTime) + mStartTime = mAnimation->getStartTime(mWeaponGroup); + else + mStartTime = 0; } void WeaponAnimationTime::updateStartTime() { - setGroup(mWeaponGroup); + setGroup(mWeaponGroup, mRelativeTime); } WeaponAnimation::WeaponAnimation() diff --git a/apps/openmw/mwrender/weaponanimation.hpp b/apps/openmw/mwrender/weaponanimation.hpp index d50729c622..ece0beaa6c 100644 --- a/apps/openmw/mwrender/weaponanimation.hpp +++ b/apps/openmw/mwrender/weaponanimation.hpp @@ -17,9 +17,10 @@ namespace MWRender Animation* mAnimation; std::string mWeaponGroup; float mStartTime; + bool mRelativeTime; public: - WeaponAnimationTime(Animation* animation) : mAnimation(animation), mStartTime(0) {} - void setGroup(const std::string& group); + WeaponAnimationTime(Animation* animation) : mAnimation(animation), mStartTime(0), mRelativeTime(false) {} + void setGroup(const std::string& group, bool relativeTime); void updateStartTime(); virtual float getValue(osg::NodeVisitor* nv); diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 6e163b0d57..b13db3a3e5 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -3,7 +3,6 @@ #include #include -#include #include @@ -204,12 +203,6 @@ namespace MWWorld osg::ref_ptr projectile = mResourceSystem->getSceneManager()->getInstance(model, attachTo); - osg::ref_ptr boundVisitor = new osg::ComputeBoundsVisitor(); - projectile->accept(*boundVisitor.get()); - osg::BoundingBox bb = boundVisitor->getBoundingBox(); - - state.mNode->setPivotPoint(bb.center()); - if (state.mIdMagic.size() > 1) for (size_t iter = 1; iter != state.mIdMagic.size(); ++iter) { @@ -465,24 +458,14 @@ namespace MWWorld osg::Vec3f pos(it->mNode->getPosition()); osg::Vec3f newPos = pos + it->mVelocity * duration; - osg::Quat orient; - - if (it->mThrown) - orient.set( - osg::Matrixd::rotate(it->mEffectAnimationTime->getTime() * -10.0,osg::Vec3f(0,0,1)) * - osg::Matrixd::rotate(osg::PI / 2.0,osg::Vec3f(0,1,0)) * - osg::Matrixd::rotate(-1 * osg::PI / 2.0,osg::Vec3f(1,0,0)) * - osg::Matrixd::inverse( - osg::Matrixd::lookAt( - osg::Vec3f(0,0,0), - it->mVelocity, - osg::Vec3f(0,0,1)) - ) - ); - else + // rotation does not work well for throwing projectiles - their roll angle will depend on shooting direction. + if (!it->mThrown) + { + osg::Quat orient; orient.makeRotate(osg::Vec3f(0,1,0), it->mVelocity); + it->mNode->setAttitude(orient); + } - it->mNode->setAttitude(orient); it->mNode->setPosition(newPos); update(*it, duration);