Implement actors movement deceleration (feature #4544)

pull/556/head
Andrei Kortunov 5 years ago
parent 1aa4cc3388
commit 61ab7f3c1e

@ -184,6 +184,7 @@
Feature #4255: Handle broken RepairedOnMe script function
Feature #4316: Implement RaiseRank/LowerRank functions properly
Feature #4360: Improve default controller bindings
Feature #4544: Actors movement deceleration
Feature #4673: Weapon sheathing
Feature #4675: Support for NiRollController
Feature #4730: Native animated containers support

@ -556,6 +556,8 @@ namespace MWClass
if(getMovementSettings(ptr).mPosition[0] != 0 && getMovementSettings(ptr).mPosition[1] == 0)
moveSpeed *= 0.75f;
moveSpeed *= ptr.getClass().getMovementSettings(ptr).mSpeedFactor;
return moveSpeed;
}

@ -990,6 +990,8 @@ namespace MWClass
if(npcdata->mNpcStats.isWerewolf() && running && npcdata->mNpcStats.getDrawState() == MWMechanics::DrawState_Nothing)
moveSpeed *= gmst.fWereWolfRunMult->mValue.getFloat();
moveSpeed *= ptr.getClass().getMovementSettings(ptr).mSpeedFactor;
return moveSpeed;
}

@ -144,6 +144,7 @@ namespace MWMechanics
{
static const int GREETING_SHOULD_START = 4; //how many updates should pass before NPC can greet player
static const int GREETING_SHOULD_END = 10;
static const float DECELERATE_DISTANCE = 512.f;
class GetStuntedMagickaDuration : public MWMechanics::EffectSourceVisitor
{
@ -422,6 +423,26 @@ namespace MWMechanics
MWBase::Environment::get().getDialogueManager()->say(actor, "idle");
}
void Actors::updateMovementSpeed(const MWWorld::Ptr& actor)
{
float previousSpeedFactor = actor.getClass().getMovementSettings(actor).mSpeedFactor;
float newSpeedFactor = 1.f;
CreatureStats &stats = actor.getClass().getCreatureStats(actor);
MWMechanics::AiSequence& seq = stats.getAiSequence();
if (!seq.isEmpty() && seq.getActivePackage()->useVariableSpeed())
{
osg::Vec3f targetPos = seq.getActivePackage()->getDestination();
osg::Vec3f actorPos = actor.getRefData().getPosition().asVec3();
float distance = (targetPos - actorPos).length();
if (distance < DECELERATE_DISTANCE)
newSpeedFactor = std::max(0.7f, 0.1f * previousSpeedFactor * (distance/64.f + 2.f));
}
actor.getClass().getMovementSettings(actor).mSpeedFactor = newSpeedFactor;
}
void Actors::updateGreetingState(const MWWorld::Ptr& actor, bool turnOnly)
{
if (!actor.getClass().isActor() || actor == getPlayer())
@ -1668,6 +1689,7 @@ namespace MWMechanics
stats.getAiSequence().execute(iter->first, *ctrl, duration);
updateGreetingState(iter->first, timerUpdateHello > 0);
playIdleDialogue(iter->first);
updateMovementSpeed(iter->first);
}
}
}

@ -121,6 +121,7 @@ namespace MWMechanics
void engageCombat(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, std::map<const MWWorld::Ptr, const std::set<MWWorld::Ptr> >& cachedAllies, bool againstPlayer);
void playIdleDialogue(const MWWorld::Ptr& actor);
void updateMovementSpeed(const MWWorld::Ptr& actor);
void updateGreetingState(const MWWorld::Ptr& actor, bool turnOnly);
void turnActorToFacePlayer(const MWWorld::Ptr& actor, const osg::Vec3f& dir);

@ -36,12 +36,16 @@ namespace MWMechanics
virtual int getTypeId() const;
virtual bool useVariableSpeed() const { return true;}
virtual bool sideWithTarget() const { return true; }
void writeState(ESM::AiSequence::AiSequence &sequence) const;
void fastForward(const MWWorld::Ptr& actor, AiState& state);
virtual osg::Vec3f getDestination() { return osg::Vec3f(mX, mY, mZ); }
private:
std::string mCellId;
float mX;

@ -7,6 +7,8 @@
#include <components/esm/defs.hpp>
#include "../mwworld/ptr.hpp"
#include "pathfinding.hpp"
namespace ESM
@ -61,6 +63,8 @@ namespace MWMechanics
virtual int getTypeId() const;
virtual bool useVariableSpeed() const { return true;}
/// Returns the actor being followed
std::string getFollowedActor();
@ -72,6 +76,15 @@ namespace MWMechanics
void fastForward(const MWWorld::Ptr& actor, AiState& state);
virtual osg::Vec3f getDestination()
{
MWWorld::Ptr target = getTarget();
if (target.isEmpty())
return osg::Vec3f(0, 0, 0);
return target.getRefData().getPosition().asVec3();
}
private:
/// This will make the actor always follow.
/** Thus ignoring mDuration and mX,mY,mZ (used for summoned creatures). **/

@ -73,6 +73,9 @@ namespace MWMechanics
/// Higher number is higher priority (0 being the lowest)
virtual unsigned int getPriority() const {return 0;}
/// Check if package use movement with variable speed
virtual bool useVariableSpeed() const { return false;}
virtual void writeState (ESM::AiSequence::AiSequence& sequence) const {}
/// Simulates the passing of time
@ -99,6 +102,8 @@ namespace MWMechanics
/// Return true if this package should repeat. Currently only used for Wander packages.
virtual bool getRepeat() const;
virtual osg::Vec3f getDestination() { return osg::Vec3f(0, 0, 0); }
/// Reset pathfinding state
void reset();

@ -388,6 +388,11 @@ void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor, boo
}
}
bool MWMechanics::AiSequence::isEmpty() const
{
return mPackages.empty();
}
AiPackage* MWMechanics::AiSequence::getActivePackage()
{
if(mPackages.empty())

@ -132,6 +132,8 @@ namespace MWMechanics
\see ESM::AIPackageList **/
void fill (const ESM::AIPackageList& list);
bool isEmpty() const;
void writeState (ESM::AiSequence::AiSequence& sequence) const;
void readState (const ESM::AiSequence::AiSequence& sequence);
};

@ -32,6 +32,10 @@ namespace MWMechanics
virtual int getTypeId() const;
virtual bool useVariableSpeed() const { return true;}
virtual osg::Vec3f getDestination() { return osg::Vec3f(mX, mY, mZ); }
private:
float mX;
float mY;

@ -10,11 +10,13 @@ namespace MWMechanics
{
float mPosition[3];
float mRotation[3];
float mSpeedFactor;
Movement()
{
mPosition[0] = mPosition[1] = mPosition[2] = 0.0f;
mRotation[0] = mRotation[1] = mRotation[2] = 0.0f;
mSpeedFactor = 1.f;
}
osg::Vec3f asVec3()

Loading…
Cancel
Save