/**
 * \file PlayerTactics.cpp
 *
 * Implementation of the PlayerTactics class
 */

#include "Player/PlayerTactics.h"
#include "Player/Formation.h"
#include "Common/Support/Debug.h"
#include "Common/Support/Log.h"
#include "Common/World/Circle.h"
#include "Common/Tasks.h"
#include "Common/World/Line.h"
#include "Common/World/Abscisse.h"
#include <string.h>
#include <list>
#include <algorithm>
using namespace std;

#include <stdio.h>
#include <math.h>

//#define max(x,y) ( ((x) > (y)) ? (x) : (y) )
//#define min(x,y) ( ((x) > (y)) ? (y) : (x) )

inline float max(float x, float y)
{
	return ((x) > (y)) ? (y) : (x);
}

inline float min(float x, float y)
{
	return ((x) < (y)) ? (y) : (x);
}

inline float sign(float x)
{
    return x >= 0.0f ? 1.0f : -1.0f;
}

PlayerTactics::PlayerTactics()
	: PlayerSkills("PlayerTactics", "PlayerKernel(PlayerTactics) module")
{
	scanBeforeKickOffAngle = 0;
	m_nNeckPos = 0;

// GP
//    m_cFormation.InitRawUnits( SIDE_LEFT, PlayerConfig.GetFormation(), PlayerConfig.GetDefUnit(), 
//		PlayerConfig.GetMidUnit(), PlayerConfig.GetForUnit() );

	m_cFormation.InitRawUnits( SIDE_LEFT, FORMATION_523, UNIT_5_L, UNIT_2_L, UNIT_3_L  );
	m_nStepsFromMyFreeKick = 0;
	Main::GetInstance()->RegisterModule(this, TACTICS_TASK);
}

// GP
void PlayerTactics::OnInit(RealSide realSide, unsigned uniform, PlayMode iMode)	
{
	PlayerSkills::OnInit(realSide, uniform, iMode);

	// inicializacia formacii
	//m_cFormation.InitRawUnits( SIDE_LEFT, PlayerConfig.GetFormation(), PlayerConfig.GetDefUnit(), 
//	PlayerConfig.GetMidUnit(), PlayerConfig.GetForUnit() );
	m_cFormation.InitRawUnits( SIDE_LEFT, FORMATION_523, UNIT_5_L, UNIT_2_L, UNIT_3_L );
	m_nStepsFromIHaveBall = world->params->server->half_time+1;
}

Interface* PlayerTactics::GetInterface(int task) const
{
	if(task == TACTICS_TASK) return (TacticsInterface*) this;
	else return PlayerSkills::GetInterface(task);
}

bool PlayerTactics::ShouldKickOnGoal()
{
	if(DistanceToGoal(world->me->pos) > 25) return false;

	Player *enemyGoalie = NULL;
	static int i;
	
	// najdeme si brankara
	for(i = 0; i < world->enemies.GetSize(); i++)
	{
		if(world->enemies[i].IsGoalie() && world->enemies[i].GetAge() < 5) 
		{
			enemyGoalie = &(world->enemies[i]);
			break;
		}
	}
	if(enemyGoalie == NULL)
	{
//		if(world->me->IsLookingAt(world->params->flags[GRT]) && 
//			world->me->IsLookingAt(world->params->flags[GRB])) return true;
		return false;
	}
	else if((enemyGoalie->pos - world->ball->pos).GetLength() < 4.f)
	{
		return true;
	}


	float posX = world->params->flags[GOAL_R].GetX();
	Point tGoal(posX, -(world->params->server->goal_width / 2) * .9f);
	Point bGoal(posX, (world->params->server->goal_width / 2) * .9f);
	Vector tVect = tGoal - world->ball->pos;
	Vector bVect = bGoal - world->ball->pos;

	int maxCycleB, maxCycleT, cycle, cycleB, cycleT;
	float edp, ekp;
	Vector v, a;
	float catchableArea;

	const int MAX_CYCLE = 30;

	Point res, T1, T2;
	float deg;
	int cycleb;
	Point futBposT[MAX_CYCLE];
	Point futBposB[MAX_CYCLE];
	Point futureHePos[MAX_CYCLE];
	float runDist[MAX_CYCLE];
	int maxCycle;
	bool found;

	Player p(*enemyGoalie);
	Ball tmpBall(*world->ball);

	catchableArea = max(world->params->server->catchable_area_l, world->params->server->catchable_area_w);
//	catchableArea *= 0.95f;

	// manual page 44
	edp = enemyGoalie->type->effort_max * enemyGoalie->type->dash_power_rate * 100;
	if(edp > world->params->server->player_accel_max) edp = world->params->server->player_accel_max;

	// manual page 48
	ekp = world->params->server->maxpower * world->params->server->kick_power_rate;
	float dir_diff = ((world->ball->pos - world->me->pos) - world->me->GetAbsDir()).GetAngle().GetAbsDeg();
	float dist_ball = (world->ball->pos - world->me->pos).GetLength() - world->params->server->ball_size - world->params->server->player_size;
	ekp *= 1.f - 0.25f * dir_diff / 180.f - 0.25f * dist_ball / world->me->type->kickable_margin;

	// lopta smerujuca k hornej a dolnej tycke
	Ball ballT(*world->ball);
	Ball ballB(*world->ball);
	ballT.vel.SetLength(ekp);
	ballT.vel.SetAngle(tVect.GetAngle());
	ballB.vel.SetLength(ballT.vel.GetLength());
	ballB.vel.SetAngle(bVect.GetAngle());

	deg = fabsf(p.GetAbsDir().GetDeg() - world->ball->vel.GetAngle().GetDeg());
	if(deg > 180) deg = 360 - deg;
	if(deg > 90) deg = 180; // he'll go backwards
	else deg = 0;

	futureHePos[0] = p.pos;
	runDist[0] = 0;
	v.SetLength(0);
	maxCycleB = maxCycleT = -1;
	for(cycleb = 1; cycleb < MAX_CYCLE; cycleb++)
	{
		// without turning
		a = PolarVector(edp, p.GetAbsDir() + DegAngle(deg));
		p.vel += a;
		if(p.vel.GetLength() > p.type->player_speed_max) p.vel.SetLength(p.type->player_speed_max);
		futureHePos[cycleb] = futureHePos[cycleb - 1] + p.vel;
		p.vel *= p.type->player_decay;

		// with turning
		if(cycleb > 1) 
		{
			v.SetLength(v.GetLength() + edp);
			if(v.GetLength() > p.type->player_speed_max) v.SetLength(p.type->player_speed_max);
		}
		runDist[cycleb] = runDist[cycleb - 1] + v.GetLength();
		if(cycleb > 1) v.SetLength(v.GetLength() * p.type->player_decay);

		// ball
		ballT.Step();
		ballB.Step();
		if(fabsf(ballT.pos.GetX()) > 52.5 && maxCycleT == -1) maxCycleT = cycleb;
		if(fabsf(ballB.pos.GetX()) > 52.5 && maxCycleB == -1) maxCycleB = cycleb;
		if(maxCycleB != -1 && maxCycleT != -1) break;
		futBposT[cycleb] = ballT.pos;
		futBposB[cycleb] = ballB.pos;
	}
	maxCycle = cycleb;
	if(maxCycleT == -1) maxCycleT = MAX_CYCLE;
	if(maxCycleB == -1) maxCycleB = MAX_CYCLE;

	found = true;

	p = *enemyGoalie;
	// he'll move by inertia while turning
	p.pos = p.pos + p.vel;

	for(cycleB = 0; cycleB < maxCycleB; cycleB++)
	{
		// first try without turning
		for(cycle = cycleB; cycle >= 0; cycle--)
		{
			if((futBposB[cycleB + 1] - futureHePos[cycle]).GetLength() <= catchableArea)
			{
				if(fabsf(futureHePos[cycle].GetX()) <= 52.5)
				{
					found = false;
					break;
				}
			}
		}
		if(!found) break;

		// now try with turning
		for(cycle = cycleB; cycle >= 0; cycle--)
		{
			if((futBposB[cycleB + 1] - p.pos).GetLength() <= runDist[cycle] + catchableArea)
			{
				found = false;
				break;
			}
		}
	}

	if(found) 
	{ 
		TXTN("%d: Quite surely should be goal1", world->state->GetSimTime());
		TXTN(" (%.2f, %.2f, %.1f), (%.2f, %.2f) - %.2f", 
			enemyGoalie->pos.GetX(),
			enemyGoalie->pos.GetY(),
			enemyGoalie->GetAbsDir().GetDeg(),
			world->ball->pos.GetX(),
			world->ball->pos.GetY(),
			ekp);
		return found;
	}

	p = *enemyGoalie;
	// he'll move by inertia while turning
	p.pos = p.pos + p.vel;

	for(cycleT = 0; cycleT < maxCycleT; cycleT++)
	{
		// first try without turning
		for(cycle = cycleT; cycle >= 0; cycle--)
		{
			if((futBposT[cycleT + 1] - futureHePos[cycle]).GetLength() <= catchableArea)
			{
				if(fabsf(futureHePos[cycle].GetX()) <= 52.5)
				{
					found = false;
					break;
				}
			}
		}
		if(!found) break;

		// now try with turning
		for(cycle = cycleT; cycle >= 0; cycle--)
		{
			if((futBposT[cycleT + 1] - p.pos).GetLength() <= runDist[cycle] + catchableArea)
			{
				found = false;
				break;
			}
		}
	}

	if(found)
	{
		TXTN("%d: Quite surely should be goal2", world->state->GetSimTime());
		TXTN(" (%.2f, %.2f, %.1f), (%.2f, %.2f) - %.2f", 
			enemyGoalie->pos.GetX(),
			enemyGoalie->pos.GetY(),
			enemyGoalie->GetAbsDir().GetDeg(),
			world->ball->pos.GetX(),
			world->ball->pos.GetY(),
			ekp);
	}
	return found;
}

void PlayerTactics::BehaveWithBall()
{
	AttentionTo(-1);	// teraz som sef, ostatny pocuvaju mna ja nikoho

	world->LogWorld();
	world->me->preparedCommands.ResetTarget();
	say->SMam(world->ball->pos, world->ball->vel);
	
	if (DoPlan())
		return;
	
	if (m_nStepsFromMyFreeKick>0){
		m_nStepsFromMyFreeKick--;
		return;
	}

	FormationRole role = m_cFormation.GetPlayerRole(0, world->me->GetUniform()-1);
	switch (role){
	case PR_Forward:
		AttackerWithBall();
		break;
	case PR_Defensman:
		DefenderWithBall();
		break;
	case PR_Midfielder:
	default:
		MidfiledWithBall();
		break;
	}
}

void PlayerTactics::BehaveWithoutBall()
{
	int idx;	
	Side who;

	world->WhoHasBall(who, idx);
	
	m_nStepsFromIHaveBall++;

	if (who==OUR){
		AttentionTo(idx);
		int idEnemyToOur = world->enemies.FindNearestToPosIndex(world->friends[idx].pos);
		Circle c(world->friends[idx].pos, 5.0);
		if (idEnemyToOur!=-1 && c.IsInside(world->enemies[idEnemyToOur].pos))
		{
			say->SZaTebou(world->enemies[idEnemyToOur].pos, world->enemies[idEnemyToOur].vel, world->enemies[idEnemyToOur].GetUniform());
		}
	}
	else{
		AttentionTo(-1);
	}
	
	FormationRole role = m_cFormation.GetPlayerRole(0, world->me->GetUniform()-1);

	switch (role){
	case PR_Forward:
	//	DBGN("PR_Forward without ball");
		AttackerWithoutBall(who, idx);
		LookWithoutBall2();
		break;
	case PR_Defensman:
	//	DBGN("PR_Defensman without ball");
		DefenderWithoutBall(who, idx);
		LookWithoutBall2();
		break;
	case PR_Midfielder:
	default:
	//	DBGN("PR_Midfielder without ball");
		MidfiledWithoutBall(who, idx);
		LookWithoutBall2();
		break;
	}

}

