Implement disposition/distance based aggression (Fixes #1520)

deque
scrawl 11 years ago
parent d11a5e19f7
commit 28feb260eb

@ -191,6 +191,8 @@ namespace MWBase
virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0; virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0;
virtual void clear() = 0; virtual void clear() = 0;
virtual bool isAggressive (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target) = 0;
}; };
} }

@ -345,7 +345,7 @@ namespace MWClass
getCreatureStats(ptr).setAttacked(true); getCreatureStats(ptr).setAttacked(true);
// Self defense // 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 && (canWalk(ptr) || canFly(ptr) || canSwim(ptr))) // No retaliation for totally static creatures
// (they have no movement or attacks anyway) // (they have no movement or attacks anyway)
MWBase::Environment::get().getMechanicsManager()->startCombat(ptr, attacker); MWBase::Environment::get().getMechanicsManager()->startCombat(ptr, attacker);

@ -624,9 +624,8 @@ namespace MWClass
// NOTE: 'object' and/or 'attacker' may be empty. // NOTE: 'object' and/or 'attacker' may be empty.
// Attacking peaceful NPCs is a crime // Attacking peaceful NPCs is a crime
// anything below 80 is considered peaceful (see Actors::updateActor)
if (!attacker.isEmpty() && !ptr.getClass().getCreatureStats(ptr).isHostile() && 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); MWBase::Environment::get().getMechanicsManager()->commitCrime(attacker, ptr, MWBase::MechanicsManager::OT_Assault);
getCreatureStats(ptr).setAttacked(true); getCreatureStats(ptr).setAttacked(true);

@ -530,7 +530,8 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co
case SelectWrapper::Function_ShouldAttack: 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: case SelectWrapper::Function_CreatureTargetted:

@ -201,32 +201,28 @@ namespace MWMechanics
|| (!actor1.getClass().canSwim(actor1) && MWBase::Environment::get().getWorld()->isSwimming(actor2)))) // creature can't swim to target || (!actor1.getClass().canSwim(actor1) && MWBase::Environment::get().getWorld()->isSwimming(actor2)))) // creature can't swim to target
return; return;
float fight; bool aggressive;
if (againstPlayer) if (againstPlayer)
fight = actor1.getClass().getCreatureStats(actor1).getAiSetting(CreatureStats::AI_Fight).getModified(); aggressive = MWBase::Environment::get().getMechanicsManager()->isAggressive(actor1, actor2);
else else
{ {
fight = 0; aggressive = false;
// if one of actors is creature then we should make a decision to start combat or not // 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 // NOTE: function doesn't take into account combat between 2 creatures
if (!actor1.getClass().isNpc()) if (!actor1.getClass().isNpc())
{ {
// if creature is hostile then it is necessarily to start combat // if creature is hostile then it is necessarily to start combat
if (creatureStats.isHostile()) fight = 100; if (creatureStats.isHostile()) aggressive = true;
else fight = creatureStats.getAiSetting(CreatureStats::AI_Fight).getModified(); else aggressive = MWBase::Environment::get().getMechanicsManager()->isAggressive(actor1, actor2);
} }
} }
ESM::Position actor1Pos = actor1.getRefData().getPosition(); if(aggressive)
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))
{ {
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)) if (againstPlayer || actor2.getClass().getCreatureStats(actor2).getAiSequence().canAddTarget(actor2Pos, d))
{ {
bool LOS = MWBase::Environment::get().getWorld()->getLOS(actor1, actor2); bool LOS = MWBase::Environment::get().getWorld()->getLOS(actor1, actor2);

@ -1098,4 +1098,29 @@ namespace MWMechanics
{ {
mActors.clear(); 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<ESM::GameSetting>().find(
"iFightDistanceBase")->getInt();
static float fFightDistanceMultiplier = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
"fFightDistanceMultiplier")->getFloat();
static float fFightDispMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().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);
}
} }

@ -156,6 +156,8 @@ namespace MWMechanics
virtual void readRecord (ESM::ESMReader& reader, int32_t type); virtual void readRecord (ESM::ESMReader& reader, int32_t type);
virtual void clear(); virtual void clear();
virtual bool isAggressive (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target);
}; };
} }

Loading…
Cancel
Save