|
|
|
@ -60,30 +60,30 @@ namespace MWMechanics
|
|
|
|
|
FleeState_RunToDestination
|
|
|
|
|
};
|
|
|
|
|
FleeState mFleeState;
|
|
|
|
|
bool mFleeLOS;
|
|
|
|
|
float mFleeUpdateLOSTimer;
|
|
|
|
|
bool mLOS;
|
|
|
|
|
float mUpdateLOSTimer;
|
|
|
|
|
float mFleeBlindRunTimer;
|
|
|
|
|
ESM::Pathgrid::Point mFleeDest;
|
|
|
|
|
|
|
|
|
|
AiCombatStorage():
|
|
|
|
|
mAttackCooldown(0),
|
|
|
|
|
mAttackCooldown(0.0f),
|
|
|
|
|
mTimerReact(AI_REACTION_TIME),
|
|
|
|
|
mTimerCombatMove(0),
|
|
|
|
|
mTimerCombatMove(0.0f),
|
|
|
|
|
mReadyToAttack(false),
|
|
|
|
|
mAttack(false),
|
|
|
|
|
mAttackRange(0),
|
|
|
|
|
mAttackRange(0.0f),
|
|
|
|
|
mCombatMove(false),
|
|
|
|
|
mLastTargetPos(0,0,0),
|
|
|
|
|
mCell(NULL),
|
|
|
|
|
mCurrentAction(),
|
|
|
|
|
mActionCooldown(0),
|
|
|
|
|
mActionCooldown(0.0f),
|
|
|
|
|
mStrength(),
|
|
|
|
|
mForceNoShortcut(false),
|
|
|
|
|
mShortcutFailPos(),
|
|
|
|
|
mMovement(),
|
|
|
|
|
mFleeState(FleeState_None),
|
|
|
|
|
mFleeLOS(false),
|
|
|
|
|
mFleeUpdateLOSTimer(0.0f),
|
|
|
|
|
mLOS(false),
|
|
|
|
|
mUpdateLOSTimer(0.0f),
|
|
|
|
|
mFleeBlindRunTimer(0.0f)
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
@ -181,10 +181,14 @@ namespace MWMechanics
|
|
|
|
|
|
|
|
|
|
if (!storage.isFleeing())
|
|
|
|
|
{
|
|
|
|
|
if (storage.mCurrentAction.get()) // need to wait to init action with it's attack range
|
|
|
|
|
if (storage.mCurrentAction.get()) // need to wait to init action with its attack range
|
|
|
|
|
{
|
|
|
|
|
//Update every frame
|
|
|
|
|
bool is_target_reached = pathTo(actor, target.getRefData().getPosition().pos, duration, storage.mAttackRange);
|
|
|
|
|
//Update every frame. UpdateLOS uses a timer, so the LOS check does not happen every frame.
|
|
|
|
|
updateLOS(actor, target, duration, storage);
|
|
|
|
|
float targetReachedTolerance = 0.0f;
|
|
|
|
|
if (storage.mLOS)
|
|
|
|
|
targetReachedTolerance = storage.mAttackRange;
|
|
|
|
|
bool is_target_reached = pathTo(actor, target.getRefData().getPosition().pos, duration, targetReachedTolerance);
|
|
|
|
|
if (is_target_reached) storage.mReadyToAttack = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -283,7 +287,7 @@ namespace MWMechanics
|
|
|
|
|
osg::Vec3f vAimDir = MWBase::Environment::get().getWorld()->aimToTarget(actor, target);
|
|
|
|
|
float distToTarget = MWBase::Environment::get().getWorld()->getHitDistance(actor, target);
|
|
|
|
|
|
|
|
|
|
storage.mReadyToAttack = (currentAction->isAttackingOrSpell() && distToTarget <= rangeAttack);
|
|
|
|
|
storage.mReadyToAttack = (currentAction->isAttackingOrSpell() && distToTarget <= rangeAttack && storage.mLOS);
|
|
|
|
|
|
|
|
|
|
if (storage.mReadyToAttack)
|
|
|
|
|
{
|
|
|
|
@ -309,18 +313,23 @@ namespace MWMechanics
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MWMechanics::AiCombat::updateFleeing(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, MWMechanics::AiCombatStorage& storage)
|
|
|
|
|
void MWMechanics::AiCombat::updateLOS(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, MWMechanics::AiCombatStorage& storage)
|
|
|
|
|
{
|
|
|
|
|
static const float LOS_UPDATE_DURATION = 0.5f;
|
|
|
|
|
static const float BLIND_RUN_DURATION = 1.0f;
|
|
|
|
|
|
|
|
|
|
if (storage.mFleeUpdateLOSTimer <= 0.f)
|
|
|
|
|
if (storage.mUpdateLOSTimer <= 0.f)
|
|
|
|
|
{
|
|
|
|
|
storage.mFleeLOS = MWBase::Environment::get().getWorld()->getLOS(actor, target);
|
|
|
|
|
storage.mFleeUpdateLOSTimer = LOS_UPDATE_DURATION;
|
|
|
|
|
storage.mLOS = MWBase::Environment::get().getWorld()->getLOS(actor, target);
|
|
|
|
|
storage.mUpdateLOSTimer = LOS_UPDATE_DURATION;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
storage.mFleeUpdateLOSTimer -= duration;
|
|
|
|
|
storage.mUpdateLOSTimer -= duration;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MWMechanics::AiCombat::updateFleeing(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, MWMechanics::AiCombatStorage& storage)
|
|
|
|
|
{
|
|
|
|
|
static const float BLIND_RUN_DURATION = 1.0f;
|
|
|
|
|
|
|
|
|
|
updateLOS(actor, target, duration, storage);
|
|
|
|
|
|
|
|
|
|
AiCombatStorage::FleeState& state = storage.mFleeState;
|
|
|
|
|
switch (state)
|
|
|
|
@ -332,7 +341,7 @@ namespace MWMechanics
|
|
|
|
|
{
|
|
|
|
|
float triggerDist = getMaxAttackDistance(target);
|
|
|
|
|
|
|
|
|
|
if (storage.mFleeLOS &&
|
|
|
|
|
if (storage.mLOS &&
|
|
|
|
|
(triggerDist >= 1000 || getDistanceMinusHalfExtents(actor, target) <= triggerDist))
|
|
|
|
|
{
|
|
|
|
|
const ESM::Pathgrid* pathgrid =
|
|
|
|
@ -399,7 +408,7 @@ namespace MWMechanics
|
|
|
|
|
static const float fFleeDistance = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fFleeDistance")->getFloat();
|
|
|
|
|
|
|
|
|
|
float dist = (actor.getRefData().getPosition().asVec3() - target.getRefData().getPosition().asVec3()).length();
|
|
|
|
|
if ((dist > fFleeDistance && !storage.mFleeLOS)
|
|
|
|
|
if ((dist > fFleeDistance && !storage.mLOS)
|
|
|
|
|
|| pathTo(actor, storage.mFleeDest, duration))
|
|
|
|
|
{
|
|
|
|
|
state = AiCombatStorage::FleeState_Idle;
|
|
|
|
@ -602,9 +611,6 @@ namespace MWMechanics
|
|
|
|
|
mMovement.mPosition[2] = 0;
|
|
|
|
|
mFleeState = FleeState_None;
|
|
|
|
|
mFleeDest = ESM::Pathgrid::Point(0, 0, 0);
|
|
|
|
|
mFleeLOS = false;
|
|
|
|
|
mFleeUpdateLOSTimer = 0.0f;
|
|
|
|
|
mFleeUpdateLOSTimer = 0.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool AiCombatStorage::isFleeing()
|
|
|
|
|