Remove allies from combat when stopping combat

switch-to-ppa
Evil Eye 3 years ago
parent a231037449
commit d6f06fbf9a

@ -2,6 +2,7 @@
------
Bug #1751: Birthsign abilities increase modified attribute values instead of base ones
Bug #1930: Followers are still fighting if a target stops combat with a leader
Bug #3246: ESSImporter: Most NPCs are dead on save load
Bug #3488: AI combat aiming is too slow
Bug #3514: Editing a reference's position after loading an esp file makes the reference disappear

@ -112,6 +112,9 @@ namespace MWBase
/// Makes \a ptr fight \a target. Also shouts a combat taunt.
virtual void startCombat (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target) = 0;
/// Removes an actor and its allies from combat with the actor's targets.
virtual void stopCombat(const MWWorld::Ptr& ptr) = 0;
enum OffenseType
{
OT_Theft, // Taking items owned by an NPC or a faction you are not a member of

@ -443,6 +443,22 @@ namespace MWMechanics
}
}
void Actors::stopCombat(const MWWorld::Ptr& ptr)
{
auto& ai = ptr.getClass().getCreatureStats(ptr).getAiSequence();
std::vector<MWWorld::Ptr> targets;
if(ai.getCombatTargets(targets))
{
std::set<MWWorld::Ptr> allySet;
getActorsSidingWith(ptr, allySet);
std::vector<MWWorld::Ptr> allies(allySet.begin(), allySet.end());
for(const auto& ally : allies)
ally.getClass().getCreatureStats(ally).getAiSequence().stopCombat(targets);
for(const auto& target : targets)
target.getClass().getCreatureStats(target).getAiSequence().stopCombat(allies);
}
}
void Actors::engageCombat (const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, std::map<const MWWorld::Ptr, const std::set<MWWorld::Ptr> >& cachedAllies, bool againstPlayer)
{
// No combat for totally static creatures
@ -979,7 +995,7 @@ namespace MWMechanics
// Calm witness down
if (ptr.getClass().isClass(ptr, "Guard"))
creatureStats.getAiSequence().stopPursuit();
creatureStats.getAiSequence().stopCombat();
stopCombat(ptr);
// Reset factors to attack
creatureStats.setAttacked(false);
@ -1967,7 +1983,7 @@ namespace MWMechanics
if (stats.isDead())
continue;
// An actor counts as siding with this actor if Follow or Escort is the current AI package, or there are only Combat and Wander packages before the Follow/Escort package
// An actor counts as siding with this actor if Follow or Escort is the current AI package, or there are only Wander packages before the Follow/Escort package
// Actors that are targeted by this actor's Follow or Escort packages also side with them
for (const auto& package : stats.getAiSequence())
{
@ -1983,7 +1999,7 @@ namespace MWMechanics
}
break;
}
else if (package->getTypeId() != AiPackageTypeId::Combat && package->getTypeId() != AiPackageTypeId::Wander)
else if (package->getTypeId() > AiPackageTypeId::Wander && package->getTypeId() <= AiPackageTypeId::Activate) // Don't count "fake" package types
break;
}
}

@ -111,6 +111,8 @@ namespace MWMechanics
///< This function is normally called automatically during the update process, but it can
/// also be called explicitly at any time to force an update.
/// Removes an actor from combat and makes all of their allies stop fighting the actor's targets
void stopCombat(const MWWorld::Ptr& ptr);
/** Start combat between two actors
@Notes: If againstPlayer = true then actor2 should be the Player.
If one of the combatants is creature it should be actor1.

@ -158,6 +158,7 @@ bool AiSequence::isInCombat(const MWWorld::Ptr &actor) const
return false;
}
// TODO: use std::list::remove_if for all these methods when we switch to C++20
void AiSequence::stopCombat()
{
for(auto it = mPackages.begin(); it != mPackages.end(); )
@ -171,6 +172,19 @@ void AiSequence::stopCombat()
}
}
void AiSequence::stopCombat(const std::vector<MWWorld::Ptr>& targets)
{
for(auto it = mPackages.begin(); it != mPackages.end(); )
{
if ((*it)->getTypeId() == AiPackageTypeId::Combat && std::find(targets.begin(), targets.end(), (*it)->getTarget()) != targets.end())
{
it = mPackages.erase(it);
}
else
++it;
}
}
void AiSequence::stopPursuit()
{
for(auto it = mPackages.begin(); it != mPackages.end(); )

@ -102,6 +102,9 @@ namespace MWMechanics
/// Removes all combat packages until first non-combat or stack empty.
void stopCombat();
/// Removes all combat packages with the given targets
void stopCombat(const std::vector<MWWorld::Ptr>& targets);
/// Has a package been completed during the last update?
bool isPackageDone() const;

@ -1607,6 +1607,11 @@ namespace MWMechanics
MWBase::Environment::get().getDialogueManager()->say(ptr, "attack");
}
void MechanicsManager::stopCombat(const MWWorld::Ptr& actor)
{
mActors.stopCombat(actor);
}
void MechanicsManager::getObjectsInRange(const osg::Vec3f &position, float radius, std::vector<MWWorld::Ptr> &objects)
{
mActors.getObjectsInRange(position, radius, objects);

@ -102,6 +102,8 @@ namespace MWMechanics
/// Makes \a ptr fight \a target. Also shouts a combat taunt.
void startCombat (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target) override;
void stopCombat(const MWWorld::Ptr& ptr) override;
/**
* @note victim may be empty
* @param arg Depends on \a type, e.g. for Theft, the value of the item that was stolen.

@ -515,8 +515,7 @@ namespace MWScript
MWWorld::Ptr actor = R()(runtime);
if (!actor.getClass().isActor())
return;
MWMechanics::CreatureStats& creatureStats = actor.getClass().getCreatureStats(actor);
creatureStats.getAiSequence().stopCombat();
MWBase::Environment::get().getMechanicsManager()->stopCombat(actor);
}
};

Loading…
Cancel
Save