

#include "generic.h"
#include "lfptypes.h"
#include "define.h"
#include "ml.h"

#include "ctrl.h"

#ifndef N64
 #include "fontcode.h"
 #include "dbugtxt.h"
#endif


#define BOUNCE_FRAME 0x1500

#define	TO_RDISTMIN		0x700000		// Minumum distance from receiver for turn-over
#define	TO_IDISTMAX		0x200000		// Maximum distance of interceptor from receiver for grab

#define REACT_TIME 3							//minimun no of ticks before IK intercept can be made

extern char *l_names[],*a_names[],*main_names[];

int closest_approach(playert *plyr1, playert *plyr2, int *x, int *y)
{
int x_vel,  y_vel;
int x_diff, y_diff;
SW  angle;
int c,s;
int speed;

//find time of closest approach
	x_diff = (plyr2->xco - plyr1->xco) >> 8;
	y_diff = (plyr2->yco - plyr1->yco) >> 8;

	x_vel = plyr1->xvel - plyr2->xvel;
	y_vel = plyr1->yvel - plyr2->yvel;

	angle = LFPAtn(x_vel, y_vel);
	c = LFPCos(angle) >> 6;
	s = LFPSin(angle) >> 6;

	speed = ((x_vel*c) + (y_vel*s)) >> 8;

	*x = ((x_diff * c) + (y_diff * s));
	*y = ((x_diff * -s) + (y_diff * c));
	return *x/speed;
}


static int bonus_int_angle[3]={
0x200,0x100,0};


static void i_stats(playert *plyr)
{
	if (project_flag)	return;

	if (ball.main_routine==loose_ball_move && (crossX || crossY) )
	{
		if (plyr->team!=bhp->team)
			stats_o_reb(plyr);
		else
			stats_d_reb(plyr);
	}
	else if (ball.main_routine==pass_ball_move && plyr->team!=bhp->team)
	{
		steal_commentary( bhp, plyr );
		stats_steal(plyr);
		stats_TO(bhp);
	}
}


