From 28feb260eb8fd675dca04f8da2dc0dc88e3e043a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 16 Jun 2014 19:34:53 +0200 Subject: [PATCH] Implement disposition/distance based aggression (Fixes #1520) --- apps/openmw/mwbase/mechanicsmanager.hpp | 2 ++ apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/npc.cpp | 3 +-- apps/openmw/mwdialogue/filter.cpp | 3 ++- apps/openmw/mwmechanics/actors.cpp | 22 +++++++--------- .../mwmechanics/mechanicsmanagerimp.cpp | 25 +++++++++++++++++++ .../mwmechanics/mechanicsmanagerimp.hpp | 2 ++ 7 files changed, 42 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 30a576a15..07d4eb2bc 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -191,6 +191,8 @@ namespace MWBase virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0; virtual void clear() = 0; + + virtual bool isAggressive (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target) = 0; }; } diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 10c318367..59c1087f9 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -345,7 +345,7 @@ namespace MWClass getCreatureStats(ptr).setAttacked(true); // Self defense - if (!attacker.isEmpty() && ptr.getClass().getCreatureStats(ptr).getAiSetting(MWMechanics::CreatureStats::AI_Fight).getModified() < 80 + if (!attacker.isEmpty() && !MWBase::Environment::get().getMechanicsManager()->isAggressive(ptr, attacker) && (canWalk(ptr) || canFly(ptr) || canSwim(ptr))) // No retaliation for totally static creatures // (they have no movement or attacks anyway) MWBase::Environment::get().getMechanicsManager()->startCombat(ptr, attacker); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 6d5ff9f7f..2b4c54e24 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -624,9 +624,8 @@ namespace MWClass // NOTE: 'object' and/or 'attacker' may be empty. // Attacking peaceful NPCs is a crime - // anything below 80 is considered peaceful (see Actors::updateActor) if (!attacker.isEmpty() && !ptr.getClass().getCreatureStats(ptr).isHostile() && - ptr.getClass().getCreatureStats(ptr).getAiSetting(MWMechanics::CreatureStats::AI_Fight).getModified() < 80) + !MWBase::Environment::get().getMechanicsManager()->isAggressive(ptr, attacker)) MWBase::Environment::get().getMechanicsManager()->commitCrime(attacker, ptr, MWBase::MechanicsManager::OT_Assault); getCreatureStats(ptr).setAttacked(true); diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index d301e88aa..08cdb1d00 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -530,7 +530,8 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co case SelectWrapper::Function_ShouldAttack: - return mActor.getClass().getCreatureStats(mActor).getAiSetting(MWMechanics::CreatureStats::AI_Fight).getModified() >= 80; + return MWBase::Environment::get().getMechanicsManager()->isAggressive(mActor, + MWBase::Environment::get().getWorld()->getPlayerPtr()); case SelectWrapper::Function_CreatureTargetted: diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index e9e9fbe28..ddb3087dd 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -201,32 +201,28 @@ namespace MWMechanics || (!actor1.getClass().canSwim(actor1) && MWBase::Environment::get().getWorld()->isSwimming(actor2)))) // creature can't swim to target return; - float fight; + bool aggressive; if (againstPlayer) - fight = actor1.getClass().getCreatureStats(actor1).getAiSetting(CreatureStats::AI_Fight).getModified(); + aggressive = MWBase::Environment::get().getMechanicsManager()->isAggressive(actor1, actor2); else { - fight = 0; + aggressive = false; // if one of actors is creature then we should make a decision to start combat or not // NOTE: function doesn't take into account combat between 2 creatures if (!actor1.getClass().isNpc()) { // if creature is hostile then it is necessarily to start combat - if (creatureStats.isHostile()) fight = 100; - else fight = creatureStats.getAiSetting(CreatureStats::AI_Fight).getModified(); + if (creatureStats.isHostile()) aggressive = true; + else aggressive = MWBase::Environment::get().getMechanicsManager()->isAggressive(actor1, actor2); } } - ESM::Position actor1Pos = actor1.getRefData().getPosition(); - ESM::Position actor2Pos = actor2.getRefData().getPosition(); - float d = Ogre::Vector3(actor1Pos.pos).distance(Ogre::Vector3(actor2Pos.pos)); - - if( (fight == 100 && d <= 5000) - || (fight >= 95 && d <= 3000) - || (fight >= 90 && d <= 2000) - || (fight >= 80 && d <= 1000)) + if(aggressive) { + const ESM::Position& actor1Pos = actor2.getRefData().getPosition(); + const ESM::Position& actor2Pos = actor2.getRefData().getPosition(); + float d = Ogre::Vector3(actor1Pos.pos).distance(Ogre::Vector3(actor2Pos.pos)); if (againstPlayer || actor2.getClass().getCreatureStats(actor2).getAiSequence().canAddTarget(actor2Pos, d)) { bool LOS = MWBase::Environment::get().getWorld()->getLOS(actor1, actor2); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 79b121b31..4d6930135 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1098,4 +1098,29 @@ namespace MWMechanics { mActors.clear(); } + + bool MechanicsManager::isAggressive(const MWWorld::Ptr &ptr, const MWWorld::Ptr &target) + { + Ogre::Vector3 pos1 (ptr.getRefData().getPosition().pos); + Ogre::Vector3 pos2 (target.getRefData().getPosition().pos); + + float d = pos1.distance(pos2); + + static int iFightDistanceBase = MWBase::Environment::get().getWorld()->getStore().get().find( + "iFightDistanceBase")->getInt(); + static float fFightDistanceMultiplier = MWBase::Environment::get().getWorld()->getStore().get().find( + "fFightDistanceMultiplier")->getFloat(); + static float fFightDispMult = MWBase::Environment::get().getWorld()->getStore().get().find( + "fFightDispMult")->getFloat(); + + int disposition = 50; + if (ptr.getClass().isNpc()) + disposition = getDerivedDisposition(ptr); + + int fight = ptr.getClass().getCreatureStats(ptr).getAiSetting(CreatureStats::AI_Fight).getModified() + + (iFightDistanceBase - fFightDistanceMultiplier * d) + + ((50 - disposition) * fFightDispMult); + + return (fight >= 100); + } } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 714537a38..677d60ae5 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -156,6 +156,8 @@ namespace MWMechanics virtual void readRecord (ESM::ESMReader& reader, int32_t type); virtual void clear(); + + virtual bool isAggressive (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target); }; }