s16 Battle::AIAttackPosition(Arena & arena, const Unit & b, const Indexes & positions) { s16 res = -1; if(b.isMultiCellAttack()) { res = AIMaxQualityPosition(positions); } else if(b.isDoubleCellAttack()) { Indexes results; results.reserve(12); const Units enemies(arena.GetForce(b.GetColor(), true), true); if(1 < enemies.size()) { for(Units::const_iterator it1 = enemies.begin(); it1 != enemies.end(); ++it1) { const Indexes around = Board::GetAroundIndexes(**it1); for(Indexes::const_iterator it2 = around.begin(); it2 != around.end(); ++it2) { const Unit* unit = Board::GetCell(*it2)->GetUnit(); if(unit && enemies.end() != std::find(enemies.begin(), enemies.end(), unit)) results.push_back(*it2); } } if(results.size()) { // find passable results Indexes passable = Arena::GetBoard()->GetPassableQualityPositions(b); Indexes::iterator it2 = results.begin(); for(Indexes::const_iterator it = results.begin(); it != results.end(); ++it) if(passable.end() != std::find(passable.begin(), passable.end(), *it)) *it2++ = *it; if(it2 != results.end()) results.resize(std::distance(results.begin(), it2)); // get max quality if(results.size()) res = AIMaxQualityPosition(results); } } } return 0 > res ? AIShortDistance(b.GetHeadIndex(), positions) : res; }
s16 Battle::AIAreaSpellDst(const HeroBase & hero) { std::map<s16, u8> dstcount; Arena* arena = GetArena(); Units enemies(arena->GetForce(hero.GetColor(), true), true); for(Units::const_iterator it1 = enemies.begin(); it1 != enemies.end(); ++it1) { const Indexes around = Board::GetAroundIndexes(**it1); for(Indexes::const_iterator it2 = around.begin(); it2 != around.end(); ++it2) dstcount[*it2] += 1; } // find max std::map<s16, u8>::const_iterator max = std::max_element(dstcount.begin(), dstcount.end(), MaxDstCount); return max != dstcount.end() ? (*max).first : -1; }
bool AI::BattleMagicTurn(Arena & arena, const Unit & b, Actions & a, const Unit* enemy) { const HeroBase* hero = b.GetCommander(); if(b.Modes(SP_BERSERKER) || !hero || hero->Modes(Heroes::SPELLCASTED) || !hero->HaveSpellBook() || arena.isDisableCastSpell(Spell(), NULL) || a.HaveCommand(Battle::MSG_BATTLE_CAST)) return false; const Force & my_army = arena.GetForce(b.GetArmyColor(), false); const Force & enemy_army = arena.GetForce(b.GetArmyColor(), true); Units friends(my_army, true); Units enemies(enemy_army, true); // sort strongest friends.SortStrongest(); // troop bad spell - clean { // sort strongest Units::iterator it = std::find_if(friends.begin(), friends.end(), std::bind2nd(std::mem_fun(&Unit::Modes), IS_BAD_MAGIC)); if(it != friends.end()) { if(AIApplySpell(Spell::DISPEL, *it, *hero, a)) return true; if(AIApplySpell(Spell::CURE, *it, *hero, a)) return true; } } // area damage spell { const u8 areasp[] = { Spell::METEORSHOWER, Spell::FIREBLAST, Spell::CHAINLIGHTNING, Spell::FIREBALL, Spell::COLDRING }; s16 dst = AIAreaSpellDst(*hero); if(Board::isValidIndex(dst)) for(u8 ii = 0; ii < ARRAY_COUNT(areasp); ++ii) { if(hero->CanCastSpell(areasp[ii])) { a.push_back(Battle::Command(MSG_BATTLE_CAST, areasp[ii], dst)); return true; } } } // if handfighting if(enemy) { // kill dragons if(enemy->isDragons() && !b.Modes(SP_DRAGONSLAYER) && AIApplySpell(Spell::DRAGONSLAYER, &b, *hero, a)) return true; // curse if(!enemy->Modes(SP_CURSE) && AIApplySpell(Spell::CURSE, enemy, *hero, a)) return true; // enemy good spell - clean if(enemy->Modes(IS_GOOD_MAGIC) && AIApplySpell(Spell::DISPEL, enemy, *hero, a)) return true; // up defense if(!b.Modes(SP_STEELSKIN) && !b.Modes(SP_STONESKIN) && AIApplySpell(Spell::STEELSKIN, &b, *hero, a)) return true; if(!b.Modes(SP_STONESKIN) && !b.Modes(SP_STEELSKIN) && AIApplySpell(Spell::STONESKIN, &b, *hero, a)) return true; } // my army blessing if(b.isArchers()) { if(!b.Modes(SP_BLESS) && AIApplySpell(Spell::BLESS, &b, *hero, a)) return true; if(!b.Modes(SP_BLOODLUST) && AIApplySpell(Spell::BLOODLUST, &b, *hero, a)) return true; } // up speed if(hero->HaveSpell(Spell::HASTE) && !enemy) { // sort strongest Units::iterator it = std::find_if(friends.begin(), friends.end(), std::not1(std::bind2nd(std::mem_fun(&Unit::Modes), SP_HASTE))); if(it != friends.end() && AIApplySpell(Spell::HASTE, *it, *hero, a)) return true; } // shield spell conditions { Units::iterator it = std::find_if(enemies.begin(), enemies.end(), std::mem_fun(&Unit::isArchers)); const Castle* castle = Arena::GetCastle(); // find enemy archers if(it != enemies.end() || // or archers tower (castle && castle->GetColor() != b.GetColor() && castle->isCastle())) { // find strongest archers for(it = friends.begin(); it != friends.end(); ++it) if((*it)->isArchers() && ! (*it)->Modes(SP_SHIELD)) break; // or other strongest friends if(it == friends.end()) it = std::find_if(friends.begin(), friends.end(), std::not1(std::bind2nd(std::mem_fun(&Unit::Modes), SP_SHIELD))); if(it != friends.end() && AIApplySpell(Spell::SHIELD, *it, *hero, a)) return true; } } // enemy army spell { // find mirror image or summon elem Units::iterator it = std::find_if(enemies.begin(), enemies.end(), std::bind2nd(std::mem_fun(&Unit::Modes), CAP_MIRRORIMAGE | CAP_SUMMONELEM)); if(it != enemies.end()) { if(AIApplySpell(Spell::ARROW, *it, *hero, a)) return true; if(AIApplySpell(Spell::LIGHTNINGBOLT, *it, *hero, a)) return true; } // find good magic it = std::find_if(enemies.begin(), enemies.end(), std::bind2nd(std::mem_fun(&Unit::Modes), IS_GOOD_MAGIC)); if(it != enemies.end()) { // slow if((*it)->Modes(SP_HASTE) && AIApplySpell(Spell::SLOW, *it, *hero, a)) return true; // curse if((*it)->Modes(SP_CURSE) && AIApplySpell(Spell::CURSE, *it, *hero, a)) return true; // if(AIApplySpell(Spell::DISPEL, *it, *hero, a)) return true; } // check undead if(std::count_if(friends.begin(), friends.end(), std::mem_fun(&Unit::isUndead)) < std::count_if(enemies.begin(), enemies.end(), std::mem_fun(&Unit::isUndead))) { if(AIApplySpell(Spell::HOLYSHOUT, NULL, *hero, a)) return true; if(AIApplySpell(Spell::HOLYWORD, NULL, *hero, a)) return true; } // check alife if(std::count_if(friends.begin(), friends.end(), std::mem_fun(&Unit::isAlive)) < std::count_if(enemies.begin(), enemies.end(), std::mem_fun(&Unit::isAlive))) { if(AIApplySpell(Spell::DEATHRIPPLE, NULL, *hero, a)) return true; if(AIApplySpell(Spell::DEATHWAVE, NULL, *hero, a)) return true; } Unit* stats = *Rand::Get(enemies); if(AIApplySpell(Spell::LIGHTNINGBOLT, stats, *hero, a)) return true; if(AIApplySpell(Spell::ARROW, stats, *hero, a)) return true; } /* FIX: Damage Spell: */ if(AIApplySpell(Spell::ARMAGEDDON, NULL, *hero, a)) return true; if(AIApplySpell(Spell::ELEMENTALSTORM, NULL, *hero, a)) return true; return false; }