#include "Player/PlayerSkills.h"
#include "Player/PlayerTactics.h"
#include "Common/Main.h"
#include "Common/Tasks.h"
#include "Common/Support/Debug.h"
#include <stdio.h>
#include <math.h>
#include <assert.h>
#include <string.h>
#include <limits.h>

#include "DataTypes.h"

#define BALL_POS_TOL 5.0f
#define DRIBBLE_STOP_DIST 10.0f

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

static Angle CalcDir(const Vector& vector, Angle rotation)
{
	Vector tmp = vector - rotation;
	return tmp.GetAngle();
}

inline static bool Quadrat(float a, float b, float c, float* x1, float* x2)
{
	const float d = b*b - 4*a*c;
	if(d < 0) return false; //diskriminant zaporny

	const float sq_d = sqrtf(d);

	*x1 = (-b + sq_d) / (2*a);
	*x2 = (-b - sq_d) / (2*a);
	return true;
}






/*
bool PlayerSkills::DribbleRun(float angle)
{
	SKILLS_DBGN("%i: ->dribble run", world->state->GetSimTime());

	const float karea = world->params->server->ball_size + world->me->type->player_size + world->me->type->kickable_margin;
	const Point ball_nextpos = world->ball->pos + world->ball->vel;

	if((ball_nextpos - world->me->pos).GetLength() >
		(world->me->type->player_speed_max + karea))
	{
		//loptu nema sancu dostihnut za ziadnu cenu
		return false;
	}

	const Point A = world->me->pos + world->me->vel;
	const float dashpower = RecommDashPower(true);
	const float maxacc = dashpower * world->me->type->dash_power_rate * world->me->GetEffort();
	float u = world->me->GetAbsDir().GetRad();

	const Point B = A + RectVector(maxacc * cosf(u), maxacc * sinf(u));

	//vzdialenost bodu od priamky
	float sDS =  ((B.GetX() - A.GetX())*(ball_nextpos.GetY() - A.GetY()) - (B.GetY() - A.GetY())*(ball_nextpos.GetX() - A.GetX())) / maxacc;
	float DS = fabsf( sDS );

	if(DS > (0.9f * karea))
	{
		//na loptu nedociahne, resp. riziko, ze utecie
		return false;
	}

	const float controll_dist = world->params->server->ball_size + world->me->type->player_size + 0.45f * world->me->type->kickable_margin;
	if(fabsf(sDS - controll_dist*sinf(angle*M_PI/180)) > 0.4f)
	{
		return false;
	}

	float T = ( (B.GetX() - A.GetX())*(ball_nextpos.GetX() - A.GetX()) + (B.GetY() - A.GetY())*(ball_nextpos.GetY() - A.GetY()) ) / (maxacc*maxacc);

	if(T > 1)
	{
		if( (ball_nextpos - B).GetLength() > karea)
		{
			//lopta je prilis daleko
			return false;
		}
	}
	else if(T <= 0)
	{
		//lopta je prilis daleko alebo sa absolutne neoplati pohnut
		return false;
	}

	if(DS < controll_dist ) //ak je prilis blizko
	{
		float dt = sqrtf( controll_dist*controll_dist - DS*DS )/ maxacc;
		T -= dt;
	}

	if(T > 1)
	{
		T = 1;
	}
	else if(T <= 0)
	{
		return false;
	}

	if(T > 0.5f)
	{
		float power = T * dashpower;
		m_pCommandGen->Dash(power);
		TurnNeckTo(ball_nextpos,world->me->pos + PredictNextVel(power),0);
		return true;
	}
	else //bezalo by sa prilis pomaly, neoplati sa bezat
	{
		return false;
	}
}
*/


////////////////


bool PlayerSkills::TurnedInRightDir(int playerNum, int dir)
{
	Player* pl = (playerNum == -1)? world->me : &world->friends[playerNum];
	
	float turnAngle = 45.f * dir;
	if(turnAngle > 180.0f) turnAngle = turnAngle - 360.0f;
	float uhol = turnAngle - pl->GetAbsDir().GetDeg();

	if(fabsf(uhol) < 10)
		return true;
	else
		return false;
}


