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()));
}