void PlayerTactics::BehaveWithoutBallDefault()
{
//	if(DependentForBall()) {
//		m_sKickInfo.Invalidate();
//		RunToBall3();
	//}
	

/*
	if (world->me->preparedCommands.ReachTarget(world->me->pos)){
		;
	}

	if(world->me->preparedCommands.activeTarget){
		RunToPos(world->me->preparedCommands.targetPos );
		return;
	}
*/
	/*BALLARRAY balls;
	world->ball->Predict(world->variables->GetnStepForPredictBall(), balls);
	for (int i=0; i<world->friends.GetSize(); i++)
	{
		world->friends[i].PredictStepsToBall(balls);
	}
	for (i=0; i<world->enemies.GetSize(); i++)
	{
		world->enemies[i].PredictStepsToBall(balls);
	}*/

/*	if(world->me->preparedCommands.activeTarget){
		RunToPos(world->me->preparedCommands.targetPos );
		return;
	}
*/
	int idNearestEnemie = world->enemies.FindNearestToPosIndex(world->me->pos);
	Vector vectToBall = world->me->pos - world->ball->pos; 
	Ball tmpBall(*world->ball);
	tmpBall.Step();
	Vector ballToMe = tmpBall.pos - world->ball->pos;

	bool ballGetToAttack = ballToMe.GetAngle().GetAbsDeg()<80.0f?true:false;

	if (idNearestEnemie!=-1 && (world->enemies[idNearestEnemie].pos-world->me->pos).GetLength() >=6 && vectToBall.GetLength()<15){
		say->SPrihraj(world->me->pos, world->me->GetUniform());
	}

	bool bFast = (vectToBall.GetLength()>10.0) ? false:true;
	if (bFast && !ballGetToAttack)
		bFast = false;

	bool catchIt = InterceptBall();

	if(!catchIt)
	{						//nie je zodpovedny za loptu
		const float off_l = GetOffsideLine();

		if(InOffsidePos(off_l)) {	//je v ofsajde
			ExitOffside();
		}
		else {					//nie je v ofsajde

			// otestuj ci nahodou nemas bezat za prihravkou
            // zatial StjupitDox nekricia na seba ...
            /*
			if ( m_sKickInfo.IsValid() && m_sKickInfo.teammate == -1 && PlayerConfig.FollowCommands() ) {
				// sprava urcena mne
				//Log("\n %d run for ball from kick info", GetSimTime());
				CfPoint dist = m_sKickInfo.pos - world->me->pos;

				if ( dist.GetDistance() < 2.0f ) {
					// uz si dobehol za loptu
					m_sKickInfo.Invalidate();
				}
				else {
					RunToPos( m_sKickInfo.pos );
					return;
				}
			}
            */

			m_cFormation.SetSide( SIDE_LEFT );
			Point pos = m_cFormation.GetPlayerPosition( world->me->GetUniform(), world->ball->pos );
			Vector dist = pos - world->me->pos;
			
			//if ( GetNearestEnemyDistance( world->me->pos ) < 5.0f && BlockEnemy() ) {
            // GP, blokovanie vyhodene
//			if ( BlockEnemy( pos ) ) {
				// blokuj supera od lopty
//			}
//			else {
				if ( dist.GetLength() > 5.0 ) {

					// test offside

					if ( pos.GetX() > off_l - 0.1f ) {
						pos.SetX( off_l - 0.1f);
					}

					RunToPoint( pos, bFast );		// pobehni za loptou
				}
				else {				//nepresuvam sa, sledujem loptu

					int t = world->me->GetSeeCount() % 3;
					/*
					// pozeraj sa na vsetky strany
					if ( t ) {
						TurnTo(world->ball->pos);
						AlignNeck();
					}
					else {
						Point tmp = world->ball->pos;
						tmp.SetY( -world->ball->pos.GetY());

						TurnNeckTo( tmp, world->me->pos );
					}
					*/
				}
//			}
		}
	}

/*
	//bool catchIt = DependentForBall();
	//if(catchIt) 
	bool catchIt = InterceptBall();

	if(!catchIt)
	{
		// Could not intercept ball
		const float off_l = GetOffsideLine();

		if(InOffsidePos(off_l))
		{	
			// Is offside
			ExitOffside();
		}
		else
		{
			// Not offside
			Patrol();
		}
*/
		/*
			CTNode tn = tnodes[world->me->GetUniform()];

			float f = world->ball->pos.GetX() / 52.5f;
			if(f > 1) f = 1;
			else if(f < -1) f = 1;

			float tX = tn.GetTacticalXCoord(f);

			bool OffsideWarning = false; //ci idem do ofsajdu
			if(tX >= off_l && world->me->pos.GetX() > off_l - 1.0f) OffsideWarning = true;

			if(fabsf(tX - world->me->pos.GetX()) > 5 && !OffsideWarning)
			{						//takticky presun
				if(world->me->pos.GetX() < tX)
				{
					if(f < 0) RunToPoint(Point(0, 0) + tn.GetMiddlePos(), false);
					else RunToPoint(Point(0, 0) + tn.GetOffencePos(), false);
				}
				else
				{
					if(f < 0) RunToPoint(Point(0, 0) + tn.GetDefencePos(), false);
					else RunToPoint(Point(0, 0) + tn.GetMiddlePos(), false);
				}
			}
			else
			{						//nepresuvam sa, sledujem loptu
				TurnTo(world->ball->pos);
				AlignNeck();
			}
		}*/
//	}
}

void PlayerTactics::BehaveWithBallGoalie()
{
	WARNN("I am not goalie, why BehaveWithBallGoalie???");
	BehaveWithBall();
}

void PlayerTactics::BehaveWithoutBallGoalie()
{
	WARNN("I am not goalie, why BehaveWithoutBallGoalie???");
	//bool catchIt = DependentForBall();
	//if(catchIt) 
	bool catchIt = InterceptBall();

	if(!catchIt)
	{
		TurnTo(world->ball->pos);
		AlignNeck();
	}
}

void PlayerTactics::OnChangeMode(int time, PlayMode mode)
{
	// Call overloaded method from CPlayerKernel
	PlayerKernel::OnChangeMode(time, mode);

	// If this is some kick-off mode, start new scanning for players
	// see BehaveWithBall
	scanBeforeKickOffAngle = 0;
}

/// \author Peter Trebaticky
bool PlayerTactics::ShouldKickIn()
{
	bool should = PlayerSkills::ShouldKickIn();
	if(!should) return false;

#ifdef GOALIE
	// For a goalie, PlayerSkills::ShouldKickIn() works just fine.

#else // GOALIE
	if(IsBallKickAble()) return true;

	// Find player whose home position is nearest to the ball.
	float distance = 100000;	// a big number
	int uniform;

	m_cFormation.SetSide(SIDE_LEFT);
	for(int i = 1; i < 12; i++) {
        if(m_cFormation.GetPlayerRole(SIDE_LEFT, i - 1) != (FormationRole)PR_Goalie)
        {
            Point pos = m_cFormation.GetPlayerPosition(i, world->ball->pos);

            float d = (pos - world->ball->pos).GetLength();
            if(d < distance) { distance = d; uniform = i; }
        }
    }

	KICKIN_DBGN("%i: Number %i will kick in the ball", world->state->GetSimTime(), uniform);

	Point pos = m_cFormation.GetPlayerPosition(world->me->GetUniform(), world->ball->pos);
	if(fabsf((pos - world->ball->pos).GetLength() - distance) < 3.f)
		KICKIN_DBGN("%i: I am going to kick in", world->state->GetSimTime());
	else
		should = false;

#endif // GOALIE

	return should;
}

Point PlayerTactics::GetHomePos()
{
    // GP
	float s = -27.0f;
	m_cFormation.SetSide(SIDE_LEFT);
	
	//CfPoint homepos = m_cFormation.GetPlayerPosition( world->me->Unum, CfPoint( s, 0) );
    Point homepos = m_cFormation.GetPlayerPosition( world->me->GetUniform(), Point( s, 0) );
	homepos.SetX((homepos.GetX() > -2.f) ? -2.f : homepos.GetX());

	return homepos;
}

/** Finds the nearest enemy that should be blocked.
 * \return index of the nearest blockable enemy.
 */
int PlayerTactics::FindEnemyToBlock(const Point& refPos, float treshold /* = FLT_MAX */) const
{
    int bestEnemyIndex = -1;
    float bestEnemyDist = FLT_MAX;
    Point bestEnemyPos;
    Point ballPos = world->ball->pos; 
    for (int enemyIndex = 0, enemyCnt = world->enemies.GetSize(); enemyIndex < enemyCnt; enemyIndex++) {
        Point enemyPos = world->enemies[enemyIndex].pos; 
        Vector enemyDist = enemyPos - refPos;
        if (bestEnemyIndex != -1 && 
                enemyDist.GetLength() >= bestEnemyDist && 
                enemyPos.GetX() < bestEnemyPos.GetX())
        {
            //vzdialenost do nepriatela je vacsia ako doposial najdena
            //a ten uz najdeny je blizsie ku brane
            continue;
        }
        if (enemyPos.GetX() >= bestEnemyPos.GetX()) {
            // nova vzdialenost je dalej od brany
            continue;
        }
        if (enemyDist.GetLength() >= treshold) {
            //vzdialenost do nepriatela je vacsia ako zadana hranicna hodnota
            continue;
        }
        for (int mateIndex = 0, mateCnt = world->friends.GetSize(); mateIndex < mateCnt; mateIndex++) {
            Point matePos = world->friends[mateIndex].pos;
            Vector theirDist = enemyPos - matePos;
            if (theirDist.GetLength() <= enemyDist.GetLength())
                //spoluhrac je blizsie ku nepriatelovi ako ja
                continue;
            bestEnemyIndex = enemyIndex;
            bestEnemyDist = enemyDist.GetLength();
            bestEnemyPos = enemyPos;
        }
    }
    return bestEnemyIndex;
}

/// Find best friend player for passing
/// \return vrati index spoluhraca z pola friend, ktoremu je najvhodnejsie prihrat
int PlayerTactics::GetPassAbleFriend() const
{
	float myDist = DistanceToGoal(world->me->pos);
	float distFriendGoal;
	Vector diffFriend;
	float distToFriend;
	float bestDist = FLT_MAX;

	Vector diffEnemy;
	float distToEnemy;

	int best = -1;

	// niekto caka na prihravku
	if (world->passableFriends.GetSize()>0)
	{
		int age =  world->variables->GetMaximumPassableFriendAge();
		int idx= -1;
		float meX = world->me->pos.GetX();
		float bestX = meX-5.0f;
			
		for (int i=0; i<world->passableFriends.GetSize(); i++)
		{
			int idxF = world->friends.FindByUniformIndex(world->passableFriends[i].Uniform);
			if (idxF==-1)
				continue;
            Line l(world->ball->pos, world->friends[idx].pos);
			int id;
			if (world->enemies.IsAnyNearLine(l, 2.0f, id)==true)
				continue;
			
		/*	Abscisse a(world->ball->pos, world->friends[idx].pos);
			if (world->enemies.IsAnyNearAbscisse(a, 2.0f)==true)
				continue;
		*/
			if (world->friends[idxF].pos.GetX()>bestX) 
			{
				idx = idxF;
				age = world->passableFriends[idxF].age;
				bestX = world->friends[idxF].pos.GetX();
			}
		}
		best = idx;
	}

	if (best==-1)
	{
		for(int who = 0;who < world->friends.GetSize(); who++) 
		{
			// sebe a brankarovi neprihram
			if (world->friends[who].IsMyself())
				continue;
			if (world->friends[who].IsGoalie())
				continue;
			if (world->friends[who].GetUniform() == 1) 
				continue;

			int teammate_uniform = world->friends[who].GetUniform();
			distFriendGoal = DistanceToGoal(world->friends[who].pos);
			
			
			//spohuhrac je blizsie ku brane
			if(distFriendGoal < myDist) 
			{
				diffFriend = world->friends[who].pos - world->me->pos;
				distToFriend = diffFriend.GetLength();
					//spoluhrac nie je dalej ako 30 a nie blizsie ako 3m (30 a 5 su default hodnoty \mroz)
				if(
					distToFriend <= 30.0f && //world->variables->GetPassSurroundingsMaxWidth() && 
					distToFriend > 3.0f ) //world->variables->GetPassSurroundingsMinWidth())
				{

					Line l(world->ball->pos, world->friends[who].pos);
					int id;
					if (world->enemies.IsAnyNearLine(l, 2.0f, id)==true)
						continue;
                  
					bool blockingEnemy = false;
					for(int e=0; e < world->enemies.GetSize() && !blockingEnemy; e++)
					{
						diffEnemy = world->enemies[e].pos - world->me->pos;
						distToEnemy = diffEnemy.GetLength();
						//potencialne by mohol blokovat
						if(distToEnemy < distToFriend + world->variables->GetPassSurroundingsMinWidth())
						{
							//do 17 stupnov blokuje
							if((diffFriend.GetAngle() - diffEnemy.GetAngle()).GetAbsDeg() < 17)
							{
								blockingEnemy = true;
//								TXTN("player %d blocked: enemy %d is near or before", 
//									teammate_uniform, world->enemies[e].GetUniform());
							}
						}
					}
					
					if(!blockingEnemy && 
						(bestDist == FLT_MAX || bestDist > distFriendGoal))
					{
						best = who;
						bestDist = distFriendGoal;
						myDist = distFriendGoal; //aby sa nasiel najblizsi
					}
				}
				else {
//					TXTN("player %d has unsuitable distance", teammate_uniform);
				}
			}
				
		}
	}

	return best;



/*	float myDist = DistanceToGoal(world->me->pos);
	float distFriendGoal;
	Vector diffFriend;
	float distToFriend;
	float bestDist = FLT_MAX;

	Vector diffEnemy;
	float distToEnemy;

	int best = -1;

	// niekto caka na prihravku
	if (world->passableFriends.GetSize()>0)
	{
		int age =  world->variables->GetMaximumPassableFriendAge();
		int idx=-1;
		for (int i=0; i<world->passableFriends.GetSize(); i++)
		{
			if (world->passableFriends[i].age<age)
			{
				idx = world->passableFriends[i].index;
				age = world->passableFriends[i].age;
			}
		}
		if (idx!=-1)
			return idx;
	}

	for(int who = 0;who < world->friends.GetSize(); who++) 
    {
        if (world->friends[who].IsGoalie())
            continue;
        if (world->friends[who].IsMyself())
            continue; 

        int teammate_uniform = world->friends[who].GetUniform();

        if (teammate_uniform == -1)
            continue;

        distFriendGoal = DistanceToGoal(world->friends[who].pos);

        //spohuhrac je blizsie ku brane
        if(distFriendGoal < myDist) 
        {
            diffFriend = world->friends[who].pos - world->me->pos;
            distToFriend = diffFriend.GetLength();
            //spoluhrac nie je dalej ako 30 a nie blizsie ako 3m (30 a 5 su default hodnoty \mroz)
            if(
                    distToFriend <= world->variables->GetPassSurroundingsMaxWidth() && 
                    distToFriend > world->variables->GetPassSurroundingsMinWidth())
            {
                bool blockingEnemy = false;
                for(int e=0; e < world->enemies.GetSize() && !blockingEnemy; e++)
                {
                    diffEnemy = world->enemies[e].pos - world->me->pos;
                    distToEnemy = diffEnemy.GetLength();
                    //potencialne by mohol blokovat
                    if(distToEnemy < distToFriend + world->variables->GetPassSurroundingsMinWidth())
                    {
                        //do 17 stupnov blokuje
                        if((diffFriend.GetAngle() - diffEnemy.GetAngle()).GetAbsDeg() < 17)
                        {
                            blockingEnemy = true;
                            TXTN("player %d blocked: enemy %d is near or before", 
                                    teammate_uniform, world->enemies[e].GetUniform());
                        }
                    }
                }

                if(!blockingEnemy && 
                        (bestDist == FLT_MAX || bestDist > distFriendGoal))
                {
                    best = who;
                    bestDist = distFriendGoal;
                    myDist = distFriendGoal; //aby sa nasiel najblizsi
                }
            }
            else {
                TXTN("player %d has unsuitable distance", teammate_uniform);
            }
        }
        else {
            TXTN("player %d is near the gates", teammate_uniform);
        }
    }

	TXTN("%d: found passable teammate %d", 
		world->state->GetSimTime(), 
		best==-1?-1:world->friends[best].GetUniform());
	return best;
	*/
}

