mirror of
https://github.com/OpenMW/openmw.git
synced 2025-04-05 12:06:40 +00:00
Remove allies from combat when stopping combat
This commit is contained in:
parent
a231037449
commit
d6f06fbf9a
9 changed files with 50 additions and 5 deletions
CHANGELOG.md
apps/openmw
|
@ -2,6 +2,7 @@
|
||||||
------
|
------
|
||||||
|
|
||||||
Bug #1751: Birthsign abilities increase modified attribute values instead of base ones
|
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 #3246: ESSImporter: Most NPCs are dead on save load
|
||||||
Bug #3488: AI combat aiming is too slow
|
Bug #3488: AI combat aiming is too slow
|
||||||
Bug #3514: Editing a reference's position after loading an esp file makes the reference disappear
|
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.
|
/// Makes \a ptr fight \a target. Also shouts a combat taunt.
|
||||||
virtual void startCombat (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target) = 0;
|
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
|
enum OffenseType
|
||||||
{
|
{
|
||||||
OT_Theft, // Taking items owned by an NPC or a faction you are not a member of
|
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)
|
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
|
// No combat for totally static creatures
|
||||||
|
@ -979,7 +995,7 @@ namespace MWMechanics
|
||||||
// Calm witness down
|
// Calm witness down
|
||||||
if (ptr.getClass().isClass(ptr, "Guard"))
|
if (ptr.getClass().isClass(ptr, "Guard"))
|
||||||
creatureStats.getAiSequence().stopPursuit();
|
creatureStats.getAiSequence().stopPursuit();
|
||||||
creatureStats.getAiSequence().stopCombat();
|
stopCombat(ptr);
|
||||||
|
|
||||||
// Reset factors to attack
|
// Reset factors to attack
|
||||||
creatureStats.setAttacked(false);
|
creatureStats.setAttacked(false);
|
||||||
|
@ -1967,7 +1983,7 @@ namespace MWMechanics
|
||||||
if (stats.isDead())
|
if (stats.isDead())
|
||||||
continue;
|
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
|
// Actors that are targeted by this actor's Follow or Escort packages also side with them
|
||||||
for (const auto& package : stats.getAiSequence())
|
for (const auto& package : stats.getAiSequence())
|
||||||
{
|
{
|
||||||
|
@ -1983,7 +1999,7 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
break;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,6 +111,8 @@ namespace MWMechanics
|
||||||
///< This function is normally called automatically during the update process, but it can
|
///< This function is normally called automatically during the update process, but it can
|
||||||
/// also be called explicitly at any time to force an update.
|
/// 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
|
/** Start combat between two actors
|
||||||
@Notes: If againstPlayer = true then actor2 should be the Player.
|
@Notes: If againstPlayer = true then actor2 should be the Player.
|
||||||
If one of the combatants is creature it should be actor1.
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: use std::list::remove_if for all these methods when we switch to C++20
|
||||||
void AiSequence::stopCombat()
|
void AiSequence::stopCombat()
|
||||||
{
|
{
|
||||||
for(auto it = mPackages.begin(); it != mPackages.end(); )
|
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()
|
void AiSequence::stopPursuit()
|
||||||
{
|
{
|
||||||
for(auto it = mPackages.begin(); it != mPackages.end(); )
|
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.
|
/// Removes all combat packages until first non-combat or stack empty.
|
||||||
void stopCombat();
|
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?
|
/// Has a package been completed during the last update?
|
||||||
bool isPackageDone() const;
|
bool isPackageDone() const;
|
||||||
|
|
||||||
|
|
|
@ -1607,6 +1607,11 @@ namespace MWMechanics
|
||||||
MWBase::Environment::get().getDialogueManager()->say(ptr, "attack");
|
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)
|
void MechanicsManager::getObjectsInRange(const osg::Vec3f &position, float radius, std::vector<MWWorld::Ptr> &objects)
|
||||||
{
|
{
|
||||||
mActors.getObjectsInRange(position, radius, objects);
|
mActors.getObjectsInRange(position, radius, objects);
|
||||||
|
|
|
@ -102,6 +102,8 @@ namespace MWMechanics
|
||||||
/// Makes \a ptr fight \a target. Also shouts a combat taunt.
|
/// Makes \a ptr fight \a target. Also shouts a combat taunt.
|
||||||
void startCombat (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target) override;
|
void startCombat (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target) override;
|
||||||
|
|
||||||
|
void stopCombat(const MWWorld::Ptr& ptr) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @note victim may be empty
|
* @note victim may be empty
|
||||||
* @param arg Depends on \a type, e.g. for Theft, the value of the item that was stolen.
|
* @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);
|
MWWorld::Ptr actor = R()(runtime);
|
||||||
if (!actor.getClass().isActor())
|
if (!actor.getClass().isActor())
|
||||||
return;
|
return;
|
||||||
MWMechanics::CreatureStats& creatureStats = actor.getClass().getCreatureStats(actor);
|
MWBase::Environment::get().getMechanicsManager()->stopCombat(actor);
|
||||||
creatureStats.getAiSequence().stopCombat();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue