mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 20:53:50 +00:00
Require line of sight for AI attacks (Fixes #3646)
This commit is contained in:
parent
9febb3e824
commit
a6dae51d87
2 changed files with 32 additions and 24 deletions
|
@ -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…
Reference in a new issue