From 453068cc7d5f73cbae5f3087dbfa4b28aeea684d Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Thu, 27 Jun 2019 19:50:54 +0300 Subject: [PATCH] Disallow actors to start combat with themselves (bug #3550) Allow creatures to play initial attack dialogue Don't add combat package to dead actors --- CHANGELOG.md | 1 + apps/openmw/mwmechanics/aicombat.cpp | 3 +++ .../mwmechanics/mechanicsmanagerimp.cpp | 21 +++++++++++++------ 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4770d0a24..c9002fcb0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ Bug #3006: 'else if' operator breaks script compilation Bug #3109: SetPos/Position handles actors differently Bug #3282: Unintended behaviour when assigning F3 and Windows keys + Bug #3550: Companion from mod attacks the air after combat has ended Bug #3623: Display scaling breaks mouse recognition Bug #3725: Using script function in a non-conditional expression breaks script compilation Bug #3733: Normal maps are inverted on mirrored UVs diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 32b3f9f2b..78e65ce15 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -116,6 +116,9 @@ namespace MWMechanics || target.getClass().getCreatureStats(target).isDead()) return true; + if (actor == target) // This should never happen. + return true; + if (!storage.isFleeing()) { if (storage.mCurrentAction.get()) // need to wait to init action with its attack range diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 234c39aaa..23f5ea01d 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1647,18 +1647,28 @@ namespace MWMechanics void MechanicsManager::startCombat(const MWWorld::Ptr &ptr, const MWWorld::Ptr &target) { - MWMechanics::AiSequence& aiSequence = ptr.getClass().getCreatureStats(ptr).getAiSequence(); + CreatureStats& stats = ptr.getClass().getCreatureStats(ptr); - if (aiSequence.isInCombat(target)) + // Don't add duplicate packages nor add packages to dead actors. + if (stats.isDead() || stats.getAiSequence().isInCombat(target)) return; - aiSequence.stack(MWMechanics::AiCombat(target), ptr); + // The target is somehow the same as the actor. Early-out. + if (ptr == target) + { + // We don't care about dialogue filters since the target is invalid. + // We still want to play the combat taunt. + MWBase::Environment::get().getDialogueManager()->say(ptr, "attack"); + return; + } + + stats.getAiSequence().stack(MWMechanics::AiCombat(target), ptr); if (target == getPlayer()) { // if guard starts combat with player, guards pursuing player should do the same if (ptr.getClass().isClass(ptr, "Guard")) { - ptr.getClass().getCreatureStats(ptr).setHitAttemptActorId(target.getClass().getCreatureStats(target).getActorId()); // Stops guard from ending combat if player is unreachable + stats.setHitAttemptActorId(target.getClass().getCreatureStats(target).getActorId()); // Stops guard from ending combat if player is unreachable for (Actors::PtrActorMap::const_iterator iter = mActors.begin(); iter != mActors.end(); ++iter) { if (iter->first.getClass().isClass(iter->first, "Guard")) @@ -1676,8 +1686,7 @@ namespace MWMechanics } // Must be done after the target is set up, so that CreatureTargetted dialogue filter works properly - if (ptr.getClass().isNpc() && !ptr.getClass().getCreatureStats(ptr).isDead()) - MWBase::Environment::get().getDialogueManager()->say(ptr, "attack"); + MWBase::Environment::get().getDialogueManager()->say(ptr, "attack"); } void MechanicsManager::getObjectsInRange(const osg::Vec3f &position, float radius, std::vector &objects)