bool PlayerTactics::InOffsidePos(float off_l) const
{
	if (world->me->pos.GetX() < off_l) return false;
	return true;
}

float PlayerTactics::GetOffsideLine() const
{
	float offside_line = 0;
	float fast = 0;
	float second = 0;

	float tmp;
	int i;

	for (i = 0; i < world->enemies.GetSize(); i++) {	//druhy obranca
		if (world->enemies[i].pos.GetX() > second) {
			second = world->enemies[i].pos.GetX();
			if (second > fast) {
				tmp = fast;
				fast = second;
				second = tmp;
			}
		}
	}

	if (second > world->ball->pos.GetX()) {
		offside_line = second;
	}
	else {
		offside_line = world->ball->pos.GetX();
	}

	return offside_line;
}

void PlayerTactics::ExitOffside(bool fast)
{
	RunToPoint(Point(-1, world->me->pos.GetY()), fast);
}

float PlayerTactics::DistanceToGoal(const Point& pos) const
{
	const float posX = 52.5f;

	if (pos.GetY() < -world->params->server->goal_width / 2) {
		const Point UpperGoal(posX, -world->params->server->goal_width / 2);
		return (UpperGoal - pos).GetLength();
	}

	if (pos.GetY() > world->params->server->goal_width / 2) {
		const Point LowerGoal(posX, world->params->server->goal_width / 2);
		return (LowerGoal - pos).GetLength();
	}

	return fabsf(posX - pos.GetX());
}

bool PlayerTactics::NoEnemiesAround() const
{
	for (int i = 0; i < world->enemies.GetSize(); i++) {
		if ((world->enemies[i].pos - world->me->pos).GetLength() <= 5.0f &&
			(world->enemies[i].pos - world->me->pos).GetAngle().GetAbsDeg() < 90
			) 
		{
/*			TXTN("%d: %.2f", world->state->GetSimTime(), 
				(world->enemies[i].pos - world->me->pos).GetAngle().GetAbsDeg());
 */
			return false;
		}
	}

	return true;
}

bool PlayerTactics::SmartDribleTo(const Point& pos)
{
	int who;
	const float karea = world->variables->GetDribleSurroundingsMinWidth();
	for (who = 0; who < world->enemies.GetSize(); who++)
	{
		//protihrac uz moze kopnut do lopty
		if ((world->ball->pos - world->enemies[who].pos).GetLength() <= karea * 1.1f) return false;
	}

	const float dir = (pos - world->me->pos).GetAngle().GetDeg();
	const float controll_dist = world->params->server->ball_size + world->me->type->player_size + 0.45f * world->me->type->kickable_margin;

	float bestdir = 0;
	float maxvaha = 0;
	float vaha;

	for (float reldir = -90; reldir <= 90; reldir += 5) {
		float uhol = (dir + reldir) * M_PI/180;

		Point driblepos = world->me->pos + RectVector(cosf(uhol)* controll_dist,sinf(uhol) * controll_dist);

		vaha = 1000; //velke cislo
		for(who = 0; who < world->enemies.GetSize(); who++)
		{
			if((world->enemies[who].pos - world->me->pos).GetLength() > world->variables->GetDribleSurroundingsMaxWidth()) continue;

			const float vzdial = (world->enemies[who].pos - driblepos).GetLength();
			if (vzdial <= karea) {
				vaha = 0;
				break;
			}
			if (!InTheMiddle(world->me->pos, driblepos, world->enemies[who].pos)) {
				if (vzdial <= (karea + world->params->server->player_speed_max)) {
					vaha = 0;
					break;
				}
				vaha = min(vaha, vzdial - (karea + world->params->server->player_speed_max));
			}
			else {
				vaha = min(vaha, vzdial - karea);
			}

		}

		if(vaha > maxvaha) {
			maxvaha = vaha;
			bestdir = reldir;
		}

	}

	if(maxvaha > 0) {
		DribbleTo2(pos,bestdir);
		//DBGN("%f",bestdir);
		return true;
	}
	return false;
}

bool PlayerTactics::ShortKick(const Point& pos)
{
	SKILLS_DBGN("%i: ->short kicking to position", world->state->GetSimTime());
	SKILLS_DBGN("%i: ->pos (%3.2f, %3.2f)", world->state->GetSimTime(), pos.GetX(), pos.GetY());

	const Vector diff = pos - world->ball->pos;
	const float dist = diff.GetLength();
	if(dist == 0) return false;

	if(!world->me->IsLookingAt(pos)) return false;

	for(float d = 15.0f;d >= 5.0f; d -= 1.0f)
	{
		const Point target = world->ball->pos + diff * (d/dist);
		const int my_steps = PredictSteps((target - world->me->pos).GetLength(),RecommDashPower(true),0);
		float enemy_steps = 6000; //velke cislo

		for(int i = 0; i < world->enemies.GetSize(); i++)
		{
			enemy_steps = min(enemy_steps, (target - world->enemies[i].pos).GetLength()/world->params->server->player_speed_max);
		}

		if(my_steps < enemy_steps)
		{
			PassBallTo(target,0);
			return true;
		}
	}

	return false;
}

/**
 * Move player to given place, or watch the ball
 * \author Daniel Novomesky
 */
void PlayerTactics::Patrol() 
{
    Point fpTacticalPosition, homePos = GetHomePos();
    Vector diff = world->ball->pos - homePos;
    homePos += (diff * 0.7f);

    bool dontBlockEnemy = false;
    if (world->me->pos.GetX() + 5.0f > world->ball->pos.GetX()) 
    {
        // lopta je blizsie ku brane ako ja!
        // sup sup pred nu
        float x =  world->ball->pos.GetX() - ((52.5f + world->ball->pos.GetX()) / 3.0f) - 2.0f;
        fpTacticalPosition = Point(x, homePos.GetY());
        dontBlockEnemy = true;
    }
    else if (world->me->pos.GetX() + 5.0f < world->ball->pos.GetX()) {
        // lopta je dalej od brany ako ja
        float x =  world->ball->pos.GetX() - ((52.5f + world->ball->pos.GetX()) / 3.0f);
        fpTacticalPosition = Point(x, homePos.GetY());
    }
    else {
        fpTacticalPosition = homePos;
    }

    int enemyIdx = world->enemies.FindNearestToPosIndex(fpTacticalPosition);
    if (!dontBlockEnemy && enemyIdx != -1) {
        //Vector diff = world->enemies[enemyIdx].pos - world->ball->pos;
        Vector diff = world->ball->pos - world->enemies[enemyIdx].pos;
        if (diff.GetLength() < 5.0f) {
            fpTacticalPosition = world->enemies[enemyIdx].pos + (diff * 0.8f);
            if (world->me->pos.GetX() + 2.0f > world->ball->pos.GetX()) {
                fpTacticalPosition.SetX(fpTacticalPosition.GetX() - 2.0f);
            }
        }
    }

    bool OffsideWarning = false; //ci idem do ofsajdu

    const float off_l = GetOffsideLine();
    if(fpTacticalPosition.GetX() >= off_l && world->me->pos.GetX() > off_l - 1.0f) 
        OffsideWarning = true;

    if(fabsf(fpTacticalPosition.GetX() - world->me->pos.GetX()) > 3.0f 
            || fabsf(fpTacticalPosition.GetY() - world->me->pos.GetY()) > 5.0f) 
        //takticky presun
    {
        // ak sa nedostanem do offside-u
        if(!OffsideWarning)
        {
            RunToPoint(fpTacticalPosition, true);
        }
        else if (OffsideWarning && fabsf(fpTacticalPosition.GetY() - world->me->pos.GetY()) > 5.0f)
        {
            Point position(world->me->pos.GetX(), fpTacticalPosition.GetY());
            RunToPoint(position, false);
        } 
        else 
        {
            TurnTo(world->ball->pos);
            AlignNeck();
        }
    }
    else //nepresuvam sa, sledujem loptu
    {
        TurnTo(world->ball->pos);
        AlignNeck();
    }
}

/**
 * Find out if position is offside
 * \param target examined position
 * \return true if offside, false if not
 * \author Martin Zuzcak
 */
bool PlayerTactics::IsOffsidePosition(Point target)
{
	const float off_l = GetOffsideLine();

	if(target.GetX() >= off_l && world->me->pos.GetX() > off_l - 1.0f) return true;
	return false;
}

/**
 * Find out a better position for receiving a pass and move there
 * \return true if player should move, false if no better place found
 * \author Martin Zuzcak
 */
bool PlayerTactics::GotoPositionToPass(bool fast)
{
	Vector positions[10];
	positions[0].SetX(5.0f);
	positions[0].SetY(0.0f);
	positions[1].SetX(3.5f);
	positions[1].SetY(3.5f);
	positions[2].SetX(3.5f);
	positions[2].SetY(-3.5f);
	positions[3].SetX(0.0f);
	positions[3].SetY(5.0f);
	positions[4].SetX(0.0f);
	positions[4].SetY(-5.0f);

	int i;
	for (i = 0; i < 5; i++)
	{
		positions[i + 5].SetX(positions[i].GetX() * 2);
		positions[i + 5].SetY(positions[i].GetY() * 2);
	}

	Point fpDefaultPosition = GetHomePos();
	float fMyEnemyDistance = GetNearestEnemyDistance(world->me->pos);
	// pre kazdu z positions zistim, ci tam hrac moze ist
	for (i = 0; i < 10; i++) {
		Point fpDestination = world->me->pos + positions[i];
		if (IsOffsidePosition(fpDestination) == true)
			continue;
		float fTargetDistance = (fpDestination - fpDefaultPosition).GetLength();
		float fMyDistance = (world->me->pos - fpDefaultPosition).GetLength();
		if (fTargetDistance < 20.0f || fTargetDistance < fMyDistance) {
			// teoreticky tam mozem ist, este zistit, ci sa to oplati...
			float fTargetEnemyDistance = GetNearestEnemyDistance(fpDestination);
			if (fTargetEnemyDistance > (fMyEnemyDistance + 2.0f) && GetNearestFriendDistance(fpDestination) > 5.0f) {
				RunToPoint(fpDestination, fast);
				return true;
			}
		}
	}
	
	return false;
}