int PlayerSkills::PlayerDir(int player)
{
	Player* pl = (player == -1)? world->me : &world->friends[player];
	float uhol = pl->GetAbsDir().GetDeg();

	TXTN("PlayerDir : hrac natoceny do uhlu = %f", uhol);
	if(uhol < -10.f) uhol += 360.0f;

	for(int i=0;i<8;i++)
	{
		if(fabsf(45.0f*i - uhol) <= 15) 
		{
			TXTN("PlayerDir : Hrac %d natoceny do smeru %d", player, i);
			return i;
		}
	}

	TXTN("PlayerDir : Hrac %d natoceny do neznameho smeru", player, i);
	return -1;
}


// vrati pocet hracov nachadzajucich sa v nejakom sektore
int PlayerSkills::NumPlayersInSector(bool ignorefriends, bool ignoreenemies, Point pos, int dir, float angle, float mindistance, float maxdistance)
{
	int num = 0;

	Angle minAngle = DegAngle(-angle/2);
	Angle maxAngle = DegAngle(angle/2);

	Vector v;
	Angle ang;

	float rangle = 45.0f*dir;
	if(rangle > 180.f) rangle -= 360.0f;

	DegAngle degangle(rangle);

	if(!ignorefriends)
	{
		for(int i=0;i<world->friends.GetSize();i++)
		{
			v = world->friends[i].pos - pos;

			if(v.GetLength() > maxdistance) continue;
			if(v.GetLength() < mindistance) continue;

			ang = v.GetAngle() - degangle;

			if(ang<maxAngle && ang>minAngle) num++;
		}
	}

	if(!ignoreenemies)
	{
		for(int i=0;i<world->enemies.GetSize();i++)
		{
			v = world->enemies[i].pos - pos;
				
			if(v.GetLength() > maxdistance) continue;
			if(v.GetLength() < mindistance) continue;

			ang = v.GetAngle() - degangle;

			if(ang<maxAngle && ang>minAngle) num++;
		}
	}

	return num;
}



int PlayerTactics::DribbleDistance(int player, int dribbledir, int* points)
{
	int points1 = -1, points2 = -1, points3 = -1;
	Point catch_point;
	float dp;

	TXTN("DRIBBLEDISTANCE pre hraca %d, smer %d", player, dribbledir);

/*
	if(dribbledir < 2 || dribbledir > 6)
	{
		if(CanCatchAgain(2, player, catch_point, dribbledir))
		{
			if(RecommIfDribble(1, dp))
			{
				points1 = CyclesDistance(catch_point) - 2;
				TXTN("CatchPoint : x= %f, y = %f", catch_point.GetX(), catch_point.GetY());
			}
			else
				points1 = -1;

			TXTN("\tchyti vo vzdialenosti 2 bodov %d", points1);
		}
	}
*/
	if(CanCatchAgain(3, player, catch_point, dribbledir))
	{
		if(RecommIfDribble(2, dp))
		{
			points2 = CyclesDistance(catch_point) - 1;
			TXTN("CatchPoint : x= %f, y = %f", catch_point.GetX(), catch_point.GetY());
		}
		else
			points2 = -1;

		TXTN("\tchyti vo vzdialenosti 3 bodov %d", points2);
	}
	
	if(dribbledir < 2 || dribbledir > 6)
	{
		if(CanCatchAgain(4, player, catch_point, dribbledir))
		{
			if(RecommIfDribble(3, dp))
			{
				points3 = CyclesDistance(catch_point);
				TXTN("CatchPoint : x= %f, y = %f", catch_point.GetX(), catch_point.GetY());
			}
			else
				points3 = -1;

			TXTN("\tchyti vo vzdialenosti 4 bodov %d", points3);
		}
	}

	if(dribbledir > 1 && dribbledir < 7)
	{
		TXTN("\tpre hraca %d do smeru %d vybrata vzdialenost 3, pocet bodov %d", player, dribbledir, points2);
		if(points2 < 1) return -1;
		if(points != NULL) *points = points2;
		return 3;
	}
	
	int pointsmax = max(points1, max(points2, points3));
	
	if(points != NULL) *points = pointsmax;
	if(pointsmax<1) return -1;

	if(points3==pointsmax) 
	{
		TXTN("\tpre hraca %d do smeru %d vybrata vzdialenost %d, pocet bodov %d", player, dribbledir, 4, pointsmax);
		return 4;
	}

	if(points2==pointsmax)
	{
		TXTN("\tpre hraca %d do smeru %d vybrata vzdialenost %d, pocet bodov %d", player, dribbledir, 3, pointsmax);
		return 3;
	}
	
	TXTN("\tpre hraca %d do smeru %d vybrata vzdialenost %d, pocet bodov %d", player, dribbledir, 2, pointsmax);
	return 2;
}



#define DISTOLINEX 7.f
#define DISTOLINEY 7.f

bool PlayerTactics::DribbleDir(int player, bool ForwardOnly, int &newDir)
{	
	int i;

	int vahasmerov[8] = {1,0,2,1,0,1, 2, 0};
	Player* pl = (player == -1) ? (world->me) : (&(world->friends[player]));
	
	int playerdir = PlayerDir(player);

	for(i=0;i<8;i++)
	{
		if(ForwardOnly && (i>1 && i<7)) continue;
		if(!ForwardOnly && (i<=1 || i==7)) continue;

		int points;

		if(DribbleDistance(player, i, &points) == -1)
			vahasmerov[i] -= 5;
		else
			vahasmerov[i] += points;

		TXTN("DRIBBLEDIR : ohodnotenie pre smer %i = %d\n", i, vahasmerov[i]);
	}

	if(pl->pos.GetY() > (34.0f - DISTOLINEY)) 
	{
		vahasmerov[1] -= 20;
		vahasmerov[2] -= 20;
		vahasmerov[3] -= 20;
	}

	if(pl->pos.GetY() < (-34.0f + DISTOLINEY))
	{
		vahasmerov[5] -= 20;
		vahasmerov[6] -= 20;
		vahasmerov[7] -= 20;
	}

	if(pl->pos.GetX() > (52.0f - DISTOLINEX)) 
	{
		vahasmerov[0] = -20;
		vahasmerov[1] = -20;
		vahasmerov[7] = -20;
	}

	if(pl->pos.GetX() < (-52.0f + DISTOLINEX))
	{
		vahasmerov[3] = -20;
		vahasmerov[4] = -20;
		vahasmerov[5] = -20;
	}


	if(playerdir != -1) vahasmerov[playerdir] += 1;


	if((pl->pos.GetX() > 30.0f) && (pl->pos.GetY() > 15.0f))
	{
		vahasmerov[6] += 3;
		vahasmerov[7] += 3;
	}

	if((pl->pos.GetX() > 30.0f) && (pl->pos.GetY() < -15.0f))
	{
		vahasmerov[1] += 3;
		vahasmerov[2] += 3;
	}


	TXTN("DRIBBLEDIR : vahy smerov %d %d %d %d %d %d %d %d", vahasmerov[0], vahasmerov[1], vahasmerov[2],
		vahasmerov[3], vahasmerov[4], vahasmerov[5], vahasmerov[6], vahasmerov[7]);

	int best=-1, bestdir=-1;

	for(i=0;i<8;i++)
	{
		if(ForwardOnly && i>1 && i<7) continue;
		if(!ForwardOnly && (i<=1 || i>=7)) continue;

		if(vahasmerov[i] > best) 
		{
			best = vahasmerov[i];
			bestdir = i;
		}

	}

	newDir = bestdir;
	TXTN("DRIBBLEDIR : pre hraca %d vybrany smer %d", player, newDir); 

	if((newDir == playerdir) && (playerdir != -1)) return false; else return true;

}