int i_check_pass(int *t, int *z)
{
playert *op;
SW  a_diff;
int bs;
int v;
SW  ma;
int	oc;		// Offensive controller
int	dc;		// Defensive controller

#ifdef PLAY
	return -1;
#endif

	bs = MANHATTAN(ball.xvel, ball.yvel);
	oc=ai_team[bhp->team].controllers[0];
	dc=ai_team[bhp->team^1].controllers[0];

#ifdef Pc
	bhp->plyrROM->ub___pAttrPass = (bhp->no%5)*20;
#endif

	// Check for the long bomb from the back court here
	if (PLY(bhp)<0 && !fast_break_flag)
	{
		int	dx,dy;
		int	dist;

		op=&player[int_recvr];
		dx=op->xco-bhp->xco;
		dy=op->yco-bhp->yco;
		dist=MANHATTAN(dx,dy);
		if (dist>TO_RDISTMIN)
		{
			playert	*p,*e;

			p=&player[bhp->base^5];
			e=p+5;
			do
			{
				int	ddx,ddy;
				int	ddist;

				if (p->flags&FALLING)
					continue;

				if (p->ball_dist>op->ball_dist+COL_DI/2)
					continue;

				ddx=p->xco-op->xco;
				ddy=p->yco-op->yco;
				ddist=MANHATTAN(ddx,ddy);
				if (ddist<0x100000)
					return p->no;

			} while(++p<e);
		}
	}

	// On inbounds, only alllow steals on the long bomb
	if (!stealable_flag)
		return -1;

	// Old-fashioned intercept pass here
	if ((dc==0) && (oc==0))			//CPU vs CPU bh
		v = (bhp->plyrROM->ub___pAttrPass + 50)/2;
	else if ((dc!=0) && (oc==0))	//Human vs CPU bh	//v lower if difficulty higher
		v = (bhp->plyrROM->ub___pAttrPass + 33 + (DIFFICULTY*33))/2;
	else if ((dc==0) && (oc!=0))	//CPU vs Human bh
		v = (bhp->plyrROM->ub___pAttrPass + 100 - (DIFFICULTY*33))/2;
	else if ((dc!=0) && (oc!=0))	//Human vs human
		v = (bhp->plyrROM->ub___pAttrPass + 50)/2;

	ma = MIN_MAX(v, 0x800, 0x300);

	if (ai_team[bhp->team^1].press)
	{
		ma-=0x180;
	}

	//penalize jump pass
	if (bhp->zco)
	{
		ma+=0x300;
	}



	for (op = player+(bhp->base^5); op < (player+(bhp->base^5)+5) ; op++)
	{
		SW ba;
		int bd;

		if (op->flags&FALLING)
			continue;

		if ((op->last_speed==0) || (op->shuffle))
		{
			ba = op->ball_angle;
			bd = op->ball_dist;
		}
		else
		{
			int time;
			int px, py;

			time = op->ball_dist/bs;

			px = op->xco + (time*op->xvel);
			py = op->yco + (time*op->yvel);
			ba = LFPAtn(ball.xco-px, ball.yco-py);
			bd = MANHATTAN(ball.xco-px, ball.yco-py);
		}

		//is ball coming my way
		a_diff = ba - ball.angle - 0x8000;
		a_diff = abs(a_diff);

		if (op->control)
		{
			int t;
			t = (bhp->control) ? 0x100: bonus_int_angle[DIFFICULTY];
			a_diff -= t;
		}

		if (abs(a_diff) < ma)
		{
			//am i facing ball?
			a_diff = ba - op->angle;
			if (abs(a_diff) < 0x4000)
			{
				//recvr nearer?
				if (player[int_recvr].ball_dist > bd)
				{
					int x,y;

					*t = closest_approach(op, &ball, &x, &y);

					if ((*t < ONE_SEC) && (*t>0))
					{
						get_future_ball_cos(*t, &x, &y, z);

						if ( *z < (op->scale*(2500<<2)) )
						{
							op->target_x = x;
							op->target_y = y;
							if (random(50)<op->plyrROM->ub___pAttrSteal-bhp->plyrROM->ub___pAttrPass)
								return op->no;
						}
					}
				}
			}
		}
	}

	return -1;
}


void intercept_pass(playert *plyr)
{
	CallChainP(intercept_pass);

	if (attack_home_in(plyr, (SW)plyr->ball_angle))
	{
		current_ctrlr->d_angle = plyr->ball_angle;
		current_ctrlr->force   = 0x10;
	}
}


void missed_intercept2(playert *plyr)
{
	if (blend_to_end(plyr, TOP_RDY, LEG_RDY, 2))
	{
		SetMain(missed_intercept2,plyr,deflt);
		plyr->top_routine = top_deflt;
		plyr->leg_routine = leg_deflt;
	}
}