#if 0
bool PlayerTactics::IsOurBall() 
{
	if(!world->ball->IsValid()) return false;

	int ourc;
	int theirc;
	/*int closestFriend = */(void) NearFriend(&ourc);	/// \todo Why do we call NearFriend?
	int enemy = NearEnemy(&theirc);

	if(enemy == -1) return true;
	if (ourc < theirc) return true;
    return false;
}
#endif // 0

/**
 * Find out speed needed to kick ball to given place
 * \param ciel place where ball should be kicked
 * \param steps how many steps should it take
 * \return kick power
 * \author Martin Zuzcak
 */
float PlayerTactics::GetKickPower(const Point& ciel, int steps)
{
  int nStepTolerance = 5;
	Vector path = ciel - world->ball->pos;
	float vzdial = path.GetLength();
	float req_spd = vzdial * (1.0f - world->params->server->ball_decay) / (1.0f - float(pow(world->params->server->ball_decay, steps - 1)));
  if (req_spd > world->params->server->ball_speed_max) {
	  req_spd = vzdial * (1.0f - world->params->server->ball_decay) / (1.0f - float(pow(world->params->server->ball_decay, steps + nStepTolerance)));
    return req_spd;
    }
  return req_spd;
}

/*
int PlayerTactics::NearEnemy(int* pCycles) const
{
	if(world->enemies.GetSize() == 0) return -1;

	float psteps;
	CBall tmpBall(ball);
	Point diff;
	const float karea = world->params->server->psize + world->params->server->bsize + world->params->server->kmargin;

	for(int ncycles = 1;;ncycles++)
	{
		tmpBall = stepBall(tmpBall);

		for(int i=0;i < world->enemies.GetSize();i++)
		{
			diff = tmpBall.pos - world->enemies[i].pos;

			psteps = (diff.GetLength() - karea) / world->params->server->pspeed_max;
			if(psteps < ncycles)
			{
				*pCycles = ncycles;
				return i;
			}
		}
	}
}
*/

/**
 * Pass to a running player, if possible
 * \return true if passed, false of not
 * \author Martin Zuzcak
 */
bool PlayerTactics::PassIntoRun()
{
	return false;

	if(world->me->pos.GetX() < world->variables->GetMinXPosition()) return false;
  
	float fOurPlayerAdvantage = 0.2f;
	int n;

	for(int who = 0; who < world->friends.GetSize(); who++)
	{
		if(world->friends[who].pos.GetX() <= (world->me->pos.GetX() - 10.0f)) continue;
		
		for(n = 40; n > 10;  n = n - 2) 
		{
			float pos = world->friends[who].pos.GetX() + n;
			Point destination(pos, world->friends[who].pos.GetY());
			float diff = (destination - world->friends[who].pos).GetLength();
			float fNearestEnemy = GetNearestEnemyDistance(destination);
			
			if(diff > (fNearestEnemy - fOurPlayerAdvantage)) continue;
			if(IsBlockingEnemy(destination)) continue;

			int stepCount = int(diff / float(world->params->server->player_speed_max));
			float power = GetKickPower(destination, stepCount);
			//Point path = destination - world->ball->pos;
			//float vzdial = path.GetLength();
			
			if(power <= world->params->server->ball_speed_max) 
			{
				SKILLS_DBGN("%i: ->passing to run (really 1)", world->state->GetSimTime());
				SKILLS_DBGN("%i: ->%s player %i", world->state->GetSimTime(), world->friends[who].GetSide() == OUR ? "our" : (world->friends[who].GetSide() == THEIR ? ">>their<<" : ">>unknown<<"), world->friends[who].GetUniform());
				SKILLS_DBGN("%i: ->player pos (%3.2f, %3.2f) dest (%3.2f, %3.2f)", world->state->GetSimTime(), world->friends[who].pos.GetX(), world->friends[who].pos.GetY(), destination.GetX(), destination.GetY());

      			PassBallTo(destination, 0.2f);
				return true;
			}
		}

		for(n = 40; n > 10;  n = n - 2)
		{
			float xpos = world->friends[who].pos.GetX() + n;
			float ypos = (world->me->pos.GetY() > world->friends[who].pos.GetY()) ? world->friends[who].pos.GetY() + n : world->friends[who].pos.GetY() - n;
			Point destination(xpos, ypos);
			float diff = (destination - world->friends[who].pos).GetLength();
			float fNearestEnemy = GetNearestEnemyDistance(destination);

			if(diff > (fNearestEnemy - fOurPlayerAdvantage)) continue;
			if(IsBlockingEnemy(destination)) continue;

			int stepCount = int(diff / float(world->params->server->player_speed_max));
			float power = GetKickPower(destination, stepCount);
			//Point path = destination - world->ball->pos;
			//float vzdial = path.GetLength();
			
			if(power <= world->params->server->ball_speed_max) 
			{
				SKILLS_DBGN("%i: ->passing to run (really 2)", world->state->GetSimTime());
				SKILLS_DBGN("%i: ->%s player %i", world->state->GetSimTime(), world->friends[who].GetSide() == OUR ? "our" : (world->friends[who].GetSide() == THEIR ? ">>their<<" : ">>unknown<<"), world->friends[who].GetUniform());
				SKILLS_DBGN("%i: ->player pos (%3.2f, %3.2f) dest (%3.2f, %3.2f)", world->state->GetSimTime(), world->friends[who].pos.GetX(), world->friends[who].pos.GetY(), destination.GetX(), destination.GetY());

      			PassBallTo(destination, 0.2f);
				return true;
			}
		}
	}

	return false;
}

/**
 * Compute distance to nearest opponent
 * \param target reference point
 * \return distance
 * \author Martin Zuzcak
 */
float PlayerTactics::GetNearestEnemyDistance(const Point& target)
{
  float fMinDistance = 1000.0;
	for(int i = 0; i < world->enemies.GetSize(); i++)
	{
	  float fDiffEnemy = (world->enemies[i].pos - target).GetLength();
    if (fDiffEnemy < fMinDistance)
      fMinDistance = fDiffEnemy;
    }
  return fMinDistance;
  }

/**
 * Find nearest friend player
 * \param target Reference point
 * \return Nearest player index or -1 of none found
 * \author Matus Horvath
 */
int PlayerTactics::GetNearestFriend(const Point& target)
{
	float min = 1000.0;
	int player = -1;

	for(int i = 0; i < world->friends.GetSize(); i++)
	{
		float diff = (world->friends[i].pos - target).GetLength();
		if(diff < min)
		{
			min = diff;
			player = i;
		}
	}

	return player;
}

/**
 * Compute distance to nearest friend
 * \param target Reference point
 * \return Distance
 * \author Matus Horvath
 */
float PlayerTactics::GetNearestFriendDistance(const Point& target)
{
	int player = GetNearestFriend(target);
	return player == -1 ? 1000.0f : (world->friends[player].pos - target).GetLength();
}

bool PlayerTactics::IsBlockingEnemy(const Point& target)
{
	Vector diffTarget = target - world->me->pos;
	float distToTarget = diffTarget.GetLength();

	for(int e = 0; e < world->enemies.GetSize(); e++)
	{
		Vector diffEnemy = world->enemies[e].pos - world->me->pos;
		float fDistToEnemy = diffEnemy.GetLength();

	    if(fDistToEnemy < distToTarget && fDistToEnemy > 2)
		{
  			if((diffTarget.GetAngle() - diffEnemy.GetAngle()).GetAbsDeg() < 17)
			{
				return true;
			}
		}
	}
	
	return false;
}

// GP
int PlayerTactics::GetFormation(const char* formation)
{
    if (strncmp(formation, "Formation622", 12) == 0)
       return FORMATION_622;
    else if (strncmp(formation, "Formation532", 12) == 0)
       return FORMATION_532;
    else if (strncmp(formation, "Formation523", 12) == 0)
       return FORMATION_523;
    else if (strncmp(formation, "Formation433", 12) == 0)
       return FORMATION_433;
    else if (strncmp(formation, "Formation343", 12) == 0)
       return FORMATION_343;
    else if (strncmp(formation, "Formation334", 12) == 0)
       return FORMATION_334;

   return -1;

}

int PlayerTactics::GetUnit(int PlayerCount, char type)
{
    if (PlayerCount == 2) 
        return UNIT_2_L;

    else if ((PlayerCount == 3) && (type == 'A'))
        return UNIT_3_L;
    else if ((PlayerCount == 3) && (type == 'B'))
        return UNIT_3_V;
    else if ((PlayerCount == 3) && (type == 'C'))
        return UNIT_3_OV;

    else if ((PlayerCount == 4) && (type == 'A'))
        return UNIT_4_L;
    else if ((PlayerCount == 4) && (type == 'B'))
        return UNIT_4_V;
    else if ((PlayerCount == 4) && (type == 'C'))
        return UNIT_4_OV;
    else if ((PlayerCount == 4) && (type == 'D'))
        return UNIT_4_S;

    else if ((PlayerCount == 5) && (type == 'A'))
        return UNIT_5_L;
    else if ((PlayerCount == 5) && (type == 'E'))
        return UNIT_5_23;
    else if ((PlayerCount == 5) && (type == 'F'))
        return UNIT_5_32;
    else if ((PlayerCount == 5) && (type == 'B'))
        return UNIT_5_V;
    else if ((PlayerCount == 5) && (type == 'C'))
        return UNIT_5_OV;

    else if ((PlayerCount == 6) && (type == 'A'))
        return UNIT_6_2L;
    else if ((PlayerCount == 6) && (type == 'B'))
        return UNIT_6_V;
    else if ((PlayerCount == 6) && (type == 'C'))
        return UNIT_6_OV;

    return -1;
}

void PlayerTactics::ChangeFormation(const char* formation)
{
    int unitcount1, unitcount2, unitcount3;

    unitcount1 = (int)(formation[9] - 48);
    unitcount2 = (int)(formation[10] - 48);
    unitcount3 = (int)(formation[11] - 48);

    m_cFormation.InitRawUnits(SIDE_LEFT, GetFormation(formation), GetUnit(unitcount1, (char)formation[12]), GetUnit(unitcount2, (char)formation[13]), GetUnit(unitcount3, (char)formation[14]));
	TXTN("We are changing formation to %s", formation);
}

void PlayerTactics::DefenderWithBall()
{
	// ak je aktivny ciel zrusim ho
	world->me->preparedCommands.ResetTarget();	

	if (IsFreeKick()){
		DoFreeKick();
		return;
	}	

	if(DistanceToGoal(world->me->pos) <= world->variables->GetDistanceToGoal()
		|| ShouldKickOnGoal())
	{
		KickToGoal3();		
		return;
	}
	
    ///ak je niekto vpredu, komu mozem bezpecne prihrat - radsej prihram
    int teammate = GetPassableFriend2();
	if (teammate!=-1)
	{
		PassBallToPlayer(world->friends[teammate]);
		return;
    }
    
	if (CanDribble())
	{
		AlignNeck();
		Dribble();
		return;
	}
		
	Point pos;
	GetKickPos(pos);
	PassBall2(pos, 2.0f);
	return;
	
	TurnBall();
}

#if 0
void PlayerTactics::DefenderWithoutBall(Side who, int idx)
{
    /*
    if (!InterceptBall())
        Patrol();
    return ;
    */


    world->LogWorld();
    DBGN("%d: My position (%3.2f;%3.2f), ball's position (%3.2f;%3.2f).",
            world->state->GetSimTime(), 
            world->me->pos.GetX(), world->me->pos.GetY(),
            world->ball->pos.GetX(), world->ball->pos.GetY());

    Vector vectToBall = world->ball->pos - world->me->pos;
    bool bFast = (vectToBall.GetLength()>20) ? false:true;
    
    // ak mame loptu my a mam nastaveny target, tak bezim na target
    if (who == OUR /*|| who == UNKNOWN*/){
        if (world->me->preparedCommands.activeTarget)
        {
            if (!world->me->preparedCommands.ReachTarget(world->me->pos))
            {
                RunToPos(world->me->preparedCommands.targetPos, true);
                return;
            }
        }
    }
    else{	// ak maju loptu oni, zrusime target
        world->me->preparedCommands.ResetTarget();
    }

    //m_cFormation.SetSide( SIDE_LEFT );
    //Point formationPos = m_cFormation.GetPlayerPosition( world->me->GetUniform(), world->ball->pos );
    
    if (IsFreeKick() 
            && (world->ball->pos.GetX()<=-37.0  && fabsf(world->ball->pos.GetY())<=12))
    {
        RunToPos(GetHomePos(), true);
        return;
    }

#if 0
    if (who == OUR){
        DBGN("%d: The ball is ours, proceesing default logic.",
                world->state->GetSimTime());
        BehaveWithoutBallDefault();
        return;
    }
#endif

    if (InterceptBall()) {
        DBGN("%d: Trying to intercept the ball.",
                world->state->GetSimTime());
        return;
    }

    Patrol();
}

