diff --git a/CHANGELOG.md b/CHANGELOG.md index dbda7c2bc1..6ab7d88d3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -141,6 +141,7 @@ Task #4605: Optimize skinning Task #4606: Support Rapture3D's OpenAL driver Task #4613: Incomplete type errors when compiling with g++ on OSX 10.9 + Task #4621: Optimize combat AI 0.44.0 ------ diff --git a/apps/openmw/mwmechanics/aicombataction.cpp b/apps/openmw/mwmechanics/aicombataction.cpp index 52da1417ed..6fffff6377 100644 --- a/apps/openmw/mwmechanics/aicombataction.cpp +++ b/apps/openmw/mwmechanics/aicombataction.cpp @@ -190,11 +190,6 @@ namespace MWMechanics for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) { - std::vector 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, enemy, -1, bestArrowRating, bestBoltRating); if (rating > bestActionRating) { @@ -215,14 +210,12 @@ namespace MWMechanics for (Spells::TIterator it = spells.begin(); it != spells.end(); ++it) { - const ESM::Spell* spell = it->first; - - float rating = rateSpell(spell, actor, enemy); + float rating = rateSpell(it->first, actor, enemy); if (rating > bestActionRating) { bestActionRating = rating; - bestAction.reset(new ActionSpell(spell->mId)); - antiFleeRating = vanillaRateSpell(spell, actor, enemy); + bestAction.reset(new ActionSpell(it->first->mId)); + antiFleeRating = vanillaRateSpell(it->first, actor, enemy); } } @@ -265,11 +258,6 @@ namespace MWMechanics for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) { - std::vector 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, enemy, -1, bestArrowRating, bestBoltRating); if (rating > bestActionRating) { @@ -280,9 +268,7 @@ namespace MWMechanics for (Spells::TIterator it = spells.begin(); it != spells.end(); ++it) { - const ESM::Spell* spell = it->first; - - float rating = rateSpell(spell, actor, enemy); + float rating = rateSpell(it->first, actor, enemy); if (rating > bestActionRating) { bestActionRating = rating; diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index b64b3568f8..cf572abc0f 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -228,7 +228,7 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac { if ((*it)->getTypeId() != AiPackage::TypeIdCombat) break; - MWWorld::Ptr target = static_cast(*it)->getTarget(); + MWWorld::Ptr target = (*it)->getTarget(); // target disappeared (e.g. summoned creatures) if (target.isEmpty()) @@ -242,11 +242,11 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac const ESM::Position &targetPos = target.getRefData().getPosition(); - float distTo = (targetPos.asVec3() - vActorPos).length(); + float distTo = (targetPos.asVec3() - vActorPos).length2(); // Small threshold for changing target if (it == mPackages.begin()) - distTo = std::max(0.f, distTo - 50.f); + distTo = std::max(0.f, distTo - 2500.f); // if a target has higher priority than current target or has same priority but closer if (rating > bestRating || ((distTo < nearestDist) && rating == bestRating)) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 9e163f132c..b857c6d7e2 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -34,13 +34,17 @@ namespace MWMechanics { ESM::Skill::SkillEnum spellSchoolToSkill(int school) { - std::map schoolSkillMap; // maps spell school to skill id - schoolSkillMap[0] = ESM::Skill::Alteration; - schoolSkillMap[1] = ESM::Skill::Conjuration; - schoolSkillMap[3] = ESM::Skill::Illusion; - schoolSkillMap[2] = ESM::Skill::Destruction; - schoolSkillMap[4] = ESM::Skill::Mysticism; - schoolSkillMap[5] = ESM::Skill::Restoration; + static std::map schoolSkillMap; // maps spell school to skill id + if (schoolSkillMap.empty()) + { + schoolSkillMap[0] = ESM::Skill::Alteration; + schoolSkillMap[1] = ESM::Skill::Conjuration; + schoolSkillMap[3] = ESM::Skill::Illusion; + schoolSkillMap[2] = ESM::Skill::Destruction; + schoolSkillMap[4] = ESM::Skill::Mysticism; + schoolSkillMap[5] = ESM::Skill::Restoration; + } + assert(schoolSkillMap.find(school) != schoolSkillMap.end()); return schoolSkillMap[school]; } @@ -48,7 +52,11 @@ namespace MWMechanics float calcEffectCost(const ESM::ENAMstruct& effect) { const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effect.mEffectID); + return calcEffectCost(effect, magicEffect); + } + float calcEffectCost(const ESM::ENAMstruct& effect, const ESM::MagicEffect* magicEffect) + { int minMagn = 1; int maxMagn = 1; if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude)) diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 72f6a1f4a0..2844e7f23f 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -3,6 +3,7 @@ #include #include +#include #include "../mwworld/ptr.hpp" @@ -25,6 +26,7 @@ namespace MWMechanics ESM::Skill::SkillEnum spellSchoolToSkill(int school); float calcEffectCost(const ESM::ENAMstruct& effect); + float calcEffectCost(const ESM::ENAMstruct& effect, const ESM::MagicEffect* magicEffect); bool isSummoningEffect(int effectId); diff --git a/apps/openmw/mwmechanics/spellpriority.cpp b/apps/openmw/mwmechanics/spellpriority.cpp index 9a366a916f..a4bf467698 100644 --- a/apps/openmw/mwmechanics/spellpriority.cpp +++ b/apps/openmw/mwmechanics/spellpriority.cpp @@ -515,8 +515,6 @@ namespace MWMechanics return 0.f; } - const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effect.mEffectID); - // Underwater casting not possible if (effect.mRange == ESM::RT_Target) { @@ -530,6 +528,7 @@ namespace MWMechanics return 0.f; } + const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effect.mEffectID); if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful) { rating *= -1.f; @@ -565,7 +564,7 @@ namespace MWMechanics } } - rating *= calcEffectCost(effect); + rating *= calcEffectCost(effect, magicEffect); // Currently treating all "on target" or "on touch" effects to target the enemy actor. // Combat AI is egoistic, so doesn't consider applying positive effects to friendly actors. diff --git a/apps/openmw/mwmechanics/weaponpriority.cpp b/apps/openmw/mwmechanics/weaponpriority.cpp index 7e33784c17..ac01a07146 100644 --- a/apps/openmw/mwmechanics/weaponpriority.cpp +++ b/apps/openmw/mwmechanics/weaponpriority.cpp @@ -29,6 +29,9 @@ namespace MWMechanics if (type != -1 && weapon->mData.mType != type) return 0.f; + if (type == -1 && (weapon->mData.mType == ESM::Weapon::Arrow || weapon->mData.mType == ESM::Weapon::Bolt)) + return 0.f; + float rating=0.f; float rangedMult=1.f; diff --git a/components/esm/loadmgef.cpp b/components/esm/loadmgef.cpp index 9f8ad94e1e..75a94f828a 100644 --- a/components/esm/loadmgef.cpp +++ b/components/esm/loadmgef.cpp @@ -274,43 +274,46 @@ short MagicEffect::getResistanceEffect(short effect) // Source https://wiki.openmw.org/index.php?title=Research:Magic#Effect_attribute // - std::map effects; - effects[DisintegrateArmor] = Sanctuary; - effects[DisintegrateWeapon] = Sanctuary; - - for (int i=0; i<5; ++i) - effects[DrainAttribute+i] = ResistMagicka; - for (int i=0; i<5; ++i) - effects[DamageAttribute+i] = ResistMagicka; - for (int i=0; i<5; ++i) - effects[AbsorbAttribute+i] = ResistMagicka; - for (int i=0; i<10; ++i) - effects[WeaknessToFire+i] = ResistMagicka; - - effects[Burden] = ResistMagicka; - effects[Charm] = ResistMagicka; - effects[Silence] = ResistMagicka; - effects[Blind] = ResistMagicka; - effects[Sound] = ResistMagicka; - - for (int i=0; i<2; ++i) + static std::map effects; + if (effects.empty()) { - effects[CalmHumanoid+i] = ResistMagicka; - effects[FrenzyHumanoid+i] = ResistMagicka; - effects[DemoralizeHumanoid+i] = ResistMagicka; - effects[RallyHumanoid+i] = ResistMagicka; + effects[DisintegrateArmor] = Sanctuary; + effects[DisintegrateWeapon] = Sanctuary; + + for (int i=0; i<5; ++i) + effects[DrainAttribute+i] = ResistMagicka; + for (int i=0; i<5; ++i) + effects[DamageAttribute+i] = ResistMagicka; + for (int i=0; i<5; ++i) + effects[AbsorbAttribute+i] = ResistMagicka; + for (int i=0; i<10; ++i) + effects[WeaknessToFire+i] = ResistMagicka; + + effects[Burden] = ResistMagicka; + effects[Charm] = ResistMagicka; + effects[Silence] = ResistMagicka; + effects[Blind] = ResistMagicka; + effects[Sound] = ResistMagicka; + + for (int i=0; i<2; ++i) + { + effects[CalmHumanoid+i] = ResistMagicka; + effects[FrenzyHumanoid+i] = ResistMagicka; + effects[DemoralizeHumanoid+i] = ResistMagicka; + effects[RallyHumanoid+i] = ResistMagicka; + } + + effects[TurnUndead] = ResistMagicka; + + effects[FireDamage] = ResistFire; + effects[FrostDamage] = ResistFrost; + effects[ShockDamage] = ResistShock; + effects[Vampirism] = ResistCommonDisease; + effects[Corprus] = ResistCorprusDisease; + effects[Poison] = ResistPoison; + effects[Paralyze] = ResistParalysis; } - effects[TurnUndead] = ResistMagicka; - - effects[FireDamage] = ResistFire; - effects[FrostDamage] = ResistFrost; - effects[ShockDamage] = ResistShock; - effects[Vampirism] = ResistCommonDisease; - effects[Corprus] = ResistCorprusDisease; - effects[Poison] = ResistPoison; - effects[Paralyze] = ResistParalysis; - if (effects.find(effect) != effects.end()) return effects[effect]; else @@ -319,42 +322,44 @@ short MagicEffect::getResistanceEffect(short effect) short MagicEffect::getWeaknessEffect(short effect) { - std::map effects; - - for (int i=0; i<5; ++i) - effects[DrainAttribute+i] = WeaknessToMagicka; - for (int i=0; i<5; ++i) - effects[DamageAttribute+i] = WeaknessToMagicka; - for (int i=0; i<5; ++i) - effects[AbsorbAttribute+i] = WeaknessToMagicka; - for (int i=0; i<10; ++i) - effects[WeaknessToFire+i] = WeaknessToMagicka; - - effects[Burden] = WeaknessToMagicka; - effects[Charm] = WeaknessToMagicka; - effects[Silence] = WeaknessToMagicka; - effects[Blind] = WeaknessToMagicka; - effects[Sound] = WeaknessToMagicka; - - for (int i=0; i<2; ++i) + static std::map effects; + if (effects.empty()) { - effects[CalmHumanoid+i] = WeaknessToMagicka; - effects[FrenzyHumanoid+i] = WeaknessToMagicka; - effects[DemoralizeHumanoid+i] = WeaknessToMagicka; - effects[RallyHumanoid+i] = WeaknessToMagicka; + for (int i=0; i<5; ++i) + effects[DrainAttribute+i] = WeaknessToMagicka; + for (int i=0; i<5; ++i) + effects[DamageAttribute+i] = WeaknessToMagicka; + for (int i=0; i<5; ++i) + effects[AbsorbAttribute+i] = WeaknessToMagicka; + for (int i=0; i<10; ++i) + effects[WeaknessToFire+i] = WeaknessToMagicka; + + effects[Burden] = WeaknessToMagicka; + effects[Charm] = WeaknessToMagicka; + effects[Silence] = WeaknessToMagicka; + effects[Blind] = WeaknessToMagicka; + effects[Sound] = WeaknessToMagicka; + + for (int i=0; i<2; ++i) + { + effects[CalmHumanoid+i] = WeaknessToMagicka; + effects[FrenzyHumanoid+i] = WeaknessToMagicka; + effects[DemoralizeHumanoid+i] = WeaknessToMagicka; + effects[RallyHumanoid+i] = WeaknessToMagicka; + } + + effects[TurnUndead] = WeaknessToMagicka; + + effects[FireDamage] = WeaknessToFire; + effects[FrostDamage] = WeaknessToFrost; + effects[ShockDamage] = WeaknessToShock; + effects[Vampirism] = WeaknessToCommonDisease; + effects[Corprus] = WeaknessToCorprusDisease; + effects[Poison] = WeaknessToPoison; + + effects[Paralyze] = -1; } - effects[TurnUndead] = WeaknessToMagicka; - - effects[FireDamage] = WeaknessToFire; - effects[FrostDamage] = WeaknessToFrost; - effects[ShockDamage] = WeaknessToShock; - effects[Vampirism] = WeaknessToCommonDisease; - effects[Corprus] = WeaknessToCorprusDisease; - effects[Poison] = WeaknessToPoison; - - effects[Paralyze] = -1; - if (effects.find(effect) != effects.end()) return effects[effect]; else