void intercept(playert *plyr)
{
int dist;
int xd, yd;

	CallChainP(intercept);

	xd = plyr->target_x - plyr->xco;
	yd = plyr->target_y - plyr->yco;

	dist = MANHATTAN(xd, yd);

	current_ctrlr = ctrlrs;

	if (dist < 0x100000)
	{
		current_ctrlr->d_angle = LFPAtn(ball.xco - plyr->xco,
										ball.yco - plyr->yco);
		current_ctrlr->force   = 0x10;
	}
	else
	{
		current_ctrlr->d_angle = LFPAtn(xd, yd);
		current_ctrlr->force   = 0xf0;
	}

	plyr->ctr2--;
	
	if (project_flag)	return;


	if (plyr->ctr2 <= 0)
	{
		int bx, by, bz;
	
		start_next_anim2(plyr, 8);

		{
		#if defined(DEBUG)
			{
				char	msg[128];

				sprintf(msg,"Intercept old: %c%s\n",(plyr->top_anim>0)? ' ' : '-',a_names[abs(plyr->top_anim)]);
				PCwrite(-1,msg,strlen(msg));
			}
		#endif

			// Just quit if someone else already got the ball or player sucks
			if (possession_flag || rebound_flag || random(150)>plyr->plyrROM->ub___pAttrSteal)
			{
			#if defined(DEBUG)
				{
				int		i;
				char	txt[128];
				char	lp[16];

				memset(lp,0,sizeof(lp));
				IntToDecStr(lp_ctr,lp);

				sprintf(txt,"%s: Intercept Quit: Ball Possessed\n",lp);
				PCwrite(-1,txt,strlen(txt));
				}
			#endif

				SetIkBlendSpeed(intercept,plyr,-0x100/4);
				SetMain(intercept, plyr, missed_intercept2);
				return;
			}

			SetMain(intercept,plyr,dribble);
			SetPossession(intercept,TRUE);
			plyr->top_routine  = dribble_animate;

			current_ctrlr		   = ctrlrs+plyr->control;
			current_ctrlr->force   = 0xf0;
			current_ctrlr->d_angle = plyr->angle;

			project(plyr, 9, FALSE);
			DUMMY.top_frame = BOUNCE_FRAME;
			DUMMY.ikBlend   = 0;
			PlayGfxEvalBall(&DUMMY, &bx, &bz, &by);

			//if (abs(bx-ball.xco) > 0x200000)	BRK;
			//if (abs(bz-ball.zco) > 0x200000)	BRK;
			
			plyr->next_anim = DUMMY.top_anim;

			i_stats(plyr);	// Update stats if this is a steal
			MOMUP(plyr->team,5);

			catch_ball(plyr);

			SetMain(intercept,&ball,ball_ik_blend);
			ball.xvel = (bx-ball.xco) / 8;
			ball.yvel = (by-ball.yco) / 8;
			ball.zvel = (bz-ball.zco) / 8;

			SetIkBlendSpeed(intercept,plyr,-0x100/8);

			SetMain(intercept,plyr,intercept_recover);
			plyr->top_routine  = NULL;
		}
	}
}






void intercept_catch(playert *plyr)
{
	CallChainP(intercept_catch);

	if (end_animation_test(plyr))
	{
		SetMain(intercept_catch,plyr,stand_with_ball);
		if (!plyr->leg_routine)		// Standing around after catch bug happens here
			plyr->leg_routine=leg_deflt;
	}

#if defined(DEBUG)
	{
	int		i;
	char	txt[128];
	char	lp[16];
	char	lineno[16];

	for (i=0; i<16; i++)
		lp[i]=lineno[i]=0;

	IntToDecStr(lp_ctr,lp);
	IntToDecStr(__LINE__,lineno);

	sprintf(txt,"%s: %c%d Anim: %s [ intercept_catch (%s:%s) ]\n",
			lp,project_flag? '*':' ',plyr->no,a_names[abs(plyr->top_anim)],__FILE__,lineno);
	PCwrite(-1,txt,strlen(txt));
	}
#endif
}




void intercept_recover(playert *plyr)
{

	CallChainP(intercept_recover);

	/*
	 * keep running
	 */
	current_ctrlr->force   = 0xf0;
	current_ctrlr->d_angle = plyr->angle;

	/*
	 * if done, then start dribble
	 */
	if (blend_to_end(plyr, plyr->next_anim, 0 , 4))
	{
		SetMain(intercept_recover,plyr,dribble);
		SetPossession(intercept_recover,TRUE);
		plyr->top_routine  = dribble_animate;
	}

	if (plyr->top_anim == plyr->next_anim)	// Probably
	{
		if (plyr->top_frame == 0)
		{
			plyr->top_frame = BOUNCE_FRAME-(plyr->top_rate*4);
		}
	}

#if defined(DEBUG)
	{
	int		i;
	char	txt[128];
	char	lp[16];
	char	lineno[16];

	for (i=0; i<16; i++)
		lp[i]=lineno[i]=0;

	IntToDecStr(lp_ctr,lp);
	IntToDecStr(__LINE__,lineno);

	sprintf(txt,"%s: %c%d Anim: %s [ intercept_recover (%s:%s) ]\n",
			lp,project_flag? '*':' ',plyr->no,a_names[abs(plyr->top_anim)],__FILE__,lineno);
	PCwrite(-1,txt,strlen(txt));
	}
#endif
}