#else
Point PlayerTactics::GetStaticPos()
{
    float ballX = world->ball->pos.GetX();
    float ballY = world->ball->pos.GetY();
    float signY = sign(GetHomePos().GetY());
    Point staticPos;
    if (ballX > 0.0f) {
        staticPos = Point((-52.5f - ballX)/2.0f + ballX, signY*15.0f);
    }
    else {
        float myX, myY, baseY;

        const float halfHeight = 34.0f;
        if (world->me->GetUniform()==3){
			baseY = 0.0f;
        }
        else {
            const float halfGoal = world->params->server->goal_width / 2.0f;
            
            Point tyckaH(-52.5f,-halfGoal);
            Point tyckaD(-52.5f, halfGoal);
            Point homePos = GetHomePos();
            Vector vH= tyckaH - homePos;
            Vector vD= tyckaD - homePos;
            if (vH.GetLength()<vD.GetLength()){
                baseY = tyckaH.GetY();
            }
            else{
                baseY = tyckaD.GetY();
            }
        }
        myX = (-52.5f - ballX)/5 + ballX;
        myY = (((ballY + halfHeight) - (baseY + halfHeight)) / 3.0f + (baseY + halfHeight)) - halfHeight;
        staticPos = Point(myX, myY);
    }
    return staticPos;
}

//AUTSAJDRY RK
void PlayerTactics::FindBestFreeKickPosition(Point &pos)
{	
	int b,a,j,index;
	float uhol;
	Point poss[3];
	Vector v,v1,v2;
	PlayerPriority pp,ppbest;
	
	for(b=0;b<15;b++){
		index=-1;
		for(a=0;a<3;a++){
			poss[a].SetX(pos.GetX());
			poss[a].SetY(pos.GetY());
		}
		v=pos-world->ball->pos;
		v1=v.OrthoLeft();
		v2=v.OrthoRight();
		v1.SetLength(1);
		v2.SetLength(1);
		v1=v1+v;
		v2=v2+v;
		v1.SetLength(v.GetLength());
		v2.SetLength(v.GetLength());

		if((world->ball->pos+v1).GetX()>-52.6 && (world->ball->pos+v1).GetX()<52.6 && (world->ball->pos+v1).GetY()>34 && (world->ball->pos+v1).GetY()<-34)
			poss[1]=world->ball->pos+v1;
		if((world->ball->pos+v2).GetX()>-52.6 && (world->ball->pos+v2).GetX()<52.6 && (world->ball->pos+v2).GetY()>34 && (world->ball->pos+v2).GetY()<-34)
			poss[2]=world->ball->pos+v2;

		for(a=0;a<3;a++){
			pp.isEnemyNear=(GetNearestEnemyDistance(poss[a])<4) ?1:0;
			
			const float off_l = GetOffsideLine();
			pp.IsInOffside =poss[a].GetX()>=off_l ?1:0;
			pp.DistToGoal=DistanceToGoal(poss[a]);

			pp.cosAngleWithEnemy=0.8;//cos(30)
			for(j=0;j<world->enemies.GetSize();j++){
				v1=poss[a] - world->ball->pos;
				v2=world->enemies[j].pos - world->ball->pos;
				if(v1.GetLength()>v2.GetLength()){
					uhol=v1.GetAngle2(v2);
					if(pp.cosAngleWithEnemy<uhol)pp.cosAngleWithEnemy=uhol;
				}
			}
			if(pp.cosAngleWithEnemy<0.8)pp.cosAngleWithEnemy=0.8;//cos(30)

			if(index==-1){
				index=a;
				ppbest=pp;
			}
			else if(pp.BetterThen(ppbest)){
				pp=ppbest;
				index=a;
			}
		}
		pos.SetX(poss[index].GetX());
		pos.SetY(poss[index].GetY());
	}	
	return;
}

void PlayerTactics::DefenderWithoutBall(Side who, int idx)
{
    world->LogWorld();
    DBGN("%d: My position (%3.2f;%3.2f), ball's position (%3.2f;%3.2f).",
            world->state->GetSimTime(), 
            world->me->pos.GetX(), world->me->pos.GetY(),
            world->ball->pos.GetX(), world->ball->pos.GetY());

    Vector vectToBall = world->ball->pos - world->me->pos;
    bool bFast = (vectToBall.GetLength()>20) ? false:true;
    bool bForLife = false;
    
    // ak mame loptu my a mam nastaveny target, tak bezim na target
    if (who == OUR || who == UNKNOWN){
        if (world->me->preparedCommands.activeTarget)
        {
            if (!world->me->preparedCommands.ReachTarget(world->me->pos))
            {
                RunToPos(world->me->preparedCommands.targetPos, true);
                return;
            }
        }
    }
    else if(!IsFreeKick()){	// ak maju loptu oni, zrusime target
        world->me->preparedCommands.ResetTarget();
    }

    //m_cFormation.SetSide( SIDE_LEFT );
    //Point formationPos = m_cFormation.GetPlayerPosition( world->me->GetUniform(), world->ball->pos );
    
    if (IsFreeKick()&& (world->ball->pos.GetX()<=-37.0 && fabsf(world->ball->pos.GetY())<=12))
    {
        RunToPoint(GetHomePos(), true);
        return;
    }

	/*
	//AUTSAJDRY RK/////
	if(IsFreeKick() && GetNearestFriend(world->ball->pos) == world->me->GetUniform()){
		world->me->preparedCommands.SetTarget(world->ball->pos,0.1);
		DBGN("%d: Idem vykopnut!!!",world->me->GetUniform());
		RunToPoint(world->ball->pos,true);
        return;
	}
	//if(IsFreeKick() && GetNearestFriend(world->ball->pos) == world->me->GetUniform())
	

	Point pos=world->me->pos;
	if(IsFreeKick() && (world->ball->pos-world->me->pos).GetLength()<30){
		FindBestFreeKickPosition(pos);
		DBGN("%d: Idem zachytit prihravku!!! %f %f",world->me->GetUniform,pos.GetX(),pos.GetY());
		world->me->preparedCommands.SetTarget(pos,0.1);
		RunToPoint(pos,bFast);
        return;
	}
	////////////////////
*/
    if (who == OUR && world->ball->pos.GetX() > 0.0){
        DBGN("%d: The ball is ours, proceesing default logic.",
                world->state->GetSimTime());
        BehaveWithoutBallDefault();
        return;
    }

    if (InterceptBall()) {
        DBGN("%d: Trying to intercept the ball.",
                world->state->GetSimTime());
        return;
    }

    /*
    Patrol();
    return ;
    */
    
#if 0
    if (world->ball->IsValid()){
        BALLARRAY balls;
        world->ball->Predict(7, balls);	

        int nSteps = world->me->PredictStepsToBall(balls);

        if ((world->ball->pos - world->me->pos).GetLength()<4.0 && nSteps <5){
            DBGN("%d: The ball is near me, going to hit it at (%3.2f;%3.2f)",
                    world->state->GetSimTime(), 
                    world->me->posToReachBall.GetX(), world->me->posToReachBall.GetY());
            RunToPos(world->me->posToReachBall, true);
            return;
        }
    }
#endif

    Vector diff;
    Point ballPos = world->ball->pos;

    int idxFriend = world->friends.FindNearestToPosIndex(world->ball->pos);
    if (idxFriend!=-1)
        diff = world->friends[idxFriend].pos - world->ball->pos;
    else
        diff.SetLength(6000.0f);

    Circle c_home(GetHomePos(), 5.0f);
    Circle c_me(world->me->pos, 2.0f);

    if (world->ball->IsValid() && 
            (c_home.IsInside(world->ball->pos)	// lopta je okolo mojej domovskej pozicie
             || 
             (c_me.IsInside(world->ball->pos)	// lopta je menej ako 2 metre odo mna
              && diff.GetLength()>2.0f)		// vzdielenost najblizsieho spoluhraca od lopty je > ako 2m
            ))
    {
        DBGN("%d: The ball is near my home position or near me and here is no friends -> trying to hit it.",
                world->state->GetSimTime());
        RunToPos( world->ball->pos, true );	
        c_home.SetRadius(5.f);
        //if (!c_home.IsInside(world->ball->pos)){
        int idNearest = world->enemies.FindNearestToPosIndex(world->me->pos);
        if (idNearest !=-1) ;
           // TurnNeckTo(world->enemies[idNearest].pos, world->me->pos + PredictNextVel(RecommDashPower(true)),0);
        else{
           // TurnNeckTo(world->ball->pos, world->me->pos + PredictNextVel(RecommDashPower(true)));
        }
        //}
        //else{
        //	TurnNeckTo(world->ball->pos, world->me->pos + PredictNextVel(RecommDashPower(true)));
        //}
        return /* void */;
    } 

#if 1
    float x, y, r = 4.0f;

    if (world->ball->pos.GetX() < GetHomePos().GetX())
        x = world->ball->pos.GetX() + ((-52.5f - world->ball->pos.GetX())/4.0f);
    else
        x = GetHomePos().GetX() + ((world->ball->pos.GetX() - GetHomePos().GetX())/2.0f);

    float halfGoal = world->params->server->goal_width / 2.0f;
    if (world->me->pos.GetX() > 0) {
        halfGoal *= 3.0f;
        r = 10.0f;
    }
    else if (world->me->pos.GetX() > -10.0f) {
        halfGoal *= 2.5f;
        r = 9.0f;
    }
    else if (world->me->pos.GetX() > -20.0f) {
        halfGoal *= 2.0f;
        r = 8.0f;
    }
    else if (world->me->pos.GetX() > -30.0f) {
        halfGoal*=1.8f;
        r = 7.0f;
    }
    else if (world->me->pos.GetX() > -40.0f) {
        halfGoal*=1.3f;
        r = 5.0f;
    }
#if 0
    if (world->me->GetUniform()==3){
        y=0.0;
    }
    else{	
        Point tyckaH(-52.5f,-halfGoal);
        Point tyckaD(-52.5f, halfGoal);
        Point homePos = GetHomePos();
        Vector vH= tyckaH - homePos;
        Vector vD= tyckaD - homePos;
        if (vH.GetLength()<vD.GetLength()){
            y = tyckaH.GetY();
        }
        else{
            y = tyckaD.GetY();
        }
    }
#else
    y = GetHomePos().GetY();
#endif

    //Point staticPos(x,y);
#else
    //Point staticPos = GetStaticPos();
#endif
    Point staticPos(GetHomePos());
    {
        Vector defendVector = world->ball->pos - staticPos;
        defendVector.SetLength(defendVector.GetLength()*0.2f);
        staticPos = staticPos + defendVector;
    }
    
    DBGN("%d: I'm player #%d with static pos at (%3.2f;%3.2f).",
            world->state->GetSimTime(),
            world->me->GetUniform(),
            staticPos.GetX(),
            staticPos.GetY());

    bool targetDesignated = false;

    /*
    if (world->me->pos.GetX() > world->ball->pos.GetX()) {
        if (world->ball->pos.GetX() > -30.0f ||
                (world->me->pos - world->ball->pos).GetLength() < 5.0f) 
        {
            staticPos.SetX(world->ball->pos.GetX() - 2.0f);
            targetDesignated = true;
            if (staticPos.GetX() < -52.5f)
                staticPos.SetX(-51.0f);
        }
    }*/

    if (!targetDesignated) {
        //int idxEnemy = world->enemies.FindNearestToPosIndex(staticPos);
        int idxEnemy = FindEnemyToBlock(staticPos);
        if (idxEnemy!=-1){			

            Vector mydist = staticPos - world->enemies[idxEnemy].pos;
            if (mydist.GetLength()<=r || world->enemies[idxEnemy].pos.GetX() < world->me->pos.GetX() - 3.0f)
            {    
                Point tmpBall(staticPos.GetX(), world->ball->pos.GetY());
                Point enemyPos(world->enemies[idxEnemy].pos);
                Vector defendVector = tmpBall - enemyPos;
                defendVector.SetLength(defendVector.GetLength()*0.1f);
                staticPos = enemyPos + defendVector;
#if 1
                if (ballPos.GetX() < staticPos.GetX()
                        ||
                        (ballPos.GetX() < -30.0f && ballPos.GetX() > -50.0f))
                {
                    staticPos.SetX(staticPos.GetX() - 2.0f);
                    bForLife = true;
                }
#endif
                targetDesignated = true;

                DBGN("%d: Enemy #%d at (%3.2f;%3.2f) is near my home position (%3.2f;%3.2f) -> blocking it.",
                        world->state->GetSimTime(),
                        world->enemies[idxEnemy].GetUniform(),
                        enemyPos.GetX(), enemyPos.GetY(),
                        staticPos.GetX(), staticPos.GetY());
            }
        }
    }

    if (!targetDesignated) {
        //int idxEnemy = world->enemies.FindNearestToPosIndex(world->me->pos);
        int idxEnemy = FindEnemyToBlock(world->me->pos);
        if (idxEnemy!=-1){
            Vector mydist = world->me->pos - world->enemies[idxEnemy].pos;
            /*Vector matedist;
            
            int idxTeammate = world->friends.FindNearestToPosIndex(world->enemies[idxEnemy].pos);
            if (idxTeammate != -1) {
                // vzdialenost spoluhraca od najblizsieho protihraca
                matedist = world->friends[idxTeammate].pos - world->enemies[idxEnemy].pos;
            }
            else {
                // spoluhrac je v "nekonecnu"
                matedist.SetX(6000.0f);
                matedist.SetY(6000.0f);
            }
            */

            if (mydist.GetLength()<=r || world->enemies[idxEnemy].pos.GetX() < world->me->pos.GetX() - 3.0f/*
                    && matedist.GetLength() > mydist.GetLength()*/)
            {	   
                Point tmpBall(staticPos.GetX(), world->ball->pos.GetY());
                Point enemyPos(world->enemies[idxEnemy].pos);

                Vector defendVector = tmpBall - enemyPos;
                defendVector.SetLength(defendVector.GetLength()*0.1f);
                staticPos = enemyPos + defendVector;
#if 1
                if (world->ball->IsValid() &&
                        (ballPos.GetX() < staticPos.GetX())
                        ||
                        (ballPos.GetX() < -30.0f))
                {
                    staticPos.SetX(staticPos.GetX() - 1.0f);
                    bForLife = true;
                }
#endif
                targetDesignated = true;

                DBGN("%d: Enemy #%d at (%3.2f;%3.2f) is near me -> blocking it.",
                        world->state->GetSimTime(),
                        enemyPos.GetX(), enemyPos.GetY(),
                        world->enemies[idxEnemy].GetUniform());
            }
        }
    }

    if ((staticPos - world->me->pos).GetLength() < 1.0f 
            && (world->ball->pos - world->me->pos).GetLength() > 10.0f) 
    {
        Scan();
        return;
    }

    RunToPoint(staticPos, bFast, bForLife);
    return;
    
    RunToPos(staticPos, bFast);
    Point neckPos;
//    int idNearest;

    /*if (m_nNeckPos == 0 
                || (world->ball->pos - world->me->pos).GetLength() < 3.0f) 
    {
        neckPos = world->ball->pos;
        m_nNeckPos = 1;
        DBGN("%d: Checking ball position at (%3.2f;%3.2f)",
                world->state->GetSimTime(),
                neckPos.GetX(), neckPos.GetY());
    }
    else if (
            (idNearest = world->enemies.FindNearestToPosIndex(world->me->pos)) != -1 
            && m_nNeckPos == 1) 
    {
        neckPos = world->enemies[idNearest].pos;
        m_nNeckPos = 2;
        DBGN("%d: Checking position of the nearest enemy at (%3.2f;%3.2f)",
                world->state->GetSimTime(),
                neckPos.GetX(), neckPos.GetY());
    }
    else {
        neckPos = GetHomePos();
        m_nNeckPos = 0;
        DBGN("%d: Checking my home position at (%3.2f;%3.2f)",
                world->state->GetSimTime(),
                neckPos.GetX(), neckPos.GetY());
    }*/

    switch (m_nNeckPos) {
        case 0:
            neckPos = Point(52.5,world->me->pos.GetY());
            break;
        case 1:
            neckPos = Point(-52.5,world->me->pos.GetY());
            break;
        case 2:
            neckPos = Point(world->me->pos.GetX(),34.0);
            break;
        case 3:
            neckPos = Point(world->me->pos.GetX(),-34.0);
            break;
    }
    if (++m_nNeckPos == 4)
        m_nNeckPos = 0;

    //TurnNeckTo(neckPos, 
    //        world->me->pos + PredictNextVel(RecommDashPower(true)),0);
}
#endif


/// \brief Taktika útočníka, ktorý má loptu
void PlayerTactics::AttackerWithBall()
{
	// If we can kick to goal, do so
//	TXTN("%d: %.2f", world->state->GetSimTime(), DistanceToGoal(world->me->pos));
	
	world->me->preparedCommands.ResetTarget();
	say->SMam(world->ball->pos, world->ball->vel);
	

	/// ak je vykop
	if (IsFreeKick()){
		DoFreeKick();
		return;
	}
	
	if(DistanceToGoal(world->me->pos) <= world->variables->GetDistanceToGoal()
		|| ShouldKickOnGoal())
	{
		KickToGoal3();
		return;
	}

/*	if (CanStopBall() == true)
	{
		log.printf("%d - Stop Ball", world->state->GetSimTime());
		StopBall();
		m_nStepsFromIHaveBall=0;
		return;
	}
*/
    ///ak je niekto vpredu, komu mozem bezpecne prihrat - radsej prihram
    int idPassFriend = GetPassableFriend2();
	if (idPassFriend!=-1)
	{
		if (world->ball->pos.GetX()<10.0)
		{
			PassBallToPlayer(world->friends[idPassFriend]);
			return;
		}
    }


	/// ak som vpredu a mozem rychlo driblovat tak driblujem rychlo

	if (world->me->pos.GetX()> 10.0 && CanFastDribble())
	{
		AlignNeck();
		FastDribble();
		return;
	}
	
	/// ak mozem bezpecne driblovat driblujem
	if (CanDribble()){
		AlignNeck();
		FastDribble();
		return;
	}

	/// mozem prist o loptu prihram 
	/*
	if (idPassFriend!=-1)
    {
        if (world->me->pos.GetX()<world->friends[idPassFriend].pos.GetX())
        {
            PassBallToPlayer(world->friends[idPassFriend]);
            return;
        }
    }
	if (idPassFriend == -1)
		idPassFriend = GetPassableFriendFreeKick();
	*/
	Point toRunPos;
	GetKickPos(toRunPos);
//	toRunPos.SetX(53.5);
//	toRunPos.SetY(5.0);
	PassBallTo(toRunPos);
	return;	


// Else find someone to pass to
	int teammate = -1;

	if(ShouldKickIn())
	{
		// \author Matus Horvath
		//DBGN("kick off, searching for world->friends");

		// We have to pass somebody, if we just dribble, we get a free_kick_fault.
		// We have enough time, so let's turn around first to see all players.
		// Update> we do not have enough time on kick_in, when we do not need this either
		// Update (Trebaticky)> we do have enough time and we need it :)
		if(scanBeforeKickOffAngle <= 360)
		{
			//DBGN("scan");
			scanBeforeKickOffAngle += Scan();
			return;
		}

		// We have made a whole circle, find someone to pass to
		// \todo Sem by sa hodila mozno neuronka
		// \todo Ak ju sem nedame, treba dat aspon GetMostFreeFriend namiesto GetNearestFriend
		teammate = GetPassableFriend2();
		DBGN("passable friend: %i", teammate == -1 ? -1 : world->friends[teammate].GetUniform());
		if(teammate == -1) {
			teammate = GetNearestFriend(world->ball->pos);
		}
		DBGN("nearest friend: %i", teammate == -1 ? -1 : world->friends[teammate].GetUniform());
	}
	else
	{
		int idNearestEnemie = world->enemies.FindNearestToPosIndex(world->ball->pos);
		if (idNearestEnemie!=-1){
			Circle c(world->enemies[idNearestEnemie].pos, 5.0);

			if (!c.IsInside(world->ball->pos)){
				float posX = 44.25f;
				float posY = world->params->server->goal_width / 2.0f;
				if(RecommDashPower(true) != world->params->server->maxpower)
					DribbleTo2(Point(posX, posY), 0);
				else
				{
					Vector where(Point(posX, posY) - world->me->pos);
					where.SetLength(2);
					PassBallTo(world->me->pos + where);
				}
			}
		}
		// We are in game, just try someone better for passing
		teammate = GetPassableFriend2();
	}

	// Now either pass to found teammmate, or dribble
	if(teammate == -1)
	{
		
		// Run to old position
		/*float posX = 52.5f;
		float posY = 0;/**/
		
		//Run to new position
		float posX = 44.25f;
		float posY = world->params->server->goal_width / 2.0f;
		
		if (world->me->pos.GetY() < 0) posY = -posY;/**/

		/*
		if(NoEnemiesAround())
		{
			//DribleTo(Point(posX,0));
			DribleTo2(Point(posX,0),0);
		}
		else
		{
			//DribleTo(Point(posX,0));
			if(!SmartDribleTo(Point(posX,0)))
			{
				//KickToGoal2();
				DumbKick(Point(posX,0));
			}
			//DribleTo2(Point(posX,0),0);
		}
		*/

		if(!ShortKick(Point(posX, posY)))
		{
			if(NoEnemiesAround())
			{
				if(RecommDashPower(true) != world->params->server->maxpower)
					DribbleTo2(Point(posX, posY), 0);
				else
				{
					Vector where(Point(posX, posY) - world->me->pos);
					where.SetLength(2);
					PassBallTo(world->me->pos + where);
				}
			}
			else
			{
				if(!SmartDribleTo(Point(posX, posY)))
				{
					if(DistanceToGoal(world->me->pos) > 25)
					{
						Point aux(world->me->pos + PolarVector(8.f, world->me->GetAbsDir()));
						if(aux.GetX() < 1.f) aux.SetX(-aux.GetX() + 3);
						if(world->me->pos.GetX() < -15)
						{
							aux.SetY(world->me->pos.GetY() - 1);
							aux.SetX(world->me->pos.GetX() + .5f * (world->me->pos.GetY() > 0 ? 1 : -1));
							PassBallTo(aux, 100.f);
						}
						else PassBallTo(aux);
//						DBGN("%d: Predkopavam si loptu (%.2f, %2f)", world->state->GetSimTime(), aux.GetX(), aux.GetY());
					}
					else
					{
						KickToGoal3();
//						DBGN("%d: Strielam na branu", world->state->GetSimTime());
					}
				}
			}
		}
	}
	else
	{
		if(!PassIntoRun())
		{
			// Prihravka
  			PassBallToPlayer(world->friends[teammate], world->me->pos.GetX() < -20 ? 3.f : .7f);
		}
		else
		{
			// P. do behu
		}
	}

	//TurnBall();
}

void PlayerTactics::AttackerWithoutBall(Side who, int idx)
{
	world->LogWorld();

	Ball nextBall(*world->ball);
	nextBall.Step();

	int idNearestEnemie = world->enemies.FindNearestToPosIndex(world->me->pos);
	
	Vector vectToBall = world->me->pos - world->ball->pos; 
	
    bool bFast = (vectToBall.GetLength()>15.0) ? false:true;
/*	if (idNearestEnemie!=-1 && (world->enemies[idNearestEnemie].pos-world->me->pos).GetLength() >=6 && vectToBall.GetLength()<15){
		say->SPrihraj(world->me->pos, world->me->GetUniform());
	}
*/	


	Point ballPos = world->ball->pos;
	Point mePos = world->me->pos;
	if (mePos.GetX()<=ballPos.GetX()+10.0 && mePos.GetX()>=ballPos.GetX()-10)
		if (idNearestEnemie!=-1 && (world->enemies[idNearestEnemie].pos-world->me->pos).GetLength()>=5 ){
		say->SPrihraj(world->me->pos, world->me->GetUniform());
	}


	if (who == OUR || who ==UNKNOWN)
	{
		if (world->me->preparedCommands.activeTarget)
		{
			if (!world->me->preparedCommands.ReachTarget(world->me->pos))
			{
				RunToPoint(world->me->preparedCommands.targetPos, bFast);
				//TurnNeckTo(nextBall.pos, world->me->pos + PredictNextVel(bFast?100.f: 45),0);
				return;
			}
		}

		if (who == OUR){
			bool fast = false;
			if ((world->me->pos-world->friends[idx].pos).GetLength()<=15.0)
				fast = false;
			
			GotoPositionToPass(fast);
			//TurnNeckTo(nextBall.pos, world->me->pos + PredictNextVel(fast?100.f: 45),0);
			return;
		}
	}
	else if(!IsFreeKick()){
		/// loptu maju oni
		world->me->preparedCommands.ResetTarget();
		if (vectToBall.GetLength()>10.0f)
		{
			// ak som v ofsajde idem z neho von
			if (InOffsidePos(GetOffsideLine()))	
			{
				ExitOffside(false);
			//	TurnNeckTo(nextBall.pos, world->me->pos + PredictNextVel(45.0),0);
				return;
			}
			return;
		}
		else{
			// ak som v ofsajde idem z neho von
			if (InOffsidePos(GetOffsideLine()))	
			{
				ExitOffside(true);
			//	TurnNeckTo(nextBall.pos, world->me->pos + PredictNextVel(100.0),0);
				return;
			}
		}	
	}
	/*

	//AUTSAJDRY RK/////
	if(IsFreeKick() && GetNearestFriend(world->ball->pos) == world->me->GetUniform()){
		world->me->preparedCommands.SetTarget(world->ball->pos,0.1);
		DBGN("%d: Idem vykopnut!!!",world->me->GetUniform());
		RunToPoint(world->ball->pos,true);
		return;
	}
		Point pos=world->me->pos;
	if(IsFreeKick() && (world->ball->pos-world->me->pos).GetLength()<30){
		FindBestFreeKickPosition(pos);
		world->me->preparedCommands.SetTarget(pos,0.1);
		DBGN("%d: Idem zachytit prihravku!!! %f %f",world->me->GetUniform(),pos.GetX(),pos.GetY());
		RunToPoint(pos,true);
		return;
	}
	////////////////////
	*/
	bool catchIt = InterceptBall();

	if(!catchIt)
	{						//nie je zodpovedny za loptu
		const float off_l = GetOffsideLine();
/*
		if(InOffsidePos(off_l)) {	//je v ofsajde
			ExitOffside();
		}
		else {					//nie je v ofsajde
*/

			m_cFormation.SetSide( SIDE_LEFT );
			Point pos = m_cFormation.GetPlayerPosition( world->me->GetUniform(), world->ball->pos );
			Vector dist = pos - world->me->pos;

				if ( dist.GetLength() > 5.0 ) {

					// test offside

					if ( pos.GetX() > off_l - 0.1f ) {
						pos.SetX( off_l - 0.1f);
					}

					RunToPoint( pos, bFast );		// pobehni za loptou
				}
				else {				//nepresuvam sa, sledujem loptu

					int t = world->me->GetSeeCount() % 3;
					/*
					// pozeraj sa na vsetky strany
					if ( t ) {
						TurnTo(world->ball->pos);
						AlignNeck();
					}
					else {
						Point tmp = world->ball->pos;
						tmp.SetY( -world->ball->pos.GetY());

						TurnNeckTo( tmp, world->me->pos );
					}
					*/
				}
//			}
//		}
	}
	/*
	else 
	{
		TurnTo(world->ball->pos);
		AlignNeck();
	}

	*/
	
}

//AUTSAJDRY RK//////////////////////////////////////////////////////////////
int PlayerTactics::GetPassableFriendFreeKick2()
{
	PlayerPriority pp,ppbest;
	float uhol;
	Vector v1,v2;
	int index=-1;

	for (int i=0; i<world->friends.GetSize(); i++)
	{
		if (world->friends[i].IsMyself())
			continue;

		if (world->friends[i].IsGoalie())
			continue;
		if(world->friends[i].GetSide() !=  OUR)
			continue;

		pp.index = i; 
		pp.ahead = (world->friends[i].pos.GetX() - world->me->pos.GetX()) >=0.0?true:false;
		pp.distance = (world->friends[i].pos - world->me->pos).GetLength();
		pp.DistToGoal=DistanceToGoal(world->friends[i].pos);
		pp.isEnemyNear=(GetNearestEnemyDistance(world->friends[i].pos)<4) ?1:0;
		
		const float off_l = GetOffsideLine();
		pp.IsInOffside=HeInOffsidePos(i,off_l);

		pp.cosAngleWithEnemy=0.866;//cos(30)
		for(int j=0;j<world->enemies.GetSize();j++){
			v1=world->friends[i].pos - world->ball->pos;
			v2=world->enemies[j].pos - world->ball->pos;
			if(v1.GetLength()>v2.GetLength()){
				uhol=v1.GetAngle2(v2);
				if(pp.cosAngleWithEnemy<uhol)pp.cosAngleWithEnemy=uhol;
			}
		}
		if(pp.cosAngleWithEnemy<0.866)pp.cosAngleWithEnemy=0.866;//cos(30)
		if(index==-1){
			index=i;
			ppbest=pp;
		}
		else if(ppbest<pp){
			pp=ppbest;
			index=i;
		}
	}

	return index;
}

int PlayerTactics::GetPassableFriend2()
{
	PlayerPriority pp,ppbest;
	float uhol;
	Vector v1,v2;
	int index=-1;

	for (int i=0; i<world->friends.GetSize(); i++)
	{
		if (world->friends[i].IsMyself())
			continue;

		if (world->friends[i].IsGoalie())
			continue;
		if(world->friends[i].GetSide() !=  OUR)
			continue;

		pp.index = i; 
		pp.ahead = (world->friends[i].pos.GetX() - world->me->pos.GetX()) >=0.0?true:false;
		pp.distance = (world->friends[i].pos - world->me->pos).GetLength();
		pp.DistToGoal=DistanceToGoal(world->friends[i].pos);
		pp.isEnemyNear=(GetNearestEnemyDistance(world->friends[i].pos)<4) ?1:0;
		
		const float off_l = GetOffsideLine();
		pp.IsInOffside=HeInOffsidePos(i,off_l);

		pp.cosAngleWithEnemy=0.866;//cos(30)
		for(int j=0;j<world->enemies.GetSize();j++){
			v1=world->friends[i].pos - world->ball->pos;
			v2=world->enemies[j].pos - world->ball->pos;
			if(v1.GetLength()>v2.GetLength()){
				uhol=v1.GetAngle2(v2);
				if(pp.cosAngleWithEnemy<uhol)pp.cosAngleWithEnemy=uhol;
			}
		}
		if(pp.cosAngleWithEnemy<0.866)pp.cosAngleWithEnemy=0.866;//cos(30)
		if(index==-1){
			index=i;
			ppbest=pp;
		}
		else if(ppbest<pp){
			pp=ppbest;
			index=i;
		}
	}

	if(pp.isgoodpos())return index;
	else return -1;
}

void PlayerTactics::MidfiledWithBall()
{
	if(DistanceToGoal(world->me->pos) <= world->variables->GetDistanceToGoal()
		|| ShouldKickOnGoal())
	{
		KickToGoal3();
		return;
	}

	if (IsFreeKick()){
		DoFreeKick();
		return;
	}	

	if (CanDribble()){
		AlignNeck();
		FastDribble();
		return;
	}

	// Else find someone to pass to
	int teammate = -1;

	if(ShouldKickIn())
	{
		// \author Matus Horvath
		//DBGN("kick off, searching for world->friends");

		// We have to pass somebody, if we just dribble, we get a free_kick_fault.
		// We have enough time, so let's turn around first to see all players.
		// Update> we do not have enough time on kick_in, when we do not need this either
		// Update (Trebaticky)> we do have enough time and we need it :)
		if(scanBeforeKickOffAngle <= 360)
		{
			//DBGN("scan");
			scanBeforeKickOffAngle += Scan();
			return;
		}

		// We have made a whole circle, find someone to pass to
		// \todo Sem by sa hodila mozno neuronka
		// \todo Ak ju sem nedame, treba dat aspon GetMostFreeFriend namiesto GetNearestFriend
		teammate = GetPassableFriend2();
		DBGN("passable friend: %i", teammate == -1 ? -1 : world->friends[teammate].GetUniform());
		if(teammate == -1) {
			teammate = GetNearestFriend(world->ball->pos);
		}
		DBGN("nearest friend: %i", teammate == -1 ? -1 : world->friends[teammate].GetUniform());
	}
	else
	{
		// We are in game, just try someone better for passing
		teammate = GetPassableFriend2();
	}

	// Now either pass to found teammmate, or dribble
	if(teammate == -1)
	{
		
		// Run to old position
		/*float posX = 52.5f;
		float posY = 0;/**/
		
		//Run to new position
		float posX = 44.25f;
		float posY = world->params->server->goal_width / 2.0f;
		
		if (world->me->pos.GetY() < 0) posY = -posY;/**/

		/*
		if(NoEnemiesAround())
		{
			//DribleTo(Point(posX,0));
			DribleTo2(Point(posX,0),0);
		}
		else
		{
			//DribleTo(Point(posX,0));
			if(!SmartDribleTo(Point(posX,0)))
			{
				//KickToGoal2();
				DumbKick(Point(posX,0));
			}
			//DribleTo2(Point(posX,0),0);
		}
		*/

		if(!ShortKick(Point(posX, posY)))
		{
			if(NoEnemiesAround())
			{
				if(RecommDashPower(true) != world->params->server->maxpower)
					DribbleTo2(Point(posX, posY), 0);
				else
				{
					Vector where(Point(posX, posY) - world->me->pos);
					where.SetLength(2);
					PassBallTo(world->me->pos + where);
				}
			}
			else
			{
				if(!SmartDribleTo(Point(posX, posY)))
				{
					if(DistanceToGoal(world->me->pos) > 25)
					{
						Point aux(world->me->pos + PolarVector(8.f, world->me->GetAbsDir()));
						if(aux.GetX() < 1.f) aux.SetX(-aux.GetX() + 3);
						if(world->me->pos.GetX() < -15)
						{
							aux.SetY(world->me->pos.GetY() - 1);
							aux.SetX(world->me->pos.GetX() + .5f * (world->me->pos.GetY() > 0 ? 1 : -1));
							PassBallTo(aux, 100.f);
						}
						else PassBallTo(aux);
//						DBGN("%d: Predkopavam si loptu (%.2f, %2f)", world->state->GetSimTime(), aux.GetX(), aux.GetY());
					}
					else
					{
						KickToGoal3();
//						DBGN("%d: Strielam na branu", world->state->GetSimTime());
					}
				}
			}
		}
	}
	else
	{
		if(!PassIntoRun())
		{
			// Prihravka
  			PassBallToPlayer(world->friends[teammate], world->me->pos.GetX() < -20 ? 3.f : .7f);
		}
		else
		{
			// P. do behu
		}
	}

	//TurnBall();
}

void PlayerTactics::MidfiledWithoutBall(Side who, int idx)
{
	/*
	//AUTSAJDRY RK/////
	if(IsFreeKick() && GetNearestFriend(world->ball->pos) == world->me->GetUniform()){
		world->me->preparedCommands.SetTarget(world->ball->pos,0.5);
		DBGN("%d: Idem vykopnut!!!",world->me->GetUniform());
		RunToPoint(world->ball->pos,true);
        return;
	}

	Point pos=world->me->pos;
	if(IsFreeKick() && (world->ball->pos-world->me->pos).GetLength()<30){
		FindBestFreeKickPosition(pos);
		DBGN("%d: Idem zachytit prihravku!!! %f %f",world->me->GetUniform(),pos.GetX(),pos.GetY());
		RunToPoint(pos,true);
        return;
	}
	////////////////////
*/

	BehaveWithoutBallDefault();
}

void PlayerTactics::GetGoalPosition(Point &pos)
{
	float sign = pos.GetY()>0.0f ? 1.0f : -1.0f;

	if (world->me->pos.GetX()<35.0f){
		Circle c(world->me->pos, 10.0);
		int nEnemyQ1 = world->GetNumberOfEnemisInQuadrant(c, Q_ATTACK_UP);
		int nEnemyQ2 = world->GetNumberOfEnemisInQuadrant(c, Q_ATTACK_DOWN);

		if (nEnemyQ1 < nEnemyQ2)
			c.GetQuadrantCenter(pos, Q_ATTACK_UP);
		else
			c.GetQuadrantCenter(pos, Q_ATTACK_DOWN);
		
		if (nEnemyQ1 == 0 && nEnemyQ2==0)
			pos = Point( c.GetCenter().GetX()+c.GetRadius(), c.GetCenter().GetY() );
	}
	else if (fabs(world->me->pos.GetY())> 20.0){
		pos = Point(44.0f, pos.GetY()>0? 13.0f:-13.0f);
	}

	else
	{
		pos = Point(44.25f, sign*world->params->server->goal_width / 2.0f);
	}
	
	
	if (fabs(pos.GetY())> 30.0f)
	{
		pos.SetY( 30.0f * sign);
	}
}


/// \brief Urci ci mozem driblovat 
/// \return \li true ak mozem
///			\li false ak nie
bool PlayerTactics::CanDribble()
{
	int idNearestEnemie = world->enemies.FindNearestToPosIndex(world->ball->pos);
	if (idNearestEnemie!=-1)
	{
		if (world->me->pos.GetX()<30.0)	/// driblujem na istotu
		{
			Circle c(world->enemies[idNearestEnemie].pos, 5.0);
			if (!c.IsInside(world->ball->pos))
				return true;
			else 
				return false;
		}
		else		// som v utoju tak aj riskujem
		{
			Point enemyPos = world->enemies[idNearestEnemie].pos;
			Circle c(enemyPos , 3.0);
			if (!c.IsInside(world->ball->pos))
				return true;
			else
			{
				if (c.IsInQuadrant(enemyPos, Q_ATTACK_UP)==false && c.IsInQuadrant(enemyPos, Q_ATTACK_DOWN)==false)
					return true;
				
				return false;
			}
		}
	}
	return true;
}

