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; }
void AI::BattleTurn(Arena & arena, const Unit & b, Actions & a) { Board* board = Arena::GetBoard(); // reset quality param for board board->Reset(); // set quality for enemy troop board->SetEnemyQuality(b); const Unit* enemy = NULL; bool attack = false; if(b.isArchers() && !b.isHandFighting()) { enemy = arena.GetEnemyMaxQuality(b.GetColor()); if(BattleMagicTurn(arena, b, a, enemy)) return; /* repeat turn: correct spell ability */ attack = true; } else if(b.isHandFighting()) { enemy = AIGetEnemyAbroadMaxQuality(b); if(BattleMagicTurn(arena, b, a, enemy)) return; /* repeat turn: correct spell ability */ attack = true; } else { s16 move = -1; if(b.Modes(SP_BERSERKER)) { const Indexes positions = board->GetNearestTroopIndexes(b.GetHeadIndex(), NULL); if(positions.size()) move = *Rand::Get(positions); } else { if(BattleMagicTurn(arena, b, a, NULL)) return; /* repeat turn: correct spell ability */ // set quality position from enemy board->SetPositionQuality(b); // get passable quality positions const Indexes positions = board->GetPassableQualityPositions(b); attack = true; if(positions.size()) move = AIAttackPosition(arena, b, positions); } if(Board::isValidIndex(move)) { if(b.isFly()) { enemy = AIGetEnemyAbroadMaxQuality(move, b.GetColor()); if(BattleMagicTurn(arena, b, a, enemy)) return; /* repeat turn: correct spell ability */ a.push_back(Battle::Command(MSG_BATTLE_MOVE, b.GetUID(), move)); attack = true; } else { Position dst = Position::GetCorrect(b, move); Indexes path = arena.GetPath(b, dst); if(path.empty()) { const u8 direction = b.GetPosition().GetHead()->GetPos().x > dst.GetHead()->GetPos().x ? RIGHT : LEFT; // find near position while(path.empty() && Board::isValidDirection(dst.GetHead()->GetIndex(), direction)) { const s16 & pos = Board::GetIndexDirection(dst.GetHead()->GetIndex(), direction); if(b.GetHeadIndex() == pos) break; dst.Set(pos, b.isWide(), direction == RIGHT); path = arena.GetPath(b, dst); } } if(path.size()) { if(b.isWide()) { const s16 & head = dst.GetHead()->GetIndex(); const s16 & tail = dst.GetTail()->GetIndex(); if(path.back() == head || path.back() == tail) { enemy = AIGetEnemyAbroadMaxQuality(head, b.GetColor()); if(!enemy) enemy = AIGetEnemyAbroadMaxQuality(tail, b.GetColor()); } } if(! enemy) enemy = AIGetEnemyAbroadMaxQuality(path.back(), b.GetColor()); a.push_back(Battle::Command(MSG_BATTLE_MOVE, b.GetUID(), path.back())); // archers move and short attack only attack = b.isArchers() ? false : true; } } } else enemy = AIGetEnemyAbroadMaxQuality(b); } if(enemy) { if(attack) a.push_back(Battle::Command(MSG_BATTLE_ATTACK, b.GetUID(), enemy->GetUID(), enemy->GetHeadIndex(), 0)); } else { DEBUG(DBG_BATTLE, DBG_TRACE, "enemy: " << "is NULL" << ", board: " << board->AllUnitsInfo()); } // end action a.push_back(Battle::Command(MSG_BATTLE_END_TURN, b.GetUID())); }