From cc081c3d2d05a11ea39d1d89dce332dcdd736d75 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Tue, 23 Nov 2021 22:44:47 +0100 Subject: [PATCH 1/2] Don't add additional targets to allies that are already in combat --- CHANGELOG.md | 2 ++ apps/openmw/mwmechanics/actors.cpp | 3 +++ apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 7 +++++++ 3 files changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a95e960528..4d6918cffc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ Bug #3792: 1 frame late magicka recalc breaks early scripted magicka reactions to Intelligence change Bug #3846: Strings starting with "-" fail to compile if not enclosed in quotes Bug #3855: AI sometimes spams defensive spells + Bug #3867: All followers attack player when one follower enters combat with player Bug #3905: Great House Dagoth issues Bug #4203: Resurrecting an actor doesn't close the loot GUI Bug #4376: Moved actors don't respawn in their original cells @@ -26,6 +27,7 @@ Bug #5192: Actor turn rate is too slow Bug #5207: Loose summons can be present in scene Bug #5279: Ingame console stops auto-scrolling after clicking output + Bug #5318: Aiescort behaves differently from vanilla Bug #5371: 'Dead' slaughterfish added by mod are animated/alive Bug #5377: Console does not appear after using menutest in inventory Bug #5379: Wandering NPCs falling through cantons diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 2353f3729d..c0165f507b 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -501,6 +501,9 @@ namespace MWMechanics // If an ally of actor1 has been attacked by actor2 or has attacked actor2, start combat between actor1 and actor2 for (const MWWorld::Ptr& ally : allies1) { + // Don't let allies that are already in combat choose additional sides + if (ally.getClass().getCreatureStats(ally).getAiSequence().isInCombat()) + continue; if (creatureStats1.getAiSequence().isInCombat(ally)) continue; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 2fd5a81f0d..f20381ea91 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1457,7 +1457,14 @@ namespace MWMechanics } if (!peaceful) + { startCombat(target, attacker); + // Force friendly actors into combat to prevent infighting between followers + std::set followersTarget; + getActorsSidingWith(target, followersTarget); + for(const auto& follower : followersTarget) + startCombat(follower, attacker); + } } } From b79c42fa77ec6104d409652570298846ec3569d6 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sat, 27 Nov 2021 14:20:55 +0100 Subject: [PATCH 2/2] Exclude followers in combat with their leader --- apps/openmw/mwmechanics/actors.cpp | 23 +++++++++++++++-------- apps/openmw/mwmechanics/actors.hpp | 21 ++++++++++++--------- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index c0165f507b..b24149827c 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -501,9 +501,6 @@ namespace MWMechanics // If an ally of actor1 has been attacked by actor2 or has attacked actor2, start combat between actor1 and actor2 for (const MWWorld::Ptr& ally : allies1) { - // Don't let allies that are already in combat choose additional sides - if (ally.getClass().getCreatureStats(ally).getAiSequence().isInCombat()) - continue; if (creatureStats1.getAiSequence().isInCombat(ally)) continue; @@ -1983,7 +1980,7 @@ namespace MWMechanics return false; } - std::vector Actors::getActorsSidingWith(const MWWorld::Ptr& actorPtr) + std::vector Actors::getActorsSidingWith(const MWWorld::Ptr& actorPtr, bool excludeInfighting) { std::vector list; for (const Actor& actor : mActors) @@ -2002,10 +1999,20 @@ namespace MWMechanics // Actors that are targeted by this actor's Follow or Escort packages also side with them for (const auto& package : stats.getAiSequence()) { + if (excludeInfighting && !sameActor && package->getTypeId() == AiPackageTypeId::Combat && package->getTarget() == actorPtr) + break; if (package->sideWithTarget() && !package->getTarget().isEmpty()) { if (sameActor) { + if(excludeInfighting) + { + MWWorld::Ptr ally = package->getTarget(); + std::vector enemies; + if(ally.getClass().getCreatureStats(ally).getAiSequence().getCombatTargets(enemies) + && std::find(enemies.begin(), enemies.end(), actorPtr) != enemies.end()) + break; + } list.push_back(package->getTarget()); } else if (package->getTarget() == actorPtr) @@ -2042,11 +2049,11 @@ namespace MWMechanics getActorsFollowing(follower, out); } - void Actors::getActorsSidingWith(const MWWorld::Ptr &actor, std::set& out) { - auto followers = getActorsSidingWith(actor); + void Actors::getActorsSidingWith(const MWWorld::Ptr &actor, std::set& out, bool excludeInfighting) { + auto followers = getActorsSidingWith(actor, excludeInfighting); for(const MWWorld::Ptr &follower : followers) if (out.insert(follower).second) - getActorsSidingWith(follower, out); + getActorsSidingWith(follower, out, excludeInfighting); } void Actors::getActorsSidingWith(const MWWorld::Ptr &actor, std::set& out, std::map >& cachedAllies) { @@ -2056,7 +2063,7 @@ namespace MWMechanics out.insert(search->second.begin(), search->second.end()); else { - auto followers = getActorsSidingWith(actor); + auto followers = getActorsSidingWith(actor, true); for (const MWWorld::Ptr &follower : followers) if (out.insert(follower).second) getActorsSidingWith(follower, out, cachedAllies); diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 547c2916e2..7b54a98198 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -93,11 +93,6 @@ namespace MWMechanics /// 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. - */ - void engageCombat(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, std::map >& cachedAllies, bool againstPlayer); void playIdleDialogue(const MWWorld::Ptr& actor); void updateMovementSpeed(const MWWorld::Ptr& actor); @@ -144,15 +139,13 @@ namespace MWMechanics ///Returns the list of actors which are siding with the given actor in fights /**ie AiFollow or AiEscort is active and the target is the actor **/ - std::vector getActorsSidingWith(const MWWorld::Ptr& actor); + std::vector getActorsSidingWith(const MWWorld::Ptr& actor, bool excludeInfighting = false); std::vector getActorsFollowing(const MWWorld::Ptr& actor); /// Recursive version of getActorsFollowing void getActorsFollowing(const MWWorld::Ptr &actor, std::set& out); /// Recursive version of getActorsSidingWith - void getActorsSidingWith(const MWWorld::Ptr &actor, std::set& out); - /// Recursive version of getActorsSidingWith that takes, adds to and returns a cache of actors mapped to their allies - void getActorsSidingWith(const MWWorld::Ptr &actor, std::set& out, std::map >& cachedAllies); + void getActorsSidingWith(const MWWorld::Ptr &actor, std::set& out, bool excludeInfighting = false); /// Get the list of AiFollow::mFollowIndex for all actors following this target std::vector getActorsFollowingIndices(const MWWorld::Ptr& actor); @@ -218,6 +211,16 @@ namespace MWMechanics void purgeSpellEffects (int casterActorId); void predictAndAvoidCollisions(float duration); + + /** 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. + */ + void engageCombat(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, std::map >& cachedAllies, bool againstPlayer); + + /// Recursive version of getActorsSidingWith that takes, adds to and returns a cache of actors mapped to their allies. Excludes infighting + void getActorsSidingWith(const MWWorld::Ptr &actor, std::set& out, std::map >& cachedAllies); + }; }