From 4c285151a3789105489259f3b01e5114a9a5d3a0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 16 Sep 2014 02:38:49 +0200 Subject: [PATCH 1/6] Fix incorrect movement animation for some creatures (Fixes #1924) --- apps/openmw/mwmechanics/character.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 825d77869..249cb13bf 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -258,6 +258,8 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat } const WeaponInfo *weap = std::find_if(sWeaponTypeList, sWeaponTypeListEnd, FindWeaponType(mWeaponType)); + if (!mPtr.getClass().hasInventoryStore(mPtr)) + weap = sWeaponTypeListEnd; if(force || idle != mIdleState) { From b6a89c78453e8d51ca7130351413fc18e766bd9d Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 16 Sep 2014 03:01:48 +0200 Subject: [PATCH 2/6] Fix idlestorm animation conflict with torch animation --- apps/openmw/mwmechanics/character.cpp | 6 +++--- apps/openmw/mwmechanics/character.hpp | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 249cb13bf..566ca77aa 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -668,10 +668,10 @@ void CharacterController::updateIdleStormState() mAnimation->getInfo("idlestorm", &complete); if (complete == 0) - mAnimation->play("idlestorm", Priority_Torch, MWRender::Animation::Group_RightArm, false, + mAnimation->play("idlestorm", Priority_Storm, MWRender::Animation::Group_RightArm, false, 1.0f, "start", "loop start", 0.0f, 0); else if (complete == 1) - mAnimation->play("idlestorm", Priority_Torch, MWRender::Animation::Group_RightArm, false, + mAnimation->play("idlestorm", Priority_Storm, MWRender::Animation::Group_RightArm, false, 1.0f, "loop start", "loop stop", 0.0f, ~0ul); } else @@ -682,7 +682,7 @@ void CharacterController::updateIdleStormState() { if (mAnimation->getCurrentTime("idlestorm") < mAnimation->getTextKeyTime("idlestorm: loop stop")) { - mAnimation->play("idlestorm", Priority_Torch, MWRender::Animation::Group_RightArm, true, + mAnimation->play("idlestorm", Priority_Storm, MWRender::Animation::Group_RightArm, true, 1.0f, "loop stop", "stop", 0.0f, 0); } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 12a68970b..d09d2df52 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -32,6 +32,7 @@ enum Priority { Priority_Weapon, Priority_Knockdown, Priority_Torch, + Priority_Storm, Priority_Death, From 269c200c8f5e659189579c2b93e91d2a93e609ac Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 16 Sep 2014 03:15:04 +0200 Subject: [PATCH 3/6] Fix jump velocity mechanics (Fixes #1708) --- apps/openmw/mwmechanics/character.cpp | 38 +++++++++------------------ apps/openmw/mwworld/physicssystem.cpp | 20 +++++++------- 2 files changed, 24 insertions(+), 34 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 566ca77aa..cba51b835 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1277,15 +1277,7 @@ void CharacterController::update(float duration) //Ogre::Vector3 vec = cls.getMovementVector(mPtr); Ogre::Vector3 vec(cls.getMovementSettings(mPtr).mPosition); - if(vec.z > 0.0f) // to avoid slow-down when jumping - { - Ogre::Vector2 vecXY = Ogre::Vector2(vec.x, vec.y); - vecXY.normalise(); - vec.x = vecXY.x; - vec.y = vecXY.y; - } - else - vec.normalise(); + vec.normalise(); if(mHitState != CharState_None && mJumpState == JumpState_None) vec = Ogre::Vector3(0.0f); @@ -1383,28 +1375,24 @@ void CharacterController::update(float duration) mJumpState = JumpState_Falling; // This is a guess. All that seems to be known is that "While the player is in the - // air, fJumpMoveBase and fJumpMoveMult governs air control." Assuming Acrobatics - // plays a role, this makes the most sense. - float mult = 0.0f; - if(cls.isNpc()) - { - const NpcStats &stats = cls.getNpcStats(mPtr); - static const float fJumpMoveBase = gmst.find("fJumpMoveBase")->getFloat(); - static const float fJumpMoveMult = gmst.find("fJumpMoveMult")->getFloat(); + // air, fJumpMoveBase and fJumpMoveMult governs air control". What does fJumpMoveMult do? + static const float fJumpMoveBase = gmst.find("fJumpMoveBase")->getFloat(); - mult = fJumpMoveBase + - (stats.getSkill(ESM::Skill::Acrobatics).getModified()/100.0f * - fJumpMoveMult); - } - - vec.x *= mult; - vec.y *= mult; + vec.x *= fJumpMoveBase; + vec.y *= fJumpMoveBase; vec.z = 0.0f; } else if(vec.z > 0.0f && mJumpState == JumpState_None) { // Started a jump. - vec.z = cls.getJump(mPtr); + float z = cls.getJump(mPtr); + if(vec.x == 0 && vec.y == 0) + vec = Ogre::Vector3(0.0f, 0.0f, z); + else + { + Ogre::Vector3 lat = Ogre::Vector3(vec.x, vec.y, 0.0f).normalisedCopy(); + vec = Ogre::Vector3(lat.x, lat.y, 1.0f) * z * 0.707f; + } // advance acrobatics if (mPtr.getRefData().getHandle() == "player") diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 51aae2bc3..5a28e4460 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -299,18 +299,20 @@ namespace MWWorld // not in water nor can fly, so need to deal with gravity if(!physicActor->getOnGround()) // if current OnGround status is false, must be falling or jumping { - // If falling, add part of the incoming velocity with the current inertia - // TODO: but we could be jumping up? - velocity = velocity * time + physicActor->getInertialForce(); - - // avoid getting infinite inertia in air + // If falling or jumping up, add part of the incoming velocity with the current inertia, + // but don't allow increasing inertia beyond actor's speed (except on the initial jump impulse) float actorSpeed = ptr.getClass().getSpeed(ptr); - float speedXY = Ogre::Vector2(velocity.x, velocity.y).length(); - if (speedXY > actorSpeed) + float cap = std::max(actorSpeed, Ogre::Vector2(physicActor->getInertialForce().x, physicActor->getInertialForce().y).length()); + Ogre::Vector3 newVelocity = velocity + physicActor->getInertialForce(); + if (Ogre::Vector2(newVelocity.x, newVelocity.y).squaredLength() > cap*cap) { - velocity.x *= actorSpeed / speedXY; - velocity.y *= actorSpeed / speedXY; + velocity = newVelocity; + float speedXY = Ogre::Vector2(velocity.x, velocity.y).length(); + velocity.x *= cap / speedXY; + velocity.y *= cap / speedXY; } + else + velocity = newVelocity; } inertia = velocity; // NOTE: velocity is for z axis only in this code block From 6debd21ec6f989ab8b36743aa6c187faf0aa2b4d Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 17 Sep 2014 02:20:46 +0200 Subject: [PATCH 4/6] Make sure the Jump control is always handled by the PhysicsSystem even if game runs faster than the minimum physics timestep --- apps/openmw/mwmechanics/character.cpp | 13 +++++++------ apps/openmw/mwmechanics/character.hpp | 2 +- apps/openmw/mwworld/physicssystem.cpp | 3 +++ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index cba51b835..104c2bae3 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -310,7 +310,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat } } - if(mJumpState == JumpState_Falling) + if(mJumpState == JumpState_InAir) { int mode = ((jump == mCurrentJump) ? 2 : 1); @@ -1275,7 +1275,6 @@ void CharacterController::update(float duration) } } - //Ogre::Vector3 vec = cls.getMovementVector(mPtr); Ogre::Vector3 vec(cls.getMovementSettings(mPtr).mPosition); vec.normalise(); @@ -1371,8 +1370,8 @@ void CharacterController::update(float duration) cls.getCreatureStats(mPtr).land(); } - forcestateupdate = (mJumpState != JumpState_Falling); - mJumpState = JumpState_Falling; + forcestateupdate = (mJumpState != JumpState_InAir); + mJumpState = JumpState_InAir; // This is a guess. All that seems to be known is that "While the player is in the // air, fJumpMoveBase and fJumpMoveMult governs air control". What does fJumpMoveMult do? @@ -1408,7 +1407,7 @@ void CharacterController::update(float duration) fatigue.setCurrent(fatigue.getCurrent() - fatigueDecrease); cls.getCreatureStats(mPtr).setFatigue(fatigue); } - else if(mJumpState == JumpState_Falling) + else if(mJumpState == JumpState_InAir) { forcestateupdate = true; mJumpState = JumpState_Landing; @@ -1529,7 +1528,9 @@ void CharacterController::update(float duration) world->queueMovement(mPtr, Ogre::Vector3(0.0f)); movement = vec; - cls.getMovementSettings(mPtr).mPosition[0] = cls.getMovementSettings(mPtr).mPosition[1] = cls.getMovementSettings(mPtr).mPosition[2] = 0; + cls.getMovementSettings(mPtr).mPosition[0] = cls.getMovementSettings(mPtr).mPosition[1] = 0; + // Can't reset jump state (mPosition[2]) here; we don't know for sure whether the PhysicSystem will actually handle it in this frame + // due to the fixed minimum timestep used for the physics update. It will be reset in PhysicSystem::move once the jump is handled. } else if(cls.getCreatureStats(mPtr).isDead()) { diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index d09d2df52..6528c041f 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -130,7 +130,7 @@ enum UpperBodyCharacterState { enum JumpingState { JumpState_None, - JumpState_Falling, + JumpState_InAir, JumpState_Landing }; diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 5a28e4460..31d52e39d 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -23,6 +23,7 @@ #include "../mwbase/environment.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/movement.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/cellstore.hpp" @@ -296,6 +297,7 @@ namespace MWWorld else { velocity = Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * movement; + // not in water nor can fly, so need to deal with gravity if(!physicActor->getOnGround()) // if current OnGround status is false, must be falling or jumping { @@ -333,6 +335,7 @@ namespace MWWorld } } } + ptr.getClass().getMovementSettings(ptr).mPosition[2] = 0; // Now that we have the effective movement vector, apply wind forces to it if (MWBase::Environment::get().getWorld()->isInStorm()) From 3ce3f31452fa271e9297079fb50f66238f42bf10 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 17 Sep 2014 05:20:10 +0200 Subject: [PATCH 5/6] Adjust turning animation speed multiplier based on turning speed --- apps/openmw/mwmechanics/character.cpp | 18 +++++++++++++++++- apps/openmw/mwmechanics/character.hpp | 2 ++ apps/openmw/mwrender/animation.cpp | 7 +++++++ apps/openmw/mwrender/animation.hpp | 4 ++++ 4 files changed, 30 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 104c2bae3..fe316b768 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -416,7 +416,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat speedmult = mMovementSpeed / vel; } else if (mMovementState == CharState_TurnLeft || mMovementState == CharState_TurnRight) - speedmult = 1.f; // TODO: should get a speed mult depending on the current turning speed + speedmult = 1.f; // adjusted each frame else if (mMovementSpeed > 0.0f) { // The first person anims don't have any velocity to calculate a speed multiplier from. @@ -592,6 +592,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim , mSkipAnim(false) , mSecondsOfRunning(0) , mSecondsOfSwimming(0) + , mTurnAnimationThreshold(0) { if(!mAnimation) return; @@ -1480,6 +1481,15 @@ void CharacterController::update(float duration) } } + mTurnAnimationThreshold -= duration; + if (movestate == CharState_TurnRight || movestate == CharState_TurnLeft) + mTurnAnimationThreshold = 0.05; + else if (movestate == CharState_None && (mMovementState == CharState_TurnRight || mMovementState == CharState_TurnLeft) + && mTurnAnimationThreshold > 0) + { + movestate = mMovementState; + } + if (onground) cls.getCreatureStats(mPtr).land(); @@ -1510,6 +1520,12 @@ void CharacterController::update(float duration) if (inJump) mMovementAnimationControlled = false; + if (mMovementState == CharState_TurnLeft || mMovementState == CharState_TurnRight) + { + if (duration > 0) + mAnimation->adjustSpeedMult(mCurrentMovement, std::min(1.5f, std::abs(rot.z) / duration / Ogre::Math::PI)); + } + if (!mSkipAnim) { rot *= Ogre::Math::RadiansToDegrees(1.0f); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 6528c041f..550cae5fc 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -171,6 +171,8 @@ class CharacterController float mSecondsOfSwimming; float mSecondsOfRunning; + float mTurnAnimationThreshold; // how long to continue playing turning animation after actor stopped turning + std::string mAttackType; // slash, chop or thrust void determineAttackType(); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 81b92dcbf..e2f3ce62f 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -914,6 +914,13 @@ void Animation::play(const std::string &groupname, int priority, int groups, boo } } +void Animation::adjustSpeedMult(const std::string &groupname, float speedmult) +{ + AnimStateMap::iterator state(mStates.find(groupname)); + if(state != mStates.end()) + state->second.mSpeedMult = speedmult; +} + bool Animation::isPlaying(const std::string &groupname) const { AnimStateMap::const_iterator state(mStates.find(groupname)); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 4f53a737b..8ca3582dc 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -260,6 +260,10 @@ public: float speedmult, const std::string &start, const std::string &stop, float startpoint, size_t loops); + /** Adjust the speed multiplier of an already playing animation. + */ + void adjustSpeedMult (const std::string& groupname, float speedmult); + /** Returns true if the named animation group is playing. */ bool isPlaying(const std::string &groupname) const; From 441073b475c05b8300735f03a203cc565de4add1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 17 Sep 2014 06:53:30 +0200 Subject: [PATCH 6/6] Remove ancient comment --- apps/openmw/mwworld/worldimp.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index e62ee72c3..425fa20e5 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -162,7 +162,6 @@ namespace MWWorld mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); - // NOTE: We might need to reserve one more for the running game / save. mEsm.resize(contentFiles.size()); Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); listener->loadingOn();