void missed_intercept(playert *plyr)
{
int dist;
int xd, yd;

	CallChainP(missed_intercept);

	xd = plyr->target_x - plyr->xco;
	yd = plyr->target_y - plyr->yco;

	dist = MANHATTAN(xd, yd);

	if (dist < 0x100000)
	{
		current_ctrlr->d_angle = LFPAtn(ball.xco - plyr->xco,
										ball.yco - plyr->yco);
		current_ctrlr->force   = 0x10;
	}
	else
	{
		current_ctrlr->d_angle = LFPAtn(xd, yd);
		current_ctrlr->force   = 0xf0;
	}

	//get ball-hand distance
	plyr->ctr2--;
	
	if (plyr->ctr2 <= 0)
	{
		SetIkBlendSpeed(intercept,plyr,-0x100/HALF_SEC);

		start_next_anim2(plyr, HALF_SEC);

		SetMain(missed_intercept,plyr,missed_intercept_recover);
	}

#if defined(DEBUG)
	{
	int		i;
	char	txt[128];
	char	lp[16];
	char	lineno[16];

	for (i=0; i<16; i++)
		lp[i]=lineno[i]=0;

	IntToDecStr(lp_ctr,lp);
	IntToDecStr(__LINE__,lineno);

	sprintf(txt,"%s: %c%d Anim: %s [ missed_intercept (%s:%s) ]\n",
			lp,project_flag? '*':' ',plyr->no,a_names[abs(plyr->top_anim)],__FILE__,lineno);
	PCwrite(-1,txt,strlen(txt));
	}
#endif
}



void missed_intercept_recover(playert *plyr)
{
	CallChainP(missed_intercept_recover);

	current_ctrlr->force   = 0x10;
	current_ctrlr->d_angle = plyr->ball_angle;
	current_ctrlr->mctrlr  = 0;

	if (end_animation_test(plyr))
	{
		SetMain(missed_intercept_recover,plyr,deflt);
		plyr->top_routine=top_deflt;
	}
#if defined(DEBUG)
	{
	int		i;
	char	txt[128];
	char	lp[16];
	char	lineno[16];

	for (i=0; i<16; i++)
		lp[i]=lineno[i]=0;

	IntToDecStr(lp_ctr,lp);
	IntToDecStr(__LINE__,lineno);

	sprintf(txt,"%s: %c%d Anim: %s [ missed_intercept_recover (%s:%s) ]\n",
			lp,project_flag? '*':' ',plyr->no,a_names[abs(plyr->top_anim)],__FILE__,lineno);
	PCwrite(-1,txt,strlen(txt));
	}
#endif
}



