mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-10 12:39:53 +00:00
Merge pull request #1174 from Allofich/combat
Adjustments to AI combat engaging and disengaging
This commit is contained in:
commit
212e85e810
@ -29,6 +29,7 @@
|
||||
#include "movement.hpp"
|
||||
#include "character.hpp"
|
||||
#include "aicombat.hpp"
|
||||
#include "aicombataction.hpp"
|
||||
#include "aifollow.hpp"
|
||||
#include "aipursue.hpp"
|
||||
#include "actor.hpp"
|
||||
@ -286,10 +287,12 @@ namespace MWMechanics
|
||||
|
||||
void Actors::engageCombat (const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, bool againstPlayer)
|
||||
{
|
||||
CreatureStats& creatureStats = actor1.getClass().getCreatureStats(actor1);
|
||||
const CreatureStats& creatureStats1 = actor1.getClass().getCreatureStats(actor1);
|
||||
if (creatureStats1.getAiSequence().isInCombat(actor2))
|
||||
return;
|
||||
|
||||
if (actor2.getClass().getCreatureStats(actor2).isDead()
|
||||
|| actor1.getClass().getCreatureStats(actor1).isDead())
|
||||
const CreatureStats& creatureStats2 = actor2.getClass().getCreatureStats(actor2);
|
||||
if (creatureStats1.isDead() || creatureStats2.isDead())
|
||||
return;
|
||||
|
||||
const ESM::Position& actor1Pos = actor1.getRefData().getPosition();
|
||||
@ -298,55 +301,26 @@ namespace MWMechanics
|
||||
if (sqrDist > sqrAiProcessingDistance)
|
||||
return;
|
||||
|
||||
// pure water creatures won't try to fight with the target on the ground
|
||||
// except that creature is already hostile
|
||||
if ((againstPlayer || !creatureStats.getAiSequence().isInCombat())
|
||||
&& !MWMechanics::isEnvironmentCompatible(actor1, actor2)) // creature can't swim to target
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// no combat for totally static creatures (they have no movement or attack animations anyway)
|
||||
// No combat for totally static creatures
|
||||
if (!actor1.getClass().isMobile(actor1))
|
||||
return;
|
||||
|
||||
bool aggressive;
|
||||
|
||||
if (againstPlayer)
|
||||
// Start combat if target actor is in combat with one of our followers or escorters
|
||||
const std::list<MWWorld::Ptr>& followersAndEscorters = getActorsSidingWith(actor1);
|
||||
for (std::list<MWWorld::Ptr>::const_iterator it = followersAndEscorters.begin(); it != followersAndEscorters.end(); ++it)
|
||||
{
|
||||
// followers with high fight should not engage in combat with the player (e.g. bm_bear_black_summon)
|
||||
const std::list<MWWorld::Ptr>& followers = getActorsSidingWith(actor2);
|
||||
if (std::find(followers.begin(), followers.end(), actor1) != followers.end())
|
||||
return;
|
||||
|
||||
aggressive = MWBase::Environment::get().getMechanicsManager()->isAggressive(actor1, actor2);
|
||||
}
|
||||
else
|
||||
{
|
||||
aggressive = false;
|
||||
|
||||
// Make guards fight aggressive creatures
|
||||
if (!actor1.getClass().isNpc() && actor2.getClass().isClass(actor2, "Guard"))
|
||||
{
|
||||
if (creatureStats.getAiSequence().isInCombat() && MWBase::Environment::get().getMechanicsManager()->isAggressive(actor1, actor2))
|
||||
aggressive = true;
|
||||
}
|
||||
}
|
||||
|
||||
// start combat if target actor is in combat with one of our followers
|
||||
const std::list<MWWorld::Ptr>& followers = getActorsSidingWith(actor1);
|
||||
const CreatureStats& creatureStats2 = actor2.getClass().getCreatureStats(actor2);
|
||||
for (std::list<MWWorld::Ptr>::const_iterator it = followers.begin(); it != followers.end(); ++it)
|
||||
{
|
||||
// need to check both ways since player doesn't use AI packages
|
||||
// Need to check both ways since player doesn't use AI packages
|
||||
if ((creatureStats2.getAiSequence().isInCombat(*it)
|
||||
|| it->getClass().getCreatureStats(*it).getAiSequence().isInCombat(actor2))
|
||||
&& !creatureStats.getAiSequence().isInCombat(*it))
|
||||
aggressive = true;
|
||||
&& !creatureStats1.getAiSequence().isInCombat(*it))
|
||||
{
|
||||
MWBase::Environment::get().getMechanicsManager()->startCombat(actor1, actor2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// start combat if target actor is in combat with someone we are following
|
||||
for (std::list<MWMechanics::AiPackage*>::const_iterator it = creatureStats.getAiSequence().begin(); it != creatureStats.getAiSequence().end(); ++it)
|
||||
// Start combat if target actor is in combat with someone we are following through a follow package
|
||||
for (std::list<MWMechanics::AiPackage*>::const_iterator it = creatureStats1.getAiSequence().begin(); it != creatureStats1.getAiSequence().end(); ++it)
|
||||
{
|
||||
if (!(*it)->sideWithTarget())
|
||||
continue;
|
||||
@ -356,20 +330,63 @@ namespace MWMechanics
|
||||
if (followTarget.isEmpty())
|
||||
continue;
|
||||
|
||||
if (creatureStats.getAiSequence().isInCombat(followTarget))
|
||||
if (creatureStats1.getAiSequence().isInCombat(followTarget))
|
||||
continue;
|
||||
|
||||
// need to check both ways since player doesn't use AI packages
|
||||
// Need to check both ways since player doesn't use AI packages
|
||||
if (creatureStats2.getAiSequence().isInCombat(followTarget)
|
||||
|| followTarget.getClass().getCreatureStats(followTarget).getAiSequence().isInCombat(actor2))
|
||||
{
|
||||
MWBase::Environment::get().getMechanicsManager()->startCombat(actor1, actor2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Start combat with the player if we are already in combat with a player follower or escorter
|
||||
const std::list<MWWorld::Ptr>& playerFollowersAndEscorters = getActorsSidingWith(getPlayer());
|
||||
if (againstPlayer)
|
||||
{
|
||||
for (std::list<MWWorld::Ptr>::const_iterator it = playerFollowersAndEscorters.begin(); it != playerFollowersAndEscorters.end(); ++it)
|
||||
{
|
||||
if (creatureStats1.getAiSequence().isInCombat(*it))
|
||||
{
|
||||
MWBase::Environment::get().getMechanicsManager()->startCombat(actor1, actor2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, don't initiate combat with an unreachable target
|
||||
if (!MWMechanics::canFight(actor1,actor2))
|
||||
return;
|
||||
|
||||
bool aggressive = false;
|
||||
|
||||
if (againstPlayer || std::find(playerFollowersAndEscorters.begin(), playerFollowersAndEscorters.end(), actor2) != playerFollowersAndEscorters.end())
|
||||
{
|
||||
// Player followers and escorters with high fight should not initiate combat here with the player or with
|
||||
// other player followers or escorters
|
||||
if (std::find(playerFollowersAndEscorters.begin(), playerFollowersAndEscorters.end(), actor1) != playerFollowersAndEscorters.end())
|
||||
return;
|
||||
|
||||
aggressive = MWBase::Environment::get().getMechanicsManager()->isAggressive(actor1, actor2);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make guards fight aggressive creatures
|
||||
if (!actor1.getClass().isNpc() && actor2.getClass().isClass(actor2, "Guard"))
|
||||
{
|
||||
if (creatureStats1.getAiSequence().isInCombat() && MWBase::Environment::get().getMechanicsManager()->isAggressive(actor1, actor2))
|
||||
aggressive = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (aggressive)
|
||||
{
|
||||
bool LOS = MWBase::Environment::get().getWorld()->getLOS(actor1, actor2);
|
||||
|
||||
if (againstPlayer) LOS &= MWBase::Environment::get().getMechanicsManager()->awarenessCheck(actor2, actor1);
|
||||
if (againstPlayer || std::find(playerFollowersAndEscorters.begin(), playerFollowersAndEscorters.end(), actor2) != playerFollowersAndEscorters.end())
|
||||
LOS &= MWBase::Environment::get().getMechanicsManager()->awarenessCheck(actor2, actor1);
|
||||
|
||||
if (LOS)
|
||||
{
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "aicombataction.hpp"
|
||||
#include "combat.hpp"
|
||||
#include "coordinateconverter.hpp"
|
||||
#include "actorutil.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
@ -210,13 +211,14 @@ namespace MWMechanics
|
||||
else
|
||||
{
|
||||
timerReact = 0;
|
||||
attack(actor, target, storage, characterController);
|
||||
if (attack(actor, target, storage, characterController))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void AiCombat::attack(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, AiCombatStorage& storage, CharacterController& characterController)
|
||||
bool AiCombat::attack(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, AiCombatStorage& storage, CharacterController& characterController)
|
||||
{
|
||||
const MWWorld::CellStore*& currentCell = storage.mCell;
|
||||
bool cellChange = currentCell && (actor.getCell() != currentCell);
|
||||
@ -231,7 +233,10 @@ namespace MWMechanics
|
||||
storage.stopAttack();
|
||||
characterController.setAttackingOrSpell(false);
|
||||
storage.mActionCooldown = 0.f;
|
||||
if (target == MWMechanics::getPlayer())
|
||||
forceFlee = true;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
const MWWorld::Class& actorClass = actor.getClass();
|
||||
@ -243,7 +248,7 @@ namespace MWMechanics
|
||||
if (!forceFlee)
|
||||
{
|
||||
if (actionCooldown > 0)
|
||||
return;
|
||||
return false;
|
||||
|
||||
if (characterController.readyToPrepareAttack())
|
||||
{
|
||||
@ -258,7 +263,7 @@ namespace MWMechanics
|
||||
}
|
||||
|
||||
if (!currentAction)
|
||||
return;
|
||||
return false;
|
||||
|
||||
if (storage.isFleeing() != currentAction->isFleeing())
|
||||
{
|
||||
@ -266,7 +271,7 @@ namespace MWMechanics
|
||||
{
|
||||
storage.startFleeing();
|
||||
MWBase::Environment::get().getDialogueManager()->say(actor, "flee");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
storage.stopFleeing();
|
||||
@ -311,6 +316,7 @@ namespace MWMechanics
|
||||
storage.mMovement.mRotation[2] = getZAngleToDir((vTargetPos-vActorPos)); // using vAimDir results in spastic movements since the head is animated
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MWMechanics::AiCombat::updateLOS(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, MWMechanics::AiCombatStorage& storage)
|
||||
|
@ -59,7 +59,8 @@ namespace MWMechanics
|
||||
|
||||
int mTargetActorId;
|
||||
|
||||
void attack(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, AiCombatStorage& storage, CharacterController& characterController);
|
||||
/// Returns true if combat should end
|
||||
bool 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);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user