Consider weapon ammunition in combat AI (Fixes #1576)

deque
scrawl 10 years ago
parent f1d72419de
commit 0bdc1b243a

@ -73,14 +73,16 @@ namespace MWMechanics
return rateEffects(potion->mEffects, actor, MWWorld::Ptr());
}
float rateWeapon (const MWWorld::Ptr &item, const MWWorld::Ptr& actor, const MWWorld::Ptr& target)
float rateWeapon (const MWWorld::Ptr &item, const MWWorld::Ptr& actor, const MWWorld::Ptr& target, int type,
float arrowRating, float boltRating)
{
if (item.getTypeName() != typeid(ESM::Weapon).name())
return 0.f;
const ESM::Weapon* weapon = item.get<ESM::Weapon>()->mBase;
// TODO: Check that we have ammunition if needed
if (type != -1 && weapon->mData.mType != type)
return 0.f;
float rating=0.f;
@ -102,7 +104,20 @@ namespace MWMechanics
if (item.getClass().hasItemHealth(item))
rating *= item.getClass().getItemHealth(item) / float(item.getClass().getItemMaxHealth(item));
rating *= actor.getClass().getSkill(actor, item.getClass().getEquipmentSkill(item)) / 100.f;
if (weapon->mData.mType == ESM::Weapon::MarksmanBow)
{
if (arrowRating <= 0.f)
rating = 0.f;
else
rating += arrowRating;
}
else if (weapon->mData.mType == ESM::Weapon::MarksmanCrossbow)
{
if (boltRating <= 0.f)
rating = 0.f;
else
rating += boltRating;
}
if (!weapon->mEnchant.empty())
{
@ -112,6 +127,11 @@ namespace MWMechanics
|| item.getCellRef().getEnchantmentCharge() >= enchantment->mData.mCost))
rating += rateEffects(enchantment->mEffects, actor, target);
}
int skill = item.getClass().getEquipmentSkill(item);
if (skill != -1)
rating *= actor.getClass().getSkill(actor, skill) / 100.f;
return rating;
}
@ -323,7 +343,12 @@ namespace MWMechanics
MWWorld::ActionEquip equip(mWeapon);
equip.execute(actor);
}
// TODO: equip ammunition and shield where needed
if (!mAmmunition.isEmpty())
{
MWWorld::ActionEquip equip(mAmmunition);
equip.execute(actor);
}
}
actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Weapon);
}
@ -365,13 +390,50 @@ namespace MWMechanics
}
}
float bestArrowRating = 0;
MWWorld::Ptr bestArrow;
for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
{
float rating = rateWeapon(*it, actor, target, ESM::Weapon::Arrow);
if (rating > bestArrowRating)
{
bestArrowRating = rating;
bestArrow = *it;
}
}
float bestBoltRating = 0;
MWWorld::Ptr bestBolt;
for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
{
float rating = rateWeapon(*it, actor, target, ESM::Weapon::Bolt);
if (rating > bestBoltRating)
{
bestBoltRating = rating;
bestBolt = *it;
}
}
for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
{
float rating = rateWeapon(*it, actor, target);
std::vector<int> equipmentSlots = it->getClass().getEquipmentSlots(*it).first;
if (std::find(equipmentSlots.begin(), equipmentSlots.end(), (int)MWWorld::InventoryStore::Slot_CarriedRight)
== equipmentSlots.end())
continue;
float rating = rateWeapon(*it, actor, target, -1, bestArrowRating, bestBoltRating);
if (rating > bestActionRating)
{
const ESM::Weapon* weapon = it->get<ESM::Weapon>()->mBase;
MWWorld::Ptr ammo;
if (weapon->mData.mType == ESM::Weapon::MarksmanBow)
ammo = bestArrow;
else if (weapon->mData.mType == ESM::Weapon::MarksmanCrossbow)
ammo = bestBolt;
bestActionRating = rating;
bestAction.reset(new ActionWeapon(*it));
bestAction.reset(new ActionWeapon(*it, ammo));
}
}
}

@ -58,10 +58,14 @@ namespace MWMechanics
class ActionWeapon : public Action
{
private:
MWWorld::Ptr mAmmunition;
MWWorld::Ptr mWeapon;
public:
/// \a weapon may be empty for hand-to-hand combat
ActionWeapon(const MWWorld::Ptr& weapon) : mWeapon(weapon) {}
MWWorld::Ptr mWeapon;
ActionWeapon(const MWWorld::Ptr& weapon, const MWWorld::Ptr& ammo = MWWorld::Ptr())
: mWeapon(weapon), mAmmunition(ammo) {}
/// Equips the given weapon.
virtual void prepare(const MWWorld::Ptr& actor);
virtual void getCombatRange (float& rangeAttack, float& rangeFollow);
@ -70,7 +74,9 @@ namespace MWMechanics
float rateSpell (const ESM::Spell* spell, const MWWorld::Ptr& actor, const MWWorld::Ptr& target);
float rateMagicItem (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor, const MWWorld::Ptr &target);
float ratePotion (const MWWorld::Ptr& item, const MWWorld::Ptr &actor);
float rateWeapon (const MWWorld::Ptr& item, const MWWorld::Ptr& actor);
/// @param type Skip all weapons that are not of this type (i.e. return rating 0)
float rateWeapon (const MWWorld::Ptr& item, const MWWorld::Ptr& actor, const MWWorld::Ptr& target,
int type=-1, float arrowRating=0.f, float boltRating=0.f);
/// @note target may be empty
float rateEffect (const ESM::ENAMstruct& effect, const MWWorld::Ptr& actor, const MWWorld::Ptr& target);

Loading…
Cancel
Save