bool intercept_jump_test(playert *plyr)
{
int x,y,z, zv;
int bx, by, bz;
int time;
int ballDist, lastDist;
int		tx,ty,td;

	CallChainP(intercept_jump_test);

	if (rebound_flag)
		return FALSE;

	if (possession_flag)
		return( FALSE );

	if (project_flag)
		return FALSE;

	if (scored_flag)
		return FALSE;

	GetNodePos(plyr, headNodes);

	x = plyr->nodeVector[NODE_HEAD].x << 10;
	y = plyr->nodeVector[NODE_HEAD].z << 10;
	z = plyr->nodeVector[NODE_HEAD].y << 10;
	zv= plyr->zvel;

	lastDist = 0x7fffffff;

	/*
	 * Where is ball going to be closest to head
	 */

	for (time=1; z>0; time++)
	{
		x += plyr->xvel;
		y += plyr->yvel;
		z += zv;
		zv-= LITTLE_G;
		
		get_future_ball_cos(time-1, &bx, &by, &bz);

		ballDist = ((bx-x)>>10) * ((bx-x)>>10)
				  +((by-y)>>10) * ((by-y)>>10)
				  +((bz-z)>>10) * ((bz-z)>>10);

		if (ballDist > lastDist)	break;

		if (ballDist < 0x200000/0x10)
		{
			ballDist *= 0x10;

			project(plyr, time, FALSE);

			tx=plyr->target_x;
			ty=plyr->target_y;
			td=plyr->target_dist;

			plyr->target_x=bx;
			plyr->target_y=by;
			plyr->target_dist=time;

			if (ik_simple(&DUMMY, bx/1024, bz/1024, by/1024))
			{
#ifdef DEBUG
				{
					char
						text[128],
						numstr[8];

					strcpy( text, "jump_test ball:" );

					memset( numstr, 0, 8 );
					IntToDecStr( bx>>10, numstr );
					strcat( text, numstr );
					strcat( text, "," );

					memset( numstr, 0, 8 );
					IntToDecStr( by>>10, numstr );
					strcat( text, numstr );
					strcat( text, "," );

					memset( numstr, 0, 8 );
					IntToDecStr( bz>>10, numstr );
					strcat( text, numstr );

					strcat( text, " player:" );

					memset( numstr, 0, 8 );
					IntToDecStr( x>>10, numstr );
					strcat( text, numstr );
					strcat( text, "," );

					memset( numstr, 0, 8 );
					IntToDecStr( y>>10, numstr );
					strcat( text, numstr );
					strcat( text, "," );

					memset( numstr, 0, 8 );
					IntToDecStr( z>>10, numstr );
					strcat( text, numstr );
					strcat( text, "\n" );

					PCwrite( -1, text, strlen( text ) );
				}
#endif
				SetMain(intercept_jump_test,plyr,jump_catch);
				start_blend_anim2(plyr, DUMMY.top_anim, time);
				SetIkBlendSpeed(intercept,plyr,0x100/time);

				plyr->top_routine  = NULL;
				SetMain(intercept_jump_test,plyr,jump_catch);
				return TRUE;
			}
			else
			{
				plyr->target_x=tx;
				plyr->target_y=ty;
				plyr->target_dist=td;

				return FALSE;
			}
		}
	
		lastDist = ballDist;
	}

	return FALSE;
}



void jump_catch(playert *plyr)
{
int t;

	if (plyr->zco<0)
	{
		plyr->zco = 0;
		//BRK;
	}

	CallChainP(jump_catch);
	
	//plyr->xco += plyr->xvel;
	//plyr->yco += plyr->yvel;
#if 0
	t=plyr->target_dist--;
	if (t)
	{
		plyr->xvel=(plyr->target_x-plyr->xco)/t;
		plyr->yvel=(plyr->target_y-plyr->yco)/t;
	}
#endif
	collision(plyr,plyr->xvel,plyr->yvel,COL_DI);
	plyr->zco += plyr->zvel;
	plyr->zvel-= LITTLE_G;

	if (end_animation_test(plyr))
	{
		t = time_till_land(plyr);
		if (t<5)	t = 5;

		SetIkBlendSpeed(intercept,plyr,-0x100/t);
		if (in_play_flag)
		{
			if (possession_flag)
			{
				SetLastHandler(jump_catch,ball_handler);
			}
			else
			{
				i_stats(plyr); // Update stats if this is a steal

#ifdef DEBUG
				{
					char
						text[128],
						numstr[8];

					strcpy( text, "catch ball:" );

					memset( numstr, 0, 8 );
					IntToDecStr( ball.xco>>10, numstr );
					strcat( text, numstr );
					strcat( text, "," );

					memset( numstr, 0, 8 );
					IntToDecStr( ball.yco>>10, numstr );
					strcat( text, numstr );
					strcat( text, "," );

					memset( numstr, 0, 8 );
					IntToDecStr( ball.zco>>10, numstr );
					strcat( text, numstr );

					strcat( text, " player:" );

					memset( numstr, 0, 8 );
					IntToDecStr( plyr->xco>>10, numstr );
					strcat( text, numstr );
					strcat( text, "," );

					memset( numstr, 0, 8 );
					IntToDecStr( plyr->yco>>10, numstr );
					strcat( text, numstr );
					strcat( text, "," );

					memset( numstr, 0, 8 );
					IntToDecStr( plyr->zco>>10, numstr );
					strcat( text, numstr );
					strcat( text, "\n" );

					PCwrite( -1, text, strlen( text ) );
				}
#endif
				catch_ball(plyr);
				MOMUP(plyr->team,5);
			}
		}
		start_next_anim2(plyr, t);

		SetMain(jump_catch,plyr,jump_caught);
	}
}


