Require line of sight for AI attacks (Fixes #3646)

pull/120/head
Allofich 8 years ago committed by scrawl
parent e5c9a82a29
commit 19143f9bc7

@ -60,30 +60,30 @@ namespace MWMechanics
FleeState_RunToDestination FleeState_RunToDestination
}; };
FleeState mFleeState; FleeState mFleeState;
bool mFleeLOS; bool mLOS;
float mFleeUpdateLOSTimer; float mUpdateLOSTimer;
float mFleeBlindRunTimer; float mFleeBlindRunTimer;
ESM::Pathgrid::Point mFleeDest; ESM::Pathgrid::Point mFleeDest;
AiCombatStorage(): AiCombatStorage():
mAttackCooldown(0), mAttackCooldown(0.0f),
mTimerReact(AI_REACTION_TIME), mTimerReact(AI_REACTION_TIME),
mTimerCombatMove(0), mTimerCombatMove(0.0f),
mReadyToAttack(false), mReadyToAttack(false),
mAttack(false), mAttack(false),
mAttackRange(0), mAttackRange(0.0f),
mCombatMove(false), mCombatMove(false),
mLastTargetPos(0,0,0), mLastTargetPos(0,0,0),
mCell(NULL), mCell(NULL),
mCurrentAction(), mCurrentAction(),
mActionCooldown(0), mActionCooldown(0.0f),
mStrength(), mStrength(),
mForceNoShortcut(false), mForceNoShortcut(false),
mShortcutFailPos(), mShortcutFailPos(),
mMovement(), mMovement(),
mFleeState(FleeState_None), mFleeState(FleeState_None),
mFleeLOS(false), mLOS(false),
mFleeUpdateLOSTimer(0.0f), mUpdateLOSTimer(0.0f),
mFleeBlindRunTimer(0.0f) mFleeBlindRunTimer(0.0f)
{} {}
@ -181,10 +181,14 @@ namespace MWMechanics
if (!storage.isFleeing()) 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 //Update every frame. UpdateLOS uses a timer, so the LOS check does not happen every frame.
bool is_target_reached = pathTo(actor, target.getRefData().getPosition().pos, duration, storage.mAttackRange); 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; if (is_target_reached) storage.mReadyToAttack = true;
} }
@ -283,7 +287,7 @@ namespace MWMechanics
osg::Vec3f vAimDir = MWBase::Environment::get().getWorld()->aimToTarget(actor, target); osg::Vec3f vAimDir = MWBase::Environment::get().getWorld()->aimToTarget(actor, target);
float distToTarget = MWBase::Environment::get().getWorld()->getHitDistance(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) 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 LOS_UPDATE_DURATION = 0.5f;
static const float BLIND_RUN_DURATION = 1.0f; if (storage.mUpdateLOSTimer <= 0.f)
if (storage.mFleeUpdateLOSTimer <= 0.f)
{ {
storage.mFleeLOS = MWBase::Environment::get().getWorld()->getLOS(actor, target); storage.mLOS = MWBase::Environment::get().getWorld()->getLOS(actor, target);
storage.mFleeUpdateLOSTimer = LOS_UPDATE_DURATION; storage.mUpdateLOSTimer = LOS_UPDATE_DURATION;
} }
else 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; AiCombatStorage::FleeState& state = storage.mFleeState;
switch (state) switch (state)
@ -332,7 +341,7 @@ namespace MWMechanics
{ {
float triggerDist = getMaxAttackDistance(target); float triggerDist = getMaxAttackDistance(target);
if (storage.mFleeLOS && if (storage.mLOS &&
(triggerDist >= 1000 || getDistanceMinusHalfExtents(actor, target) <= triggerDist)) (triggerDist >= 1000 || getDistanceMinusHalfExtents(actor, target) <= triggerDist))
{ {
const ESM::Pathgrid* pathgrid = 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(); 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(); 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)) || pathTo(actor, storage.mFleeDest, duration))
{ {
state = AiCombatStorage::FleeState_Idle; state = AiCombatStorage::FleeState_Idle;
@ -602,9 +611,6 @@ namespace MWMechanics
mMovement.mPosition[2] = 0; mMovement.mPosition[2] = 0;
mFleeState = FleeState_None; mFleeState = FleeState_None;
mFleeDest = ESM::Pathgrid::Point(0, 0, 0); mFleeDest = ESM::Pathgrid::Point(0, 0, 0);
mFleeLOS = false;
mFleeUpdateLOSTimer = 0.0f;
mFleeUpdateLOSTimer = 0.0f;
} }
bool AiCombatStorage::isFleeing() bool AiCombatStorage::isFleeing()

@ -61,6 +61,8 @@ namespace MWMechanics
void attack(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, AiCombatStorage& storage, CharacterController& characterController); void attack(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, AiCombatStorage& storage, CharacterController& characterController);
void updateLOS(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, AiCombatStorage& storage);
void updateFleeing(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, AiCombatStorage& storage); void updateFleeing(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, AiCombatStorage& storage);
/// Transfer desired movement (from AiCombatStorage) to Actor /// Transfer desired movement (from AiCombatStorage) to Actor

Loading…
Cancel
Save