diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 1ae27a9cb..cbe161af1 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -5,6 +5,8 @@ #include +#include + #include #include "../mwphysics/collisiontype.hpp" @@ -240,10 +242,6 @@ namespace MWMechanics if (storage.mReadyToAttack) { - storage.startCombatMove(isRangedCombat, distToTarget, rangeAttack, actor, target); - // start new attack - storage.startAttackIfReady(actor, characterController, weapon, isRangedCombat); - if (isRangedCombat) { // rotate actor taking into account target movement direction and projectile speed @@ -259,6 +257,10 @@ namespace MWMechanics storage.mMovement.mRotation[0] = getXAngleToDir(vAimDir); storage.mMovement.mRotation[2] = getZAngleToDir((vTargetPos-vActorPos)); // using vAimDir results in spastic movements since the head is animated } + + storage.startCombatMove(isRangedCombat, distToTarget, rangeAttack, actor, target); + // start new attack + storage.startAttackIfReady(actor, characterController, weapon, isRangedCombat); } return false; } @@ -372,9 +374,13 @@ namespace MWMechanics void AiCombat::updateActorsMovement(const MWWorld::Ptr& actor, float duration, AiCombatStorage& storage) { // apply combat movement + float deltaAngle = storage.mMovement.mRotation[2] - actor.getRefData().getPosition().rot[2]; + osg::Vec2f movement = Misc::rotateVec2f( + osg::Vec2f(storage.mMovement.mPosition[0], storage.mMovement.mPosition[1]), -deltaAngle); + MWMechanics::Movement& actorMovementSettings = actor.getClass().getMovementSettings(actor); - actorMovementSettings.mPosition[0] = storage.mMovement.mPosition[0]; - actorMovementSettings.mPosition[1] = storage.mMovement.mPosition[1]; + actorMovementSettings.mPosition[0] = movement.x(); + actorMovementSettings.mPosition[1] = movement.y(); actorMovementSettings.mPosition[2] = storage.mMovement.mPosition[2]; rotateActorOnAxis(actor, 2, actorMovementSettings, storage); @@ -385,26 +391,11 @@ namespace MWMechanics MWMechanics::Movement& actorMovementSettings, AiCombatStorage& storage) { actorMovementSettings.mRotation[axis] = 0; - float& targetAngleRadians = storage.mMovement.mRotation[axis]; - if (targetAngleRadians != 0) - { - // Some attack animations contain small amount of movement. - // Since we use cone shapes for melee, we can use a threshold to avoid jittering - std::shared_ptr& currentAction = storage.mCurrentAction; - bool isRangedCombat = false; - currentAction->getCombatRange(isRangedCombat); - // Check if the actor now facing desired direction, no need to turn any more - if (isRangedCombat) - { - if (smoothTurn(actor, targetAngleRadians, axis)) - targetAngleRadians = 0; - } - else - { - if (smoothTurn(actor, targetAngleRadians, axis, osg::DegreesToRadians(3.f))) - targetAngleRadians = 0; - } - } + bool isRangedCombat = false; + storage.mCurrentAction->getCombatRange(isRangedCombat); + float eps = isRangedCombat ? osg::DegreesToRadians(0.5) : osg::DegreesToRadians(3.f); + float targetAngleRadians = storage.mMovement.mRotation[axis]; + smoothTurn(actor, targetAngleRadians, axis, eps); } MWWorld::Ptr AiCombat::getTarget() const @@ -489,12 +480,19 @@ namespace MWMechanics // Note: do not use for ranged combat yet since in couple with back up behaviour can move actor out of cliff else if (actor.getClass().isBipedal(actor)) { - // apply sideway movement (kind of dodging) with some probability - // if actor is within range of target's weapon - if (distToTarget <= rangeAttackOfTarget && Misc::Rng::rollClosedProbability() < 0.25) + float moveDuration = 0; + float angleToTarget = Misc::normalizeAngle(mMovement.mRotation[2] - actor.getRefData().getPosition().rot[2]); + // Apply a big side step if enemy tries to get around and come from behind. + // Otherwise apply a random side step (kind of dodging) with some probability + // if actor is within range of target's weapon. + if (std::abs(angleToTarget) > osg::PI / 4) + moveDuration = 0.2; + else if (distToTarget <= rangeAttackOfTarget && Misc::Rng::rollClosedProbability() < 0.25) + moveDuration = 0.1f + 0.1f * Misc::Rng::rollClosedProbability(); + if (moveDuration > 0) { mMovement.mPosition[0] = Misc::Rng::rollProbability() < 0.5 ? 1.0f : -1.0f; // to the left/right - mTimerCombatMove = 0.1f + 0.1f * Misc::Rng::rollClosedProbability(); + mTimerCombatMove = moveDuration; mCombatMove = true; } }