diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index f718972b93..532c1c3faa 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -128,6 +128,7 @@ namespace MWBase OffenseType type, int arg=0) = 0; virtual void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, OffenseType type, int arg=0) = 0; + virtual void actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker) = 0; /// Utility to check if taking this item is illegal and calling commitCrime if so virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, int count) = 0; /// Utility to check if opening (i.e. unlocking) this object is illegal and calling commitCrime if so diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index a57b47de42..b6cb0e62db 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -333,16 +333,11 @@ namespace MWClass getCreatureStats(ptr).setAttacked(true); // Self defense - if ( ((!attacker.isEmpty() && attacker.getClass().getCreatureStats(attacker).getAiSequence().isInCombat(ptr)) - || attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) - && !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat(attacker) - && (canWalk(ptr) || canFly(ptr) || canSwim(ptr)) // No retaliation for totally static creatures + if ((canWalk(ptr) || canFly(ptr) || canSwim(ptr)) // No retaliation for totally static creatures // (they have no movement or attacks anyway) - ) + && !attacker.isEmpty()) { - // Attacker is in combat with us, but we are not in combat with the attacker yet. Time to fight back. - // Note: accidental or collateral damage attacks are ignored. - MWBase::Environment::get().getMechanicsManager()->startCombat(ptr, attacker); + MWBase::Environment::get().getMechanicsManager()->actorAttacked(ptr, attacker); } if(!successful) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index f8e5b14cc3..a4a36602d5 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -639,26 +639,13 @@ namespace MWClass // NOTE: 'object' and/or 'attacker' may be empty. - if (ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) - { - // Attacking peaceful NPCs is a crime - if (!attacker.isEmpty() && !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat(attacker) - && !MWBase::Environment::get().getMechanicsManager()->isAggressive(ptr, attacker)) - MWBase::Environment::get().getMechanicsManager()->commitCrime(attacker, ptr, MWBase::MechanicsManager::OT_Assault); - - if (!attacker.isEmpty() && attacker.getClass().getCreatureStats(attacker).getAiSequence().isInCombat(ptr) - && !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat(attacker)) - { - // Attacker is in combat with us, but we are not in combat with the attacker yet. Time to fight back. - // Note: accidental or collateral damage attacks are ignored. - MWBase::Environment::get().getMechanicsManager()->startCombat(ptr, attacker); - } - } - bool wasDead = getCreatureStats(ptr).isDead(); getCreatureStats(ptr).setAttacked(true); + if (!attacker.isEmpty()) + MWBase::Environment::get().getMechanicsManager()->actorAttacked(ptr, attacker); + if(!successful) { // TODO: Handle HitAttemptOnMe script function diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 14298c97d4..ed21fa8a8a 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1106,6 +1106,35 @@ namespace MWMechanics } } + void MechanicsManager::actorAttacked(const MWWorld::Ptr &ptr, const MWWorld::Ptr &attacker) + { + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + return; + + std::list followers = getActorsFollowing(attacker); + if (std::find(followers.begin(), followers.end(), ptr) != followers.end()) + { + ptr.getClass().getCreatureStats(ptr).friendlyHit(); + + if (ptr.getClass().getCreatureStats(ptr).getFriendlyHits() < 4) + return; + } + + // Attacking peaceful NPCs is a crime + if (ptr.getClass().isNpc() && !attacker.isEmpty() && !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat(attacker) + && !isAggressive(ptr, attacker)) + commitCrime(attacker, ptr, MWBase::MechanicsManager::OT_Assault); + + if (!attacker.isEmpty() && (attacker.getClass().getCreatureStats(attacker).getAiSequence().isInCombat(ptr) + || attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) + && !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat(attacker)) + { + // Attacker is in combat with us, but we are not in combat with the attacker yet. Time to fight back. + // Note: accidental or collateral damage attacks are ignored. + startCombat(ptr, attacker); + } + } + bool MechanicsManager::awarenessCheck(const MWWorld::Ptr &ptr, const MWWorld::Ptr &observer) { if (observer.getClass().getCreatureStats(observer).isDead()) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 365e240677..7dbc6da74f 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -119,6 +119,7 @@ namespace MWMechanics OffenseType type, int arg=0); virtual void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, OffenseType type, int arg=0); + virtual void actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker); /// Utility to check if taking this item is illegal and calling commitCrime if so virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, int count); /// Utility to check if opening (i.e. unlocking) this object is illegal and calling commitCrime if so