mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-30 13:15:34 +00:00
Filter evade directions by supported animations
To avoid trying those which will not lead to any actor movement due to absent animation.
This commit is contained in:
parent
80ae8ce116
commit
b4868c6094
19 changed files with 199 additions and 37 deletions
|
@ -9,6 +9,7 @@
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
|
|
||||||
#include "aicombataction.hpp"
|
#include "aicombataction.hpp"
|
||||||
|
#include "character.hpp"
|
||||||
#include "steering.hpp"
|
#include "steering.hpp"
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
|
@ -48,7 +49,9 @@ bool MWMechanics::AiCast::execute(const MWWorld::Ptr& actor, MWMechanics::Charac
|
||||||
if (target.isEmpty())
|
if (target.isEmpty())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!mManual && !pathTo(actor, target.getRefData().getPosition().asVec3(), duration, mDistance))
|
if (!mManual
|
||||||
|
&& !pathTo(actor, target.getRefData().getPosition().asVec3(), duration,
|
||||||
|
characterController.getSupportedMovementDirections(), mDistance))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,7 +134,8 @@ namespace MWMechanics
|
||||||
const osg::Vec3f destination = storage.mUseCustomDestination
|
const osg::Vec3f destination = storage.mUseCustomDestination
|
||||||
? storage.mCustomDestination
|
? storage.mCustomDestination
|
||||||
: target.getRefData().getPosition().asVec3();
|
: target.getRefData().getPosition().asVec3();
|
||||||
const bool is_target_reached = pathTo(actor, destination, duration, targetReachedTolerance);
|
const bool is_target_reached = pathTo(actor, destination, duration,
|
||||||
|
characterController.getSupportedMovementDirections(), targetReachedTolerance);
|
||||||
if (is_target_reached)
|
if (is_target_reached)
|
||||||
storage.mReadyToAttack = true;
|
storage.mReadyToAttack = true;
|
||||||
}
|
}
|
||||||
|
@ -149,7 +150,7 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
updateFleeing(actor, target, duration, storage);
|
updateFleeing(actor, target, duration, characterController.getSupportedMovementDirections(), storage);
|
||||||
}
|
}
|
||||||
storage.mActionCooldown -= duration;
|
storage.mActionCooldown -= duration;
|
||||||
|
|
||||||
|
@ -342,8 +343,8 @@ namespace MWMechanics
|
||||||
storage.mUpdateLOSTimer -= duration;
|
storage.mUpdateLOSTimer -= duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MWMechanics::AiCombat::updateFleeing(
|
void MWMechanics::AiCombat::updateFleeing(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration,
|
||||||
const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, MWMechanics::AiCombatStorage& storage)
|
MWWorld::MovementDirectionFlags supportedMovementDirections, AiCombatStorage& storage)
|
||||||
{
|
{
|
||||||
static const float BLIND_RUN_DURATION = 1.0f;
|
static const float BLIND_RUN_DURATION = 1.0f;
|
||||||
|
|
||||||
|
@ -437,7 +438,7 @@ namespace MWMechanics
|
||||||
float dist
|
float dist
|
||||||
= (actor.getRefData().getPosition().asVec3() - target.getRefData().getPosition().asVec3()).length();
|
= (actor.getRefData().getPosition().asVec3() - target.getRefData().getPosition().asVec3()).length();
|
||||||
if ((dist > fFleeDistance && !storage.mLOS)
|
if ((dist > fFleeDistance && !storage.mLOS)
|
||||||
|| pathTo(actor, PathFinder::makeOsgVec3(storage.mFleeDest), duration))
|
|| pathTo(actor, PathFinder::makeOsgVec3(storage.mFleeDest), duration, supportedMovementDirections))
|
||||||
{
|
{
|
||||||
state = AiCombatStorage::FleeState_Idle;
|
state = AiCombatStorage::FleeState_Idle;
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,8 +111,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
void updateLOS(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, AiCombatStorage& storage);
|
void updateLOS(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, AiCombatStorage& storage);
|
||||||
|
|
||||||
void updateFleeing(
|
void updateFleeing(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration,
|
||||||
const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, AiCombatStorage& storage);
|
MWWorld::MovementDirectionFlags supportedMovementDirections, AiCombatStorage& storage);
|
||||||
|
|
||||||
/// Transfer desired movement (from AiCombatStorage) to Actor
|
/// Transfer desired movement (from AiCombatStorage) to Actor
|
||||||
void updateActorsMovement(const MWWorld::Ptr& actor, float duration, AiCombatStorage& storage);
|
void updateActorsMovement(const MWWorld::Ptr& actor, float duration, AiCombatStorage& storage);
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "../mwworld/cellstore.hpp"
|
#include "../mwworld/cellstore.hpp"
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
|
|
||||||
|
#include "character.hpp"
|
||||||
#include "creaturestats.hpp"
|
#include "creaturestats.hpp"
|
||||||
#include "movement.hpp"
|
#include "movement.hpp"
|
||||||
|
|
||||||
|
@ -94,7 +95,7 @@ namespace MWMechanics
|
||||||
if ((leaderPos - followerPos).length2() <= mMaxDist * mMaxDist)
|
if ((leaderPos - followerPos).length2() <= mMaxDist * mMaxDist)
|
||||||
{
|
{
|
||||||
const osg::Vec3f dest(mX, mY, mZ);
|
const osg::Vec3f dest(mX, mY, mZ);
|
||||||
if (pathTo(actor, dest, duration, maxHalfExtent)) // Returns true on path complete
|
if (pathTo(actor, dest, duration, characterController.getSupportedMovementDirections(), maxHalfExtent))
|
||||||
{
|
{
|
||||||
mRemainingDuration = mDuration;
|
mRemainingDuration = mDuration;
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "../mwworld/cellstore.hpp"
|
#include "../mwworld/cellstore.hpp"
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
|
|
||||||
|
#include "character.hpp"
|
||||||
#include "creaturestats.hpp"
|
#include "creaturestats.hpp"
|
||||||
#include "steering.hpp"
|
#include "steering.hpp"
|
||||||
|
|
||||||
|
@ -202,7 +203,9 @@ namespace MWMechanics
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
storage.mMoving = !pathTo(actor, targetPos, duration, baseFollowDistance); // Go to the destination
|
// Go to the destination
|
||||||
|
storage.mMoving = !pathTo(
|
||||||
|
actor, targetPos, duration, characterController.getSupportedMovementDirections(), baseFollowDistance);
|
||||||
|
|
||||||
if (storage.mMoving)
|
if (storage.mMoving)
|
||||||
{
|
{
|
||||||
|
|
|
@ -110,7 +110,8 @@ void MWMechanics::AiPackage::reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f& dest, float duration,
|
bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f& dest, float duration,
|
||||||
float destTolerance, float endTolerance, PathType pathType)
|
MWWorld::MovementDirectionFlags supportedMovementDirections, float destTolerance, float endTolerance,
|
||||||
|
PathType pathType)
|
||||||
{
|
{
|
||||||
const Misc::TimerStatus timerStatus = mReaction.update(duration);
|
const Misc::TimerStatus timerStatus = mReaction.update(duration);
|
||||||
|
|
||||||
|
@ -230,7 +231,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f&
|
||||||
smoothTurn(actor, mPathFinder.getXAngleToNext(position.x(), position.y(), position.z()), 0);
|
smoothTurn(actor, mPathFinder.getXAngleToNext(position.x(), position.y(), position.z()), 0);
|
||||||
|
|
||||||
const auto destination = getNextPathPoint(dest);
|
const auto destination = getNextPathPoint(dest);
|
||||||
mObstacleCheck.update(actor, destination, duration);
|
mObstacleCheck.update(actor, destination, duration, supportedMovementDirections);
|
||||||
|
|
||||||
if (smoothMovement)
|
if (smoothMovement)
|
||||||
{
|
{
|
||||||
|
|
|
@ -125,7 +125,8 @@ namespace MWMechanics
|
||||||
protected:
|
protected:
|
||||||
/// Handles path building and shortcutting with obstacles avoiding
|
/// Handles path building and shortcutting with obstacles avoiding
|
||||||
/** \return If the actor has arrived at his destination **/
|
/** \return If the actor has arrived at his destination **/
|
||||||
bool pathTo(const MWWorld::Ptr& actor, const osg::Vec3f& dest, float duration, float destTolerance = 0.0f,
|
bool pathTo(const MWWorld::Ptr& actor, const osg::Vec3f& dest, float duration,
|
||||||
|
MWWorld::MovementDirectionFlags supportedMovementDirections, float destTolerance = 0.0f,
|
||||||
float endTolerance = 0.0f, PathType pathType = PathType::Full);
|
float endTolerance = 0.0f, PathType pathType = PathType::Full);
|
||||||
|
|
||||||
/// Check if there aren't any obstacles along the path to make shortcut possible
|
/// Check if there aren't any obstacles along the path to make shortcut possible
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
|
|
||||||
#include "actorutil.hpp"
|
#include "actorutil.hpp"
|
||||||
|
#include "character.hpp"
|
||||||
#include "creaturestats.hpp"
|
#include "creaturestats.hpp"
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
|
@ -55,7 +56,8 @@ namespace MWMechanics
|
||||||
const float pathTolerance = 100.f;
|
const float pathTolerance = 100.f;
|
||||||
|
|
||||||
// check the true distance in case the target is far away in Z-direction
|
// check the true distance in case the target is far away in Z-direction
|
||||||
bool reached = pathTo(actor, dest, duration, pathTolerance, (actorPos - dest).length(), PathType::Partial)
|
bool reached = pathTo(actor, dest, duration, characterController.getSupportedMovementDirections(),
|
||||||
|
pathTolerance, (actorPos - dest).length(), PathType::Partial)
|
||||||
&& std::abs(dest.z() - actorPos.z()) < pathTolerance;
|
&& std::abs(dest.z() - actorPos.z()) < pathTolerance;
|
||||||
|
|
||||||
if (reached)
|
if (reached)
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
|
|
||||||
|
#include "character.hpp"
|
||||||
#include "creaturestats.hpp"
|
#include "creaturestats.hpp"
|
||||||
#include "movement.hpp"
|
#include "movement.hpp"
|
||||||
|
|
||||||
|
@ -89,7 +90,7 @@ namespace MWMechanics
|
||||||
if (!isWithinMaxRange(targetPos, actorPos))
|
if (!isWithinMaxRange(targetPos, actorPos))
|
||||||
return mHidden;
|
return mHidden;
|
||||||
|
|
||||||
if (pathTo(actor, targetPos, duration))
|
if (pathTo(actor, targetPos, duration, characterController.getSupportedMovementDirections()))
|
||||||
{
|
{
|
||||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "../mwphysics/raycasting.hpp"
|
#include "../mwphysics/raycasting.hpp"
|
||||||
|
|
||||||
#include "actorutil.hpp"
|
#include "actorutil.hpp"
|
||||||
|
#include "character.hpp"
|
||||||
#include "creaturestats.hpp"
|
#include "creaturestats.hpp"
|
||||||
#include "movement.hpp"
|
#include "movement.hpp"
|
||||||
#include "pathgrid.hpp"
|
#include "pathgrid.hpp"
|
||||||
|
@ -190,7 +191,7 @@ namespace MWMechanics
|
||||||
* will kick in.
|
* will kick in.
|
||||||
*/
|
*/
|
||||||
bool AiWander::execute(
|
bool AiWander::execute(
|
||||||
const MWWorld::Ptr& actor, CharacterController& /*characterController*/, AiState& state, float duration)
|
const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
|
||||||
{
|
{
|
||||||
MWMechanics::CreatureStats& cStats = actor.getClass().getCreatureStats(actor);
|
MWMechanics::CreatureStats& cStats = actor.getClass().getCreatureStats(actor);
|
||||||
if (cStats.isDead() || cStats.getHealth().getCurrent() <= 0)
|
if (cStats.isDead() || cStats.getHealth().getCurrent() <= 0)
|
||||||
|
@ -244,7 +245,7 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
doPerFrameActionsForState(actor, duration, storage);
|
doPerFrameActionsForState(actor, duration, characterController.getSupportedMovementDirections(), storage);
|
||||||
|
|
||||||
if (storage.mReaction.update(duration) == Misc::TimerStatus::Waiting)
|
if (storage.mReaction.update(duration) == Misc::TimerStatus::Waiting)
|
||||||
return false;
|
return false;
|
||||||
|
@ -454,7 +455,8 @@ namespace MWMechanics
|
||||||
storage.setState(AiWanderStorage::Wander_IdleNow);
|
storage.setState(AiWanderStorage::Wander_IdleNow);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AiWander::doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage)
|
void AiWander::doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration,
|
||||||
|
MWWorld::MovementDirectionFlags supportedMovementDirections, AiWanderStorage& storage)
|
||||||
{
|
{
|
||||||
switch (storage.mState)
|
switch (storage.mState)
|
||||||
{
|
{
|
||||||
|
@ -463,7 +465,7 @@ namespace MWMechanics
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AiWanderStorage::Wander_Walking:
|
case AiWanderStorage::Wander_Walking:
|
||||||
onWalkingStatePerFrameActions(actor, duration, storage);
|
onWalkingStatePerFrameActions(actor, duration, supportedMovementDirections, storage);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AiWanderStorage::Wander_ChooseAction:
|
case AiWanderStorage::Wander_ChooseAction:
|
||||||
|
@ -520,11 +522,13 @@ namespace MWMechanics
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AiWander::onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage)
|
void AiWander::onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, float duration,
|
||||||
|
MWWorld::MovementDirectionFlags supportedMovementDirections, AiWanderStorage& storage)
|
||||||
{
|
{
|
||||||
// Is there no destination or are we there yet?
|
// Is there no destination or are we there yet?
|
||||||
if ((!mPathFinder.isPathConstructed())
|
if ((!mPathFinder.isPathConstructed())
|
||||||
|| pathTo(actor, osg::Vec3f(mPathFinder.getPath().back()), duration, DESTINATION_TOLERANCE))
|
|| pathTo(actor, osg::Vec3f(mPathFinder.getPath().back()), duration, supportedMovementDirections,
|
||||||
|
DESTINATION_TOLERANCE))
|
||||||
{
|
{
|
||||||
stopWalking(actor);
|
stopWalking(actor);
|
||||||
storage.setState(AiWanderStorage::Wander_ChooseAction);
|
storage.setState(AiWanderStorage::Wander_ChooseAction);
|
||||||
|
|
|
@ -123,9 +123,11 @@ namespace MWMechanics
|
||||||
int getRandomIdle() const;
|
int getRandomIdle() const;
|
||||||
void setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos);
|
void setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos);
|
||||||
void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage);
|
void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage);
|
||||||
void doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage);
|
void doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration,
|
||||||
|
MWWorld::MovementDirectionFlags supportedMovementDirections, AiWanderStorage& storage);
|
||||||
void onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage);
|
void onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage);
|
||||||
void onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage);
|
void onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, float duration,
|
||||||
|
MWWorld::MovementDirectionFlags supportedMovementDirections, AiWanderStorage& storage);
|
||||||
void onChooseActionStatePerFrameActions(const MWWorld::Ptr& actor, AiWanderStorage& storage);
|
void onChooseActionStatePerFrameActions(const MWWorld::Ptr& actor, AiWanderStorage& storage);
|
||||||
bool reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, ESM::Position& pos);
|
bool reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, ESM::Position& pos);
|
||||||
inline bool isPackageCompleted() const;
|
inline bool isPackageCompleted() const;
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
|
|
||||||
#include "character.hpp"
|
#include "character.hpp"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
#include <components/esm/records.hpp>
|
#include <components/esm/records.hpp>
|
||||||
#include <components/misc/mathutil.hpp>
|
#include <components/misc/mathutil.hpp>
|
||||||
#include <components/misc/resourcehelpers.hpp>
|
#include <components/misc/resourcehelpers.hpp>
|
||||||
|
@ -2926,4 +2928,77 @@ namespace MWMechanics
|
||||||
mAnimation->setHeadYaw(zAngleRadians);
|
mAnimation->setHeadYaw(zAngleRadians);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MWWorld::MovementDirectionFlags CharacterController::getSupportedMovementDirections() const
|
||||||
|
{
|
||||||
|
using namespace std::string_view_literals;
|
||||||
|
// There are fallbacks in the CharacterController::refreshMovementAnims for certain animations. Arrays below
|
||||||
|
// represent them.
|
||||||
|
constexpr std::array all = { ""sv };
|
||||||
|
constexpr std::array walk = { "walk"sv };
|
||||||
|
constexpr std::array swimWalk = { "swimwalk"sv, "walk"sv };
|
||||||
|
constexpr std::array sneak = { "sneak"sv };
|
||||||
|
constexpr std::array run = { "run"sv, "walk"sv };
|
||||||
|
constexpr std::array swimRun = { "swimrun"sv, "run"sv, "walk"sv };
|
||||||
|
constexpr std::array swim = { "swim"sv };
|
||||||
|
switch (mMovementState)
|
||||||
|
{
|
||||||
|
case CharState_None:
|
||||||
|
case CharState_SpecialIdle:
|
||||||
|
case CharState_Idle:
|
||||||
|
case CharState_IdleSwim:
|
||||||
|
case CharState_IdleSneak:
|
||||||
|
return mAnimation->getSupportedMovementDirections(all);
|
||||||
|
case CharState_WalkForward:
|
||||||
|
case CharState_WalkBack:
|
||||||
|
case CharState_WalkLeft:
|
||||||
|
case CharState_WalkRight:
|
||||||
|
return mAnimation->getSupportedMovementDirections(walk);
|
||||||
|
case CharState_SwimWalkForward:
|
||||||
|
case CharState_SwimWalkBack:
|
||||||
|
case CharState_SwimWalkLeft:
|
||||||
|
case CharState_SwimWalkRight:
|
||||||
|
return mAnimation->getSupportedMovementDirections(swimWalk);
|
||||||
|
case CharState_RunForward:
|
||||||
|
case CharState_RunBack:
|
||||||
|
case CharState_RunLeft:
|
||||||
|
case CharState_RunRight:
|
||||||
|
return mAnimation->getSupportedMovementDirections(run);
|
||||||
|
case CharState_SwimRunForward:
|
||||||
|
case CharState_SwimRunBack:
|
||||||
|
case CharState_SwimRunLeft:
|
||||||
|
case CharState_SwimRunRight:
|
||||||
|
return mAnimation->getSupportedMovementDirections(swimRun);
|
||||||
|
case CharState_SneakForward:
|
||||||
|
case CharState_SneakBack:
|
||||||
|
case CharState_SneakLeft:
|
||||||
|
case CharState_SneakRight:
|
||||||
|
return mAnimation->getSupportedMovementDirections(sneak);
|
||||||
|
case CharState_TurnLeft:
|
||||||
|
case CharState_TurnRight:
|
||||||
|
return mAnimation->getSupportedMovementDirections(all);
|
||||||
|
case CharState_SwimTurnLeft:
|
||||||
|
case CharState_SwimTurnRight:
|
||||||
|
return mAnimation->getSupportedMovementDirections(swim);
|
||||||
|
case CharState_Death1:
|
||||||
|
case CharState_Death2:
|
||||||
|
case CharState_Death3:
|
||||||
|
case CharState_Death4:
|
||||||
|
case CharState_Death5:
|
||||||
|
case CharState_SwimDeath:
|
||||||
|
case CharState_SwimDeathKnockDown:
|
||||||
|
case CharState_SwimDeathKnockOut:
|
||||||
|
case CharState_DeathKnockDown:
|
||||||
|
case CharState_DeathKnockOut:
|
||||||
|
case CharState_Hit:
|
||||||
|
case CharState_SwimHit:
|
||||||
|
case CharState_KnockDown:
|
||||||
|
case CharState_KnockOut:
|
||||||
|
case CharState_SwimKnockDown:
|
||||||
|
case CharState_SwimKnockOut:
|
||||||
|
case CharState_Block:
|
||||||
|
return mAnimation->getSupportedMovementDirections(all);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -315,6 +315,8 @@ namespace MWMechanics
|
||||||
void setHeadTrackTarget(const MWWorld::ConstPtr& target);
|
void setHeadTrackTarget(const MWWorld::ConstPtr& target);
|
||||||
|
|
||||||
void playSwishSound() const;
|
void playSwishSound() const;
|
||||||
|
|
||||||
|
MWWorld::MovementDirectionFlags getSupportedMovementDirections() const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "obstacle.hpp"
|
#include "obstacle.hpp"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
#include <components/detournavigator/agentbounds.hpp>
|
#include <components/detournavigator/agentbounds.hpp>
|
||||||
#include <components/esm3/loaddoor.hpp>
|
#include <components/esm3/loaddoor.hpp>
|
||||||
|
@ -22,14 +23,21 @@ namespace MWMechanics
|
||||||
constexpr float durationSameSpot = 1.5f;
|
constexpr float durationSameSpot = 1.5f;
|
||||||
constexpr float durationToEvade = 1;
|
constexpr float durationToEvade = 1;
|
||||||
|
|
||||||
constexpr float evadeDirections[][2] = {
|
struct EvadeDirection
|
||||||
{ 1.0f, 1.0f }, // move to side and forward
|
{
|
||||||
{ 1.0f, 0.0f }, // move to side
|
float mMovementX;
|
||||||
{ 1.0f, -1.0f }, // move to side and backwards
|
float mMovementY;
|
||||||
{ 0.0f, -1.0f }, // move backwards
|
MWWorld::MovementDirectionFlag mRequiredAnimation;
|
||||||
{ -1.0f, -1.0f }, // move to other side and backwards
|
};
|
||||||
{ -1.0f, 0.0f }, // move to other side
|
|
||||||
{ -1.0f, 1.0f }, // move to other side and forward
|
constexpr EvadeDirection evadeDirections[] = {
|
||||||
|
{ 1.0f, 1.0f, MWWorld::MovementDirectionFlag_Forward }, // move to right and forward
|
||||||
|
{ 1.0f, 0.0f, MWWorld::MovementDirectionFlag_Right }, // move to right
|
||||||
|
{ 1.0f, -1.0f, MWWorld::MovementDirectionFlag_Back }, // move to right and backwards
|
||||||
|
{ 0.0f, -1.0f, MWWorld::MovementDirectionFlag_Back }, // move backwards
|
||||||
|
{ -1.0f, -1.0f, MWWorld::MovementDirectionFlag_Back }, // move to left and backwards
|
||||||
|
{ -1.0f, 0.0f, MWWorld::MovementDirectionFlag_Left }, // move to left
|
||||||
|
{ -1.0f, 1.0f, MWWorld::MovementDirectionFlag_Forward }, // move to left and forward
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,7 +140,8 @@ namespace MWMechanics
|
||||||
* u = how long to move sideways
|
* u = how long to move sideways
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void ObstacleCheck::update(const MWWorld::Ptr& actor, const osg::Vec3f& destination, float duration)
|
void ObstacleCheck::update(const MWWorld::Ptr& actor, const osg::Vec3f& destination, float duration,
|
||||||
|
MWWorld::MovementDirectionFlags supportedMovementDirection)
|
||||||
{
|
{
|
||||||
const auto position = actor.getRefData().getPosition().asVec3();
|
const auto position = actor.getRefData().getPosition().asVec3();
|
||||||
|
|
||||||
|
@ -185,8 +194,15 @@ namespace MWMechanics
|
||||||
|
|
||||||
mWalkState = WalkState::Evade;
|
mWalkState = WalkState::Evade;
|
||||||
mStateDuration = 0;
|
mStateDuration = 0;
|
||||||
if (++mEvadeDirectionIndex == std::size(evadeDirections))
|
std::size_t newEvadeDirectionIndex = mEvadeDirectionIndex;
|
||||||
mEvadeDirectionIndex = 0;
|
do
|
||||||
|
{
|
||||||
|
++newEvadeDirectionIndex;
|
||||||
|
if (newEvadeDirectionIndex == std::size(evadeDirections))
|
||||||
|
newEvadeDirectionIndex = 0;
|
||||||
|
if ((evadeDirections[newEvadeDirectionIndex].mRequiredAnimation & supportedMovementDirection) != 0)
|
||||||
|
break;
|
||||||
|
} while (mEvadeDirectionIndex != newEvadeDirectionIndex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,7 +218,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
void ObstacleCheck::takeEvasiveAction(MWMechanics::Movement& actorMovement) const
|
void ObstacleCheck::takeEvasiveAction(MWMechanics::Movement& actorMovement) const
|
||||||
{
|
{
|
||||||
actorMovement.mPosition[0] = evadeDirections[mEvadeDirectionIndex][0];
|
actorMovement.mPosition[0] = evadeDirections[mEvadeDirectionIndex].mMovementX;
|
||||||
actorMovement.mPosition[1] = evadeDirections[mEvadeDirectionIndex][1];
|
actorMovement.mPosition[1] = evadeDirections[mEvadeDirectionIndex].mMovementY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#ifndef OPENMW_MECHANICS_OBSTACLE_H
|
#ifndef OPENMW_MECHANICS_OBSTACLE_H
|
||||||
#define OPENMW_MECHANICS_OBSTACLE_H
|
#define OPENMW_MECHANICS_OBSTACLE_H
|
||||||
|
|
||||||
|
#include "apps/openmw/mwworld/movementdirection.hpp"
|
||||||
|
|
||||||
#include <osg/Vec3f>
|
#include <osg/Vec3f>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -36,7 +38,8 @@ namespace MWMechanics
|
||||||
bool isEvading() const;
|
bool isEvading() const;
|
||||||
|
|
||||||
// Updates internal state, call each frame for moving actor
|
// Updates internal state, call each frame for moving actor
|
||||||
void update(const MWWorld::Ptr& actor, const osg::Vec3f& destination, float duration);
|
void update(const MWWorld::Ptr& actor, const osg::Vec3f& destination, float duration,
|
||||||
|
MWWorld::MovementDirectionFlags supportedMovementDirection);
|
||||||
|
|
||||||
// change direction to try to fix "stuck" actor
|
// change direction to try to fix "stuck" actor
|
||||||
void takeEvasiveAction(Movement& actorMovement) const;
|
void takeEvasiveAction(Movement& actorMovement) const;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "animation.hpp"
|
#include "animation.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
|
@ -1800,6 +1801,28 @@ namespace MWRender
|
||||||
mInsert->removeChild(mObjectRoot);
|
mInsert->removeChild(mObjectRoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MWWorld::MovementDirectionFlags Animation::getSupportedMovementDirections(
|
||||||
|
std::span<const std::string_view> prefixes) const
|
||||||
|
{
|
||||||
|
MWWorld::MovementDirectionFlags result = 0;
|
||||||
|
for (const std::string_view animation : mSupportedAnimations)
|
||||||
|
{
|
||||||
|
if (std::find_if(
|
||||||
|
prefixes.begin(), prefixes.end(), [&](std::string_view v) { return animation.starts_with(v); })
|
||||||
|
== prefixes.end())
|
||||||
|
continue;
|
||||||
|
if (animation.ends_with("forward"))
|
||||||
|
result |= MWWorld::MovementDirectionFlag_Forward;
|
||||||
|
else if (animation.ends_with("back"))
|
||||||
|
result |= MWWorld::MovementDirectionFlag_Back;
|
||||||
|
else if (animation.ends_with("left"))
|
||||||
|
result |= MWWorld::MovementDirectionFlag_Left;
|
||||||
|
else if (animation.ends_with("right"))
|
||||||
|
result |= MWWorld::MovementDirectionFlag_Right;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
|
|
||||||
float Animation::AnimationTime::getValue(osg::NodeVisitor*)
|
float Animation::AnimationTime::getValue(osg::NodeVisitor*)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef GAME_RENDER_ANIMATION_H
|
#ifndef GAME_RENDER_ANIMATION_H
|
||||||
#define GAME_RENDER_ANIMATION_H
|
#define GAME_RENDER_ANIMATION_H
|
||||||
|
|
||||||
|
#include "../mwworld/movementdirection.hpp"
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
|
|
||||||
#include <components/misc/strings/algorithm.hpp>
|
#include <components/misc/strings/algorithm.hpp>
|
||||||
|
@ -9,6 +10,7 @@
|
||||||
#include <components/sceneutil/textkeymap.hpp>
|
#include <components/sceneutil/textkeymap.hpp>
|
||||||
#include <components/sceneutil/util.hpp>
|
#include <components/sceneutil/util.hpp>
|
||||||
|
|
||||||
|
#include <span>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -472,6 +474,9 @@ namespace MWRender
|
||||||
/// @note The matching is case-insensitive.
|
/// @note The matching is case-insensitive.
|
||||||
const osg::Node* getNode(std::string_view name) const;
|
const osg::Node* getNode(std::string_view name) const;
|
||||||
|
|
||||||
|
MWWorld::MovementDirectionFlags getSupportedMovementDirections(
|
||||||
|
std::span<const std::string_view> prefixes) const;
|
||||||
|
|
||||||
virtual bool useShieldAnimations() const { return false; }
|
virtual bool useShieldAnimations() const { return false; }
|
||||||
virtual bool getWeaponsShown() const { return false; }
|
virtual bool getWeaponsShown() const { return false; }
|
||||||
virtual void showWeapons(bool showWeapon) {}
|
virtual void showWeapons(bool showWeapon) {}
|
||||||
|
|
17
apps/openmw/mwworld/movementdirection.hpp
Normal file
17
apps/openmw/mwworld/movementdirection.hpp
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#ifndef OPENMW_APPS_OPENMW_MWWORLD_MOVEMENTDIRECTION_H
|
||||||
|
#define OPENMW_APPS_OPENMW_MWWORLD_MOVEMENTDIRECTION_H
|
||||||
|
|
||||||
|
namespace MWWorld
|
||||||
|
{
|
||||||
|
using MovementDirectionFlags = unsigned char;
|
||||||
|
|
||||||
|
enum MovementDirectionFlag : MovementDirectionFlags
|
||||||
|
{
|
||||||
|
MovementDirectionFlag_Forward = 1 << 0,
|
||||||
|
MovementDirectionFlag_Back = 1 << 1,
|
||||||
|
MovementDirectionFlag_Left = 1 << 2,
|
||||||
|
MovementDirectionFlag_Right = 1 << 3,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -44,6 +44,8 @@ namespace SceneUtil
|
||||||
|
|
||||||
bool hasGroupStart(std::string_view groupName) const { return mGroups.count(groupName) > 0; }
|
bool hasGroupStart(std::string_view groupName) const { return mGroups.count(groupName) > 0; }
|
||||||
|
|
||||||
|
const std::set<std::string, std::less<>>& getGroups() const { return mGroups; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct IsGroupStart
|
struct IsGroupStart
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue