From b8c60dabb3cc1d2e6c377d9807d5b1c654d6918b Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Tue, 1 Oct 2013 23:35:34 +0200 Subject: [PATCH 1/7] Reintroduce Acrobatics changes made by Glorf Advance Acrobatics skill on jump and on landing, apply fall damage on landing. --- apps/openmw/mwclass/npc.cpp | 28 ++++++++++++++++ apps/openmw/mwclass/npc.hpp | 3 ++ apps/openmw/mwmechanics/character.cpp | 47 ++++++++++++++++++++++++++- apps/openmw/mwmechanics/character.hpp | 3 ++ apps/openmw/mwworld/class.cpp | 5 +++ apps/openmw/mwworld/class.hpp | 3 ++ 6 files changed, 88 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 073d1b1b92..505c902db5 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -769,6 +769,34 @@ namespace MWClass return x; } + float Npc::getFallDamage(const MWWorld::Ptr &ptr, float fallHeight) const + { + const float fallDistanceMin = MWBase::Environment::get().getWorld()->getStore().get().find("fFallDamageDistanceMin")->getFloat(); + + if (fallHeight>=fallDistanceMin) + { + const float acrobaticsSkill = MWWorld::Class::get(ptr).getNpcStats (ptr).getSkill(ESM::Skill::Acrobatics).getModified(); + const CustomData *npcdata = static_cast(ptr.getRefData().getCustomData()); + const float jumpSpellBonus = npcdata->mNpcStats.getMagicEffects().get(MWMechanics::EffectKey(9/*jump*/)).mMagnitude; + const float fallAcroBase = MWBase::Environment::get().getWorld()->getStore().get().find("fFallAcroBase")->getFloat(); + const float fallAcroMult = MWBase::Environment::get().getWorld()->getStore().get().find("fFallAcroMult")->getFloat(); + const float fallDistanceBase = MWBase::Environment::get().getWorld()->getStore().get().find("fFallDistanceBase")->getFloat(); + const float fallDistanceMult = MWBase::Environment::get().getWorld()->getStore().get().find("fFallDistanceMult")->getFloat(); + + float x = fallHeight - fallDistanceMin; + x -= (1.5 * acrobaticsSkill) + jumpSpellBonus; + x = std::max(0.0f, x); + + float a = fallAcroBase + fallAcroMult * (100 - acrobaticsSkill); + x = fallDistanceBase + fallDistanceMult * x; + x *= a; + + return x; + } + + return 0; + } + MWMechanics::Movement& Npc::getMovementSettings (const MWWorld::Ptr& ptr) const { ensureCustomData (ptr); diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 3591d7c688..c39ca42ef4 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -97,6 +97,9 @@ namespace MWClass virtual float getJump(const MWWorld::Ptr &ptr) const; ///< Return jump velocity (not accounting for movement) + virtual float getFallDamage(const MWWorld::Ptr &ptr, float fallHeight) const; + ///< Return amount of health points lost when falling + virtual MWMechanics::Movement& getMovementSettings (const MWWorld::Ptr& ptr) const; ///< Return desired movement. diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ec2bb1b59e..2753b09c21 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -767,10 +767,17 @@ void CharacterController::update(float duration) } if(sneak || inwater || flying) + { vec.z = 0.0f; + mFallHeight = 0.0f; + } if(!onground && !flying && !inwater) { + // The player is in the air (either getting up —ascending part of jump— or falling). + + mFallHeight = std::max(mFallHeight, mPtr.getRefData().getPosition().pos[2]); + const MWWorld::Store &gmst = world->getStore().get(); forcestateupdate = (mJumpState != JumpState_Falling); @@ -794,6 +801,8 @@ void CharacterController::update(float duration) } else if(vec.z > 0.0f && mJumpState == JumpState_None) { + // The player has started a jump. + float z = cls.getJump(mPtr); if(vec.x == 0 && vec.y == 0) vec = Ogre::Vector3(0.0f, 0.0f, z); @@ -803,13 +812,49 @@ void CharacterController::update(float duration) vec = Ogre::Vector3(lat.x, lat.y, 1.0f) * z * 0.707f; } - //decrease fatigue by fFatigueJumpBase + (1 - normalizedEncumbrance) * fFatigueJumpMult; + // advance acrobatics + MWWorld::Class::get(mPtr).skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 0); + + // decrease fatigue + const float fatigueJumpBase = MWBase::Environment::get().getWorld()->getStore().get().find("fFatigueJumpBase")->getFloat(); + const float fatigueJumpMult = MWBase::Environment::get().getWorld()->getStore().get().find("fFatigueJumpMult")->getFloat(); + const float normalizedEncumbrance = cls.getEncumbrance(mPtr) / cls.getCapacity(mPtr); + const int fatigueDecrease = fatigueJumpBase + (1 - normalizedEncumbrance) * fatigueJumpMult; + DynamicStat fatigue = cls.getCreatureStats(mPtr).getDynamic(2); + fatigue.setModified(fatigue.getModified() - fatigueDecrease, 0); + fatigue.setCurrent(fatigue.getCurrent() - fatigueDecrease); + cls.getCreatureStats(mPtr).setDynamic(2, fatigue); } else if(mJumpState == JumpState_Falling) { + // The player is landing. + forcestateupdate = true; mJumpState = JumpState_Landing; vec.z = 0.0f; + + float healthLost = cls.getFallDamage(mPtr, mFallHeight - mPtr.getRefData().getPosition().pos[2]); + if (healthLost > 0.0f) + { + // inflict fall damages + DynamicStat health = cls.getCreatureStats(mPtr).getHealth(); + int current = health.getCurrent(); + int realHealthLost = healthLost * (1.0f - 0.25 * 1.25f /* * fatigueTerm */); + health.setModified(health.getModified() - realHealthLost, 0); + health.setCurrent(current - realHealthLost); + cls.getCreatureStats(mPtr).setHealth(health); + + // report acrobatics progression + cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 1); + + const float acrobaticsSkill = cls.getNpcStats(mPtr).getSkill(ESM::Skill::Acrobatics).getModified(); + if (healthLost > (acrobaticsSkill * 1.25f /* * fatigueTerm */)) + { + //TODO: actor falls over + } + } + + mFallHeight = 0; } else { diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index c943b95977..7b9dda49aa 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -154,6 +154,9 @@ class CharacterController float mSecondsOfSwimming; float mSecondsOfRunning; + // used for acrobatics progress and fall damages + float mFallHeight; + std::string mAttackType; // slash, chop or thrust void refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force=false); diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index c739ea831c..de50935471 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -167,6 +167,11 @@ namespace MWWorld throw std::runtime_error ("class does not support enchanting"); } + float Class::getFallDamage(const MWWorld::Ptr &ptr, float fallHeight) const + { + return 0; + } + MWMechanics::Movement& Class::getMovementSettings (const Ptr& ptr) const { throw std::runtime_error ("movement settings not supported by class"); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 28e37cbf3c..1db09647e4 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -175,6 +175,9 @@ namespace MWWorld virtual float getJump(const MWWorld::Ptr &ptr) const; ///< Return jump velocity (not accounting for movement) + virtual float getFallDamage(const MWWorld::Ptr &ptr, float fallHeight) const; + ///< Return amount of health points lost when falling + virtual MWMechanics::Movement& getMovementSettings (const Ptr& ptr) const; ///< Return desired movement. From 486051486599e80bc0731252a7191095226b1eaf Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Wed, 2 Oct 2013 12:58:34 +0200 Subject: [PATCH 2/7] Acrobatics: cosmetic changes --- apps/openmw/mwclass/npc.cpp | 18 +++++++++++------- apps/openmw/mwmechanics/character.cpp | 14 +++++++------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 505c902db5..0110bef88e 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -7,6 +7,7 @@ #include +#include #include #include "../mwbase/environment.hpp" @@ -771,17 +772,20 @@ namespace MWClass float Npc::getFallDamage(const MWWorld::Ptr &ptr, float fallHeight) const { - const float fallDistanceMin = MWBase::Environment::get().getWorld()->getStore().get().find("fFallDamageDistanceMin")->getFloat(); + MWBase::World *world = MWBase::Environment::get().getWorld(); + const MWWorld::Store &gmst = world->getStore().get(); + + const float fallDistanceMin = gmst.find("fFallDamageDistanceMin")->getFloat(); - if (fallHeight>=fallDistanceMin) + if (fallHeight >= fallDistanceMin) { const float acrobaticsSkill = MWWorld::Class::get(ptr).getNpcStats (ptr).getSkill(ESM::Skill::Acrobatics).getModified(); const CustomData *npcdata = static_cast(ptr.getRefData().getCustomData()); - const float jumpSpellBonus = npcdata->mNpcStats.getMagicEffects().get(MWMechanics::EffectKey(9/*jump*/)).mMagnitude; - const float fallAcroBase = MWBase::Environment::get().getWorld()->getStore().get().find("fFallAcroBase")->getFloat(); - const float fallAcroMult = MWBase::Environment::get().getWorld()->getStore().get().find("fFallAcroMult")->getFloat(); - const float fallDistanceBase = MWBase::Environment::get().getWorld()->getStore().get().find("fFallDistanceBase")->getFloat(); - const float fallDistanceMult = MWBase::Environment::get().getWorld()->getStore().get().find("fFallDistanceMult")->getFloat(); + const float jumpSpellBonus = npcdata->mNpcStats.getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::Jump)).mMagnitude; + const float fallAcroBase = gmst.find("fFallAcroBase")->getFloat(); + const float fallAcroMult = gmst.find("fFallAcroMult")->getFloat(); + const float fallDistanceBase = gmst.find("fFallDistanceBase")->getFloat(); + const float fallDistanceMult = gmst.find("fFallDistanceMult")->getFloat(); float x = fallHeight - fallDistanceMin; x -= (1.5 * acrobaticsSkill) + jumpSpellBonus; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 2753b09c21..efd3b94cc2 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -813,17 +813,18 @@ void CharacterController::update(float duration) } // advance acrobatics - MWWorld::Class::get(mPtr).skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 0); + cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 0); // decrease fatigue - const float fatigueJumpBase = MWBase::Environment::get().getWorld()->getStore().get().find("fFatigueJumpBase")->getFloat(); - const float fatigueJumpMult = MWBase::Environment::get().getWorld()->getStore().get().find("fFatigueJumpMult")->getFloat(); + const MWWorld::Store &gmst = world->getStore().get(); + const float fatigueJumpBase = gmst.find("fFatigueJumpBase")->getFloat(); + const float fatigueJumpMult = gmst.find("fFatigueJumpMult")->getFloat(); const float normalizedEncumbrance = cls.getEncumbrance(mPtr) / cls.getCapacity(mPtr); const int fatigueDecrease = fatigueJumpBase + (1 - normalizedEncumbrance) * fatigueJumpMult; - DynamicStat fatigue = cls.getCreatureStats(mPtr).getDynamic(2); + DynamicStat fatigue = cls.getCreatureStats(mPtr).getFatigue(); fatigue.setModified(fatigue.getModified() - fatigueDecrease, 0); fatigue.setCurrent(fatigue.getCurrent() - fatigueDecrease); - cls.getCreatureStats(mPtr).setDynamic(2, fatigue); + cls.getCreatureStats(mPtr).setFatigue(fatigue); } else if(mJumpState == JumpState_Falling) { @@ -838,10 +839,9 @@ void CharacterController::update(float duration) { // inflict fall damages DynamicStat health = cls.getCreatureStats(mPtr).getHealth(); - int current = health.getCurrent(); int realHealthLost = healthLost * (1.0f - 0.25 * 1.25f /* * fatigueTerm */); health.setModified(health.getModified() - realHealthLost, 0); - health.setCurrent(current - realHealthLost); + health.setCurrent(health.getCurrent() - realHealthLost); cls.getCreatureStats(mPtr).setHealth(health); // report acrobatics progression From 4c151e59a26caed2d77d1f74e446472b3e78863c Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Wed, 2 Oct 2013 13:00:47 +0200 Subject: [PATCH 3/7] Acrobatics: do not touch modified stats --- apps/openmw/mwmechanics/character.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index efd3b94cc2..14eed2641a 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -822,7 +822,6 @@ void CharacterController::update(float duration) const float normalizedEncumbrance = cls.getEncumbrance(mPtr) / cls.getCapacity(mPtr); const int fatigueDecrease = fatigueJumpBase + (1 - normalizedEncumbrance) * fatigueJumpMult; DynamicStat fatigue = cls.getCreatureStats(mPtr).getFatigue(); - fatigue.setModified(fatigue.getModified() - fatigueDecrease, 0); fatigue.setCurrent(fatigue.getCurrent() - fatigueDecrease); cls.getCreatureStats(mPtr).setFatigue(fatigue); } @@ -840,7 +839,6 @@ void CharacterController::update(float duration) // inflict fall damages DynamicStat health = cls.getCreatureStats(mPtr).getHealth(); int realHealthLost = healthLost * (1.0f - 0.25 * 1.25f /* * fatigueTerm */); - health.setModified(health.getModified() - realHealthLost, 0); health.setCurrent(health.getCurrent() - realHealthLost); cls.getCreatureStats(mPtr).setHealth(health); From 2b992ef3b5e8dd27c5b4edee3e98323be230079e Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Wed, 2 Oct 2013 13:02:14 +0200 Subject: [PATCH 4/7] Acrobatics: use calculated fatigueTerm --- apps/openmw/mwmechanics/character.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 14eed2641a..5b4d316e51 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -836,9 +836,11 @@ void CharacterController::update(float duration) float healthLost = cls.getFallDamage(mPtr, mFallHeight - mPtr.getRefData().getPosition().pos[2]); if (healthLost > 0.0f) { + const float fatigueTerm = cls.getCreatureStats(mPtr).getFatigueTerm(); + // inflict fall damages DynamicStat health = cls.getCreatureStats(mPtr).getHealth(); - int realHealthLost = healthLost * (1.0f - 0.25 * 1.25f /* * fatigueTerm */); + int realHealthLost = healthLost * (1.0f - 0.25 * fatigueTerm); health.setCurrent(health.getCurrent() - realHealthLost); cls.getCreatureStats(mPtr).setHealth(health); @@ -846,7 +848,7 @@ void CharacterController::update(float duration) cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 1); const float acrobaticsSkill = cls.getNpcStats(mPtr).getSkill(ESM::Skill::Acrobatics).getModified(); - if (healthLost > (acrobaticsSkill * 1.25f /* * fatigueTerm */)) + if (healthLost > (acrobaticsSkill * fatigueTerm)) { //TODO: actor falls over } From 6e09a5fb4af2ac97330020f92172c5a712b84356 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Wed, 2 Oct 2013 22:36:28 +0200 Subject: [PATCH 5/7] Acrobatics: reinit fall height at current height rather than zero To prevent problems. --- apps/openmw/mwmechanics/character.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 5b4d316e51..0924e36b9a 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -769,7 +769,7 @@ void CharacterController::update(float duration) if(sneak || inwater || flying) { vec.z = 0.0f; - mFallHeight = 0.0f; + mFallHeight = mPtr.getRefData().getPosition().pos[2]; } if(!onground && !flying && !inwater) @@ -854,7 +854,7 @@ void CharacterController::update(float duration) } } - mFallHeight = 0; + mFallHeight = mPtr.getRefData().getPosition().pos[2]; } else { From 4265dddc40923d1fbcdbb848a0e06a5df4e66308 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Wed, 2 Oct 2013 22:53:29 +0200 Subject: [PATCH 6/7] Add MWWorld::isSlowFalling(Ptr) --- apps/openmw/mwbase/world.hpp | 1 + apps/openmw/mwworld/worldimp.cpp | 13 +++++++++++++ apps/openmw/mwworld/worldimp.hpp | 1 + 3 files changed, 15 insertions(+) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index f8453afed6..db03cb7bf8 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -324,6 +324,7 @@ namespace MWBase virtual void processChangedSettings (const Settings::CategorySettingVector& settings) = 0; virtual bool isFlying(const MWWorld::Ptr &ptr) const = 0; + virtual bool isSlowFalling(const MWWorld::Ptr &ptr) const = 0; virtual bool isSwimming(const MWWorld::Ptr &object) const = 0; ///Is the head of the creature underwater? virtual bool isSubmerged(const MWWorld::Ptr &object) const = 0; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f3d4c81b76..34ac011027 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1582,6 +1582,19 @@ namespace MWWorld return false; } + bool + World::isSlowFalling(const MWWorld::Ptr &ptr) const + { + if(!ptr.getClass().isActor()) + return false; + + const MWMechanics::CreatureStats &stats = ptr.getClass().getCreatureStats(ptr); + if(stats.getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::SlowFall)).mMagnitude > 0) + return true; + + return false; + } + bool World::isSubmerged(const MWWorld::Ptr &object) const { float *fpos = object.getRefData().getPosition().pos; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 53b01f1abf..333beb8314 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -355,6 +355,7 @@ namespace MWWorld virtual void processChangedSettings(const Settings::CategorySettingVector& settings); virtual bool isFlying(const MWWorld::Ptr &ptr) const; + virtual bool isSlowFalling(const MWWorld::Ptr &ptr) const; ///Is the head of the creature underwater? virtual bool isSubmerged(const MWWorld::Ptr &object) const; virtual bool isSwimming(const MWWorld::Ptr &object) const; From 2abe5c1c9a304bae549d4591f0c11ccd84286c9b Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Wed, 2 Oct 2013 22:54:36 +0200 Subject: [PATCH 7/7] Acrobatics: do not apply fall damages when slowfalling spell effect is active If spell effect ends up in mid-air, calculate fall height from then. --- apps/openmw/mwmechanics/character.cpp | 10 +++++++++- apps/openmw/mwmechanics/character.hpp | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 0924e36b9a..c4260d907d 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -776,7 +776,15 @@ void CharacterController::update(float duration) { // The player is in the air (either getting up —ascending part of jump— or falling). - mFallHeight = std::max(mFallHeight, mPtr.getRefData().getPosition().pos[2]); + if (world->isSlowFalling(mPtr)) + { + // SlowFalling spell effect is active, do not keep previous fall height + mFallHeight = mPtr.getRefData().getPosition().pos[2]; + } + else + { + mFallHeight = std::max(mFallHeight, mPtr.getRefData().getPosition().pos[2]); + } const MWWorld::Store &gmst = world->getStore().get(); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 7b9dda49aa..8670b385e3 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -3,6 +3,8 @@ #include +#include + #include "../mwworld/ptr.hpp" namespace MWWorld