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 clear() = 0;
virtual bool isAggressive (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target) = 0;
};
}

@ -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);

@ -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);

@ -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:

@ -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);

@ -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<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 clear();
virtual bool isAggressive (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target);
};
}

Loading…
Cancel
Save