float PlayerTactics::DribbleBallAngle(int player)
{
	if(player != -1) return 0;

	return 0;

	int dir = PlayerDir(-1);
	if(dir == -1) return 0;
	
	float dangle = 45.0f*dir;
	if(dangle > 180.f) dangle -= 360.0f;

	bool playerleft = false, playerright = false;

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

		if(diff.GetLength() > 7.0f) continue;

		float angle = dangle - diff.GetAngle().GetDeg(); 

		if((angle < 0.f) && (angle > -45.f)) playerleft = true;
		if((angle > 0.f) && (angle < 45.f)) playerright = true;

		TXTN("Hrac %d playerleft %d, playerright %d angle %f", world->enemies[i].GetUniform(), playerleft, playerright, angle);
	}

	if((playerleft && playerright) || (!playerleft && !playerright)) return 0.f;
		
	if(!playerleft && playerright) 
		return -25.f;
	else
		return 25.f;
	
	
	return 0;
}


void PlayerSkills::DribbleLow(int player, ASDribble* as)
{
	Player* pl = (player == -1) ? world->me : &(world->friends[player]);
	
	float turnAngle = 45.0f * as->turnDir;
	if(turnAngle > 180.0f) turnAngle = turnAngle - 360.0f;

	float uhol = turnAngle - pl->GetAbsDir().GetDeg();

	if(as->changedir)
	{
		Point player_nextpos = pl->pos + pl->vel;
		Point ball_nextpos = world->ball->pos + world->ball->vel;

		float karea = world->params->server->ball_size + pl->type->player_size + pl->type->kickable_margin;
		float controll_dist = world->params->server->ball_size + pl->type->player_size + 0.45f * pl->type->kickable_margin;

		as->turnAngle = CompMoment(uhol);

		if((ball_nextpos - player_nextpos).GetLength() < 0.8f*karea)
		{
			as->action = TURN;
		}
		else
		{
			as->action = SPRACUJLOPTU;

			Point player_targetpos = pl->pos + pl->vel * (1 + pl->type->player_decay);
			float ba = DegAngle(as->ballangle).GetRad();
			Point ciel = player_targetpos + RectVector(controll_dist*cosf(turnAngle + ba), controll_dist*sinf(turnAngle + ba));
			ball_nextpos = world->ball->pos + (ciel - world->ball->pos) / (1 + world->params->server->ball_decay);

			as->nearkickto = ball_nextpos;
		}

	}
	else
	{
		as->action = DRIBBLE;
		
		//float speed = (player == -1)? world->me->type->player_speed_max : world->friends[player].type->player_speed_max;
		float acc = world->params->server->player_accel_max;
		as->nearkickto = CalcBallNextPosAfterKick(player, acc, (int)as->ballangle, as->dribble_distance);
	}


}



Point PlayerSkills::SpracujLoptu()
{
	Player* pl = world->me;
	Point player_targetpos = pl->pos + pl->vel;
	float controll_dist = world->params->server->ball_size + pl->type->player_size + 0.45f * pl->type->kickable_margin;

	Point ciel = player_targetpos + PolarVector(controll_dist, pl->GetAbsDir());
	return ciel;
}







ASDribble* PlayerSkills::HoldBall()
{
	ASDribble* as = new ASDribble();
	as->type = DRIBBLET;

	//as->ballangle = DribbleBallAngle(-1);

	Point player_targetpos = world->me->pos + world->me->vel * (1 + world->me->type->player_decay);
	float controll_dist = world->params->server->ball_size + world->me->type->player_size + 0.45f * world->me->type->kickable_margin;

	float dir = 0;
	Point ciel = player_targetpos + RectVector(controll_dist*cosf(0), controll_dist*sinf(0));
	Point ball_nextpos = world->ball->pos + (ciel - world->ball->pos) / (1 + world->params->server->ball_decay);

	as->payoff = 10;
	as->action = SPRACUJLOPTU;
	as->nearkickto = ball_nextpos;

	return as;
}


void PlayerSkills::ExecuteDribble(ASDribble* as)
{
	if(as->action == SPRACUJLOPTU)
	{
		NearKick(as->nearkickto);
		
		TurnNeckTo(as->nearkickto, world->me->pos + world->me->vel, 0);
		//TurnNeckTo(DegAngle(.0f));
		newViewWidth = NORMAL_VIEW;
	}
	else if(as->action == TURN)
	{
		m_pCommandGen->Turn(as->turnAngle);
		//TurnNeckTo(world->ball->pos + world->ball->vel, world->me->pos + world->me->vel, CompTurn(as->turnAngle));
		
		TurnNeckTo(DegAngle(.0f));
		newViewWidth = NARROW_VIEW;
	}
	else if(as->action == DRIBBLE)
	{
		NearKick(as->nearkickto);
		//TurnNeckTo(world->ball->pos + world->ball->vel, world->me->pos + world->me->vel, 0);

		TurnNeckTo(DegAngle(0.f));
		newViewWidth = NARROW_VIEW;
		RunAfterBall = as->dribble_distance + 1;
	}
	else if(as->action == RUNAFTERBALL)
	{
		//TODO

	}
}


void PlayerSkills::StopBall()
{

	Point my_nextpos = world->me->pos + world->me->vel;
	Point ball_nextpos = world->ball->pos + world->ball->vel;

	float karea = world->params->server->ball_size + world->me->type->player_size + 
	world->me->type->kickable_margin;

	if((my_nextpos - ball_nextpos).GetLength() < karea)
	{
		NearKick(world->ball->pos);
	}	
}




ASDribble* PlayerTactics::TryDribble(int player)
{
	Player* pl = (player == -1) ? world->me : &(world->friends[player]);

	ASDribble* as = new ASDribble;

	as->action = DONOTHING;
	as->payoff = -1;
	as->type = DRIBBLET;
	
	as->ballangle = DribbleBallAngle(player); 
	as->changedir = DribbleDir(player, true, as->turnDir);
	as->dribble_distance = -1;

	if(as->turnDir != -1)
	{
		if(abs(((world->ball->pos - pl->pos).GetAngle() - pl->GetAbsDir()).GetDeg()) > 60)
			as->dribble_distance = 2;
		else
			as->dribble_distance = DribbleDistance(player, as->turnDir);
	}

	TXTN("TRYDRIBBLE : DribbleDir = %d, DribbleDistance = %d, DribbleBallAngle = %f", as->turnDir, as->dribble_distance, as->ballangle);

	if((as->changedir && (as->turnDir == -1)) || as->dribble_distance == -1)
	{
		TXTN("\tNie je kam bezat dopredu!!!!");
		

		as->changedir = DribbleDir(player, false, as->turnDir);

		if(as->changedir && (as->turnDir == -1))
		{
			TXTN("\tNie ja kam bezat ani do zadu!!!!");
		
			int pld = PlayerDir(-1);
			if(pld != 0)
			{
				as->action = DONOTHING;
				as->payoff = 0;
				return as;
			}

			TXTN("\tAle aj tak driblujem");
			as->turnDir = pld;
			as->changedir = false;
		}

		as->dribble_distance = 3;
		as->payoff = 1;
	}

	DribbleLow(player, as);

	if(as->action == SPRACUJLOPTU)
	{
		if(GetNearestEnemyDistance(pl->pos) < 3.0f)
		{
			TXTN("\tProtihrac je v blizkosti, nemozem spracovat loptu payoff je 1");
			// nie je cas na spracovnie
			// needpass = true;
			as->payoff = 1;
		}
		else
		{
			TXTN("\tProtihrac nie je v blizkosti, mozem spracovat loptu payoff = 3");
			as->payoff = 3;
		}
	}
	else if(as->action == TURN)
	{
		if(GetNearestEnemyDistance(pl->pos) < 3.0f)
		{
			TXTN("\tProtihrac je v blizkosti, nemozem sa otocit payoff je 1");
			as->payoff = 1;
		}
		else
		{
			TXTN("\tProtihrac nie je v blizkosti, mozem sa otocit payoff je 3");
			as->payoff = 3;
		}

	}
	else if(as->action == DRIBBLE)
	{
		if(as->dribble_distance == -1)
		{
			as->dribble_distance = 2;
			as->payoff = 1;
			TXTN("\tNie je kam driblovat ale mozme skusit payoff 1");
		}
		else
		{
			as->payoff = 3 + as->dribble_distance;
			TXTN("\tDriblovanie s payoff = %d", as->payoff);
		}
	}
	else if(as->action == RUNAFTERBALL)
	{
		if(FollowedByEnemy(player))
			as->payoff = 1;
		else
			as->payoff = 3;

	}

	return as;

}




bool PlayerSkills::FollowedByEnemy(int player)
{
	return false;
}




Point PlayerSkills::CalcBallNextPosAfterKick(int PlayerNum, float playeracc, int angle, int distance, int shootdir)
{
	if(angle > 90)
	{
		angle = 90;
	}
	else if(angle < -90)
	{
		angle = -90;
	}

	if((distance < 2)||(distance > 4)) distance = 2;
	const float acc = min(world->params->server->player_accel_max, playeracc);
	
	Player* player = (PlayerNum == -1)? world->me : &world->friends[PlayerNum];
	PLAYER_TYPE* type = player->type; 

	Point player_nextpos = player->pos + player->vel;
	Point ball_nextpos = world->ball->pos + world->ball->vel;

	Point player_targetpos = player->pos;
	Vector vel = player->vel;
	//vel.SetLength(vel.GetLength() * type->player_decay);
	

	const float karea = world->params->server->ball_size + type->player_size + type->kickable_margin;	
	const float controll_dist = world->params->server->ball_size + type->player_size + 0.45f * type->kickable_margin;

	float dir, uhol;

	if((shootdir != -1) && (shootdir != PlayerDir(PlayerNum)))
	{
		uhol = 0.785398f*shootdir;
		//if(shootdir > 4) uhol -= 6.2831853f;

		dir = uhol + angle*0.0174532f;
		vel.SetLength(0);
	}
	else
	{
		dir = (player->GetAbsDir() + DegAngle((float)angle)).GetRad();
		uhol = player->GetAbsDir().GetRad();
	}

	float sum = 1;
	float decay = 1;

	for(int i=2;i<=distance;i++)
	{
		vel = vel * type->player_decay + RectVector(acc * cosf(uhol), acc * sinf(uhol));
		
		//TXTN("CalcBallNextPosAfterKick beh %d vel = %f", i, vel.GetLength());

		if(vel.GetLength() > type->player_speed_max) vel.SetLength(type->player_speed_max);

		player_targetpos += vel;

		decay *= world->params->server->ball_decay;
		sum += decay;
	}
	TXTN("CalcBallNextPosAfterKick : TargetPos x = %f, y = %f", player_targetpos.GetX(), player_targetpos.GetY());

	Point ciel = player_targetpos + RectVector(controll_dist*cosf(dir), controll_dist*sinf(dir));
	TXTN("CaclBallNextPosAfterKick : TargetBallPos x = %f, y = %f", ciel.GetX(), ciel.GetY());
	ball_nextpos = world->ball->pos + (ciel - world->ball->pos) / sum;
	
	return ball_nextpos;
}












bool PlayerTactics::CanCatchAgain(int distance)
{
	Point cp;
	return CanCatchAgain(distance, -1, cp);
}


bool PlayerTactics::CanCatchAgain(int distance, int player, Point& catchpoint, int shootdir)
{
	//float speed = (player == -1)? world->me->type-> : world->friends[player].type->player_speed_max;
	float acc = world->params->server->player_accel_max;
	Point nextBallPos = CalcBallNextPosAfterKick(player, acc, 0, distance, shootdir);
	
	Ball lopta(*world->ball);
	//Point kde;
	
	//lopta.pos = world->ball->pos;
	lopta.vel = nextBallPos - lopta.pos;
	return CanInterceptBall(&catchpoint, &lopta, player, true, distance-1);
}






void PlayerSkills::NearKick(const Point& ciel)
{
	TXTN("%i: ->near kicking to position %f, %f", world->state->GetSimTime(), ciel.GetX(), ciel.GetY());
	//SKILLS_DBGN("%i: ->pos (%3.2f, %3.2f)", world->state->GetSimTime(), ciel.GetX(), ciel.GetY());

	//ak je dostatocne blizko
	if(m_fBallDistance < (world->me->type->player_size + world->me->type->kickable_margin + world->params->server->ball_size))
	{
		if(m_fBallDistance < (world->me->type->player_size + world->params->server->ball_size))
		{
			//nemoze byt tak blizko
			m_fBallDistance = world->me->type->player_size + world->params->server->ball_size;
		}

		float dir_diff = (m_BallDiff.GetAngle() - world->me->GetAbsDir()).GetAbsDeg();
		if(dir_diff < 0.f) dir_diff =- dir_diff;

		const float ball_power_rate = world->params->server->kick_power_rate *
			(1 - 0.25f * (dir_diff/180) - 0.25f * (m_fBallDistance - world->me->type->player_size - world->params->server->ball_size) / world->me->type->kickable_margin);

		float maxacc = world->params->server->maxpower * ball_power_rate;
		if(maxacc > world->params->server->ball_accel_max)
		{
			maxacc = world->params->server->ball_accel_max;
		}


		Point ball_zac = (world->ball->pos + world->ball->vel);
		Vector k = ciel - ball_zac;

		float req_acc = /*1.14f **/ k.GetLength();
		float kick_dir = CalcDir(k, world->me->GetAbsDir()).GetDeg(); //povodny vypocet smeru

		Vector smer = ciel - world->ball->pos;
		const float vzdial = smer.GetLength();

		if(vzdial <= 0.1f)
		{
			TXTN("   ->near kick lopta blizko pozicie kam treba kopnut");

			Vector ivel = world->ball->vel * -1.0f;
			TXTN("   ->ivel = %f, %f", ivel.GetLength(), ivel.GetAngle().GetDeg());

			kick_dir = CalcDir(ivel, world->me->GetAbsDir()).GetDeg();
			req_acc = (req_acc > maxacc) ? maxacc : req_acc;
		}
		else if(req_acc > maxacc) //tak silno nedokaze kopnut
		{	
			float a = vzdial * vzdial;
			float b = -2 * world->ball->vel.GetX() * smer.GetX()
				-2 * world->ball->vel.GetY() * smer.GetY();
			float c = world->ball->vel.GetX() * world->ball->vel.GetX() + world->ball->vel.GetY() * world->ball->vel.GetY() - maxacc*maxacc;

			float n1,n2;
			bool success = Quadrat(a,b,c,&n1,&n2);
			if(success) //kvadraticka rovnica ma riesenie
			{
				//riesenie je pouzitelne
				if(n1 >= 0 && n1 <= 1)
				{
					Vector nkdir = smer * n1 - world->ball->vel;
					kick_dir = CalcDir(nkdir, world->me->GetAbsDir()).GetDeg();
				}
				//inak sa pouzije prednastavena hodnota kick_dir
			}
			else //pokus o spomalenie lopty
			{
				TXTN("   ->pokus o spomalenie lopty");
				kick_dir = CalcDir(world->ball->vel * -1.0f, world->me->GetAbsDir()).GetDeg();
			}


			req_acc = maxacc;
		}

		float req_power = req_acc / ball_power_rate;
		m_pCommandGen->Kick(req_power,kick_dir);
	}
}