void PlayerTactics::Dribble()
{
	Point newGoal; 
	GetGoalPosition(newGoal);
	Vector where(newGoal - world->me->pos);
	where.SetLength(world->me->type->kickable_margin+0.2);
	float power = RecommDashPower(true);
	if(power != world->params->server->maxpower)
	{
		Myself meNext(*world->me);
		meNext.PredictNextVel(power);
		meNext.Step();
		float dist = (world->me->pos - meNext.pos).GetLength();
		where.SetLength(dist+0.2);
		
		
		DribbleTo2(world->me->pos + where, 0);
	}
	else
	{
		Myself meNext(*world->me);
		meNext.PredictNextVel(power);
		meNext.Step();
		float dist = (world->me->pos - meNext.pos).GetLength();
		where.SetLength(dist+0.2);

		SmartDribleTo(world->me->pos + where);
		
		//PassBallTo(world->me->pos + where);
		//SmartDribleTo(world->me->pos + where);
		
		

	}
}

bool PlayerTactics::IsFreeKick()
{
	return  world->state->IsOurKickIn();
}

void PlayerTactics::DoFreeKick()
{
	if (!LookAround())
		return;

	PlanedFreeKick();
	int i = GetPassableFriendFreeKick2();
	DBGN("%d %d: Idemrozohrat!!!",world->me->GetUniform(),i);
	PassBallToPlayer(world->friends[i]);
}


void PlayerTactics::GetKickPos(Point &pos)
{
	//if (world->me->pos
	/*
	bool podm = false;
	float r = 5.0;
	Circle c(GetHomePos(), r);
	int nEnInQuadr[4]={0, 0, 0, 0};
	vector <Point> idxEnemies;
	
	Point lt(-52.5, -34.0);
	Point lb(-52.5, +34.0);
	Point rt(+52.5, -34.0);
	Point rb(+52.5, +34.0);
	Line top(lt, rt);
	Line bottom(lb, rb);
	Line right(rt, rb);

	Point p1, p2;


	while (!podm)
	{
		idxEnemies.clear();
		nEnInQuadr[0] = world->GetNumberOfEnemisInQuadrant(c, Q_ATTACK_UP, idxEnemies);
		nEnInQuadr[1] = world->GetNumberOfEnemisInQuadrant(c, Q_ATTACK_DOWN, idxEnemies);
	//	nEnInQuadr[2] = world->GetNumberOfEnemisInQuadrant(c, Q_DEFEND_UP, idxEnemies);
	//	nEnInQuadr[3] = world->GetNumberOfEnemisInQuadrant(c, Q_DEFEND_DOWN, idxEnemies);
		
		if (top.Intercept(c, p1, p2)>0)
		{
			nEnInQuadr[c.GetPointQuadrant(p1)]++;
			if (p1.GetX()>world->me->pos.GetX())
				idxEnemies.push_back(p1);
			nEnInQuadr[c.GetPointQuadrant(p2)]++;
			if (p2.GetX()>world->me->pos.GetX())
				idxEnemies.push_back(p2);
		}
		if (bottom.Intercept(c, p1, p2)>0)
		{
			nEnInQuadr[c.GetPointQuadrant(p1)]++;
			if (p1.GetX()>world->me->pos.GetX())
				idxEnemies.push_back(p1);
			nEnInQuadr[c.GetPointQuadrant(p2)]++;
			if (p2.GetX()>world->me->pos.GetX())
				idxEnemies.push_back(p2);
		}
		
		if (right.Intercept(c, p1, p2)>0)
		{
			nEnInQuadr[c.GetPointQuadrant(p1)]++;
			idxEnemies.push_back(p1);
			nEnInQuadr[c.GetPointQuadrant(p2)]++;
			idxEnemies.push_back(p2);
		}
		
		int nQuad=0;
		for (int i=0; i<4; i++)
		{
			if (nEnInQuadr[i]>0)
				nQuad++;
		}
		if (nQuad>=3)
			podm=true;
		
		r += 5.0;
		c.SetRadius(r);
		if (r>20)
		{
			pos = GetHomePos();
			return;
		}
	}
	float m00 = idxEnemies.size();
	float m10 = 0.0;
	float m01 = 0.0;
	log.printf("\n");
	for (int i=0; i<idxEnemies.size(); i++)
	{
		
		m10 += idxEnemies[i].GetX();
		m01 += idxEnemies[i].GetY();
	}
	log.printf("\n\t\tm00:%3.2f, m10: %3.2f, m01 %3.2f",m00, m10, m01);
	pos.SetX(m10/m00);
	pos.SetY(m01/m00);
	*/

	Point mePos = world->me->pos;
	Point ballPos = world->ball->pos;
	float power;
	
	
	int meUniform = world->me->GetUniform();

	if (m_cFormation.GetPlayerRole(0, meUniform - 1) == PR_Forward)
	{
		//DBGN("UTOK");
		switch(meUniform) {
		case 9:
			//prihraj 10;
			pos = m_cFormation.GetPlayerPosition(10-1, world->ball->pos);
			pos.SetX(ballPos.GetX()+3.0f);
			power = 1.2f;
			break;
		case 10:
			{		
			pos = m_cFormation.GetPlayerPosition(11-1, world->ball->pos);
			pos.SetX(ballPos.GetX()+3.0f);
			power = 1.2f;
			Line l(world->ball->pos, pos);
			int idx;
			if (!world->enemies.IsAnyNearLine(l,3.0f, idx))
				return;

			pos = m_cFormation.GetPlayerPosition(9-1, world->ball->pos);
			pos.SetX(ballPos.GetX()+3.0f);
			power = 1.2f;
			}
			break;
		case 11:
			pos = m_cFormation.GetPlayerPosition(10-1, world->ball->pos);
			pos.SetX(ballPos.GetX()+3.0f);
			power = 1.2f;
			break;
		}
	}
	if (m_cFormation.GetPlayerRole(0, meUniform - 1) == PR_Midfielder)
	{
		DBGN("STRED");
		switch(meUniform) {
		case 7:
			//prihraj 10;
			pos = m_cFormation.GetPlayerPosition(8-1, world->ball->pos);
			pos.SetX(ballPos.GetX()+3.0f);
			power = 1.2f;
			
			break;
		case 8:
			
			pos = m_cFormation.GetPlayerPosition(7-1, world->ball->pos);
			pos.SetX(ballPos.GetX()+3.0f);
			power = 1.2f;						
			
			break;
		}
	}

	
	int id;
	Line l(ballPos, pos);
	
	// nemozem priamo prihrat strela na branu
	if (world->enemies.IsAnyNearLine(l, 2.0, id)==true)
	{
		float sign = ballPos.GetY() > 0.0 ? 1.0f : -1.0f;
		if (world->me->pos.GetX() <30.0f)
		{
			pos = Point(52.5, sign*34.00f);
			Abscisse a(ballPos, pos);
			if (world->enemies.IsAnyNearAbscisse(a, 3.0f)==false)
				return;
			//skus druhy roh
			pos.SetY(pos.GetY()*-1.0f);
			if (world->enemies.IsAnyNearAbscisse(a, 3.0f)==false)
				return;
		}

		pos.SetX(53.5);
		pos.SetY(5.0f*sign);
		power = world->params->server->ball_accel_max;
	}

}

bool PlayerTactics::DoPlan()
{
	Point kickPos;
	Point turnPos;
	Point movePos;
	
	if (world->me->preparedCommands.HaveTurnTo(turnPos))
	{
		TurnTo(turnPos);
		AlignNeck();
		SetView(WIDE_VIEW);
		world->me->preparedCommands.ResetTurnTo();
		DBGN("PLAN: Turn");
	}
	else if (world->me->preparedCommands.HaveMoveTo(movePos))
	{
		RunToPos(movePos, true); 
		world->me->preparedCommands.ResetMoveTo();
		DBGN("PLAN: Move");
	}
	
	if (world->me->preparedCommands.HaveWaitTo(world->state->GetSimTime()))
	{
		DBGN("PLAN: Wait");
		return true;
	}
	
	if (world->me->preparedCommands.HaveKick(kickPos))
	{
		DBGN("PLAN: Kick");
		float vzdialenost = (world->me->pos - kickPos).GetLength();
		float targetVel = 0.8f;
		if (vzdialenost>15.0)
			targetVel = 3.0f;

		PassBall2(kickPos, targetVel);
		world->me->preparedCommands.resetKickTo();
		return true;
	}

	if (world->me->preparedCommands.HaveFindPassableFriend())
	{
		DBGN("PLAN: FindPassableFriend");
		int idx = GetPassableFriendFreeKick2();
		if (idx!=-1)
		{
			Vector vToHe = world->friends[idx].pos - world->ball->pos;
			vToHe.SetLength(vToHe.GetLength()*0.8f);
			Point kde = world->ball->pos+vToHe;
			say->SChytaj(kde, world->friends[idx].GetUniform());
			world->me->preparedCommands.SetTurnTo(kde);
			world->me->preparedCommands.SetKickTo(kde);
			world->me->preparedCommands.ResetFindPassableFriend();
			world->me->preparedCommands.SetWaitTime(world->state->GetSimTime()+10);
			return true;
		}
	}
	return false;
}

bool PlayerTactics::LookAround()
{
	if(scanBeforeKickOffAngle <= 360)
	{
		scanBeforeKickOffAngle += Scan();
	}
	return scanBeforeKickOffAngle >360;
}

void PlayerTactics::PlanedFreeKick()
{
	world->me->preparedCommands.SetMoveTo(world->ball->pos);	
	world->me->preparedCommands.FindPassableFriend();
	world->me->preparedCommands.SetWaitTime(world->state->GetSimTime() + 10);
	m_nStepsFromMyFreeKick = 15;
}

void PlayerTactics::FastDribble()
{
	Point newGoal; 
	GetGoalPosition(newGoal);
	Vector where(newGoal - world->me->pos);
	
	float power = RecommDashPower(true);
	if(power != world->params->server->maxpower)
	{
	
		where.SetLength(5.0*world->me->type->kickable_margin);
		DribbleTo3(world->me->pos + where, 0);
	}
	else
	{
		where.SetLength(6.0*world->me->type->kickable_margin);
		DribbleTo3(world->me->pos + where, 0);
	}
}

bool PlayerTactics::CanFastDribble()
{
	int idNearestEnemie = world->enemies.FindNearestToPosIndex(world->ball->pos);
	if (idNearestEnemie!=-1)
	{
		Circle c(world->ball->pos, 7.0f);
		
		int nAUp = world->GetNumberOfEnemisInQuadrant(c, Q_ATTACK_UP);
		int nADown = world->GetNumberOfEnemisInQuadrant(c, Q_ATTACK_DOWN);
		if (nAUp == 0 || nADown ==0)
			return true;
		else
			return false;
	}
	return true;
}

typedef struct tagWHO{
	int uniform;
	float distance;
}WHO;

	struct Comparer
	{
		 bool operator()( const WHO& a, const WHO& b )
		{
			  return a.distance < b.distance;
				  
		}
	};

bool PlayerTactics::AmDependForKickoff()
{
	Point ballPos = world->ball->pos;

	vector<WHO> dist;
	WHO w;

	for (int i=2; i<11; i++)
	{
		Point he = m_cFormation.GetPlayerPosition(SIDE_LEFT, i-1);
		w.distance = (ballPos - he).GetLength();
		w.uniform = i;
		dist.push_back(w);
	}


	sort(dist.begin(), dist.end(), Comparer());
	/// toto sa nikdy nestane ale pre istotu
	if (dist.size()==0)
		return true;
	
	if (dist[0].uniform == world->me->GetUniform())
		return true;
	return false;
}

bool PlayerTactics::CanStopBall()
{
	bool canAnyKickToBall = false;
	int idx = world->enemies.FindNearestToPosIndex(world->ball->pos);
	
	if (idx != -1)
	{
		Circle heArea(world->enemies[idx].pos, world->enemies[idx].type->kickable_margin);
		if (heArea.IsInside(world->ball->pos))
			canAnyKickToBall = true;
	}

	if (m_nStepsFromIHaveBall>3 && canAnyKickToBall==false)
		return true;
	return false;
}

bool PlayerTactics::HeInOffsidePos(int index,float off_l) const
{
	if (world->friends[index].pos.GetX() < off_l) return false;
	return true;
}