void jump_caught(playert *plyr)
{
	CallChainP(jump_caught);

	//plyr->xco += plyr->xvel;
	//plyr->yco += plyr->yvel;
	collision(plyr,plyr->xvel,plyr->yvel,COL_DI);
	plyr->zco += plyr->zvel;
	plyr->zvel-= LITTLE_G;

	if (plyr->zco <0)
	{
		start_leg_anim2(plyr, LEG_REB_LD,5);
		SetMain(jump_caught,plyr,rebound_landed);
		plyr->zco = 0;
	}
}




void steal_pass(playert *plyr, int endTime)
{
SW  angle;
int bx,by,bz;
int x_diff;
int y_diff;
int ballDist, minDist, lastDist;
int time, minTime;
int	too_bad_flag=FALSE;

	/*
	 * make sure ball won't be caught before we can react
	 */

	if (project_flag)
		return;

	if (ball.ctr2 <= REACT_TIME)		return;

	/*
	 * Where is ball going to be closest to current position?
	 */

  memcpy( (void *)&DUMMY, (void *)plyr, sizeof(playert));
	lastDist =
	minDist  = 0x7fffffff;

	
	for (time=REACT_TIME; time<ball.ctr2; time++)
	{
		get_future_ball_cos(time, &bx, &by, &bz);

		//if ((bz<0x280000) && (bz>0x80000))
		{
			ballDist = MANHATTAN(bx-plyr->xco, by-plyr->yco);
			if (ballDist < minDist)
			{
				//angle = LFPAtn(bx-plyr->xco, by-plyr->yco);
				//angle -=plyr->angle;
				
				if (1)	//abs(angle) < 0x4000)
				{
					minDist = ballDist;
					minTime = time;
				}
			}

			if (ballDist > lastDist)	break;
			else						lastDist = ballDist;
		}
	}

	get_future_ball_cos(minTime, &bx, &by, &bz);

	/*
	 * Now make this position the target for the player
	 */

	plyr->target_x = bx;
	plyr->target_y = by;
	plyr->ctr2     = minTime+2;

	SetMain(steal_pass,plyr,intercept);

#if 1

	project(plyr, minTime+1, FALSE);

//	if (random(60)-30+plyr->plyrROM->ub___pAttrSteal<bhp->plyrROM->ub___pAttrPass)
//		too_bad_flag==FALSE;



	if (!stealable_flag || !ik_simple(&DUMMY, bx/1024, bz/1024, by/1024))
	{
		SetMain(steal_pass,plyr,missed_intercept);
	}
#else
	SetMain(steal_pass,plyr,missed_intercept);
#endif

	start_blend_anim2(plyr, DUMMY.top_anim, minTime+1);
	SetIkBlendSpeed(intercept,plyr,0x100/(minTime+1));
	plyr->ikBlendSpeed = 0x100/(minTime+1);

	plyr->top_routine = NULL;

	intercept(plyr);
}













