mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-31 20:26:43 +00:00 
			
		
		
		
	Consider weapon ammunition in combat AI (Fixes #1576)
This commit is contained in:
		
							parent
							
								
									f1d72419de
								
							
						
					
					
						commit
						0bdc1b243a
					
				
					 2 changed files with 77 additions and 9 deletions
				
			
		|  | @ -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); | ||||
|                 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) | ||||
|             { | ||||
|                 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…
	
		Reference in a new issue