
#include "generic.h"
#include "lfptypes.h"
#include "define.h"
#include "ml.h"

#include "audio.h"
#include "playgfx.h"
#include "comment.h"

#include "ctrl.h"

#include "min.h"

/**/
/**/
/**/

global bool project_flag;
global SB   release_flag;
global SB	icon_flag;

bool	stealable_flag;

static bool alley_test(playert *plyr, playert *recvr);

// OTKLDMFS9V


#if defined(LOGGING)
	#define		PH_SIZE		50
	#define		RECORD_PASS1(p,s,b,c)		\
					PassHistory[PassIndex].lp=lp_ctr;		\
					PassHistory[PassIndex].tl=time_left;	\
					PassHistory[PassIndex].no=(p)->no;		\
					PassHistory[PassIndex].an=(p)->top_anim;	\
					PassHistory[PassIndex].maxspeed=(s);	\
					PassHistory[PassIndex].bounce=(b);		\
					PassHistory[PassIndex].caller=(#c);		\
					PassHistory[PassIndex].speed=-1;		\
					PassHistory[PassIndex].rise=0;

	#define		RECORD_PASS2(s,r,t)			\
					/*if (PassHistory[PassIndex].speed!=-1 || PassHistory[PassIndex].rise) {BRK;}*/	\
					PassHistory[PassIndex].time=(t);		\
					PassHistory[PassIndex].speed=(s);		\
					PassHistory[PassIndex].rise=(r);		\
					PrintPass(&PassHistory[PassIndex]);		\
					/*if ((r)*1024/(s)>1000 && (t)>5) BRK;*/	\
					if (++PassIndex==PH_SIZE) PassIndex=0;	\
					PassHistory[PassIndex].caller=0;

	typedef struct PassEvent
		{
		int		lp;						// lp_ctr when pass occurred
		int		tl;						// Time left
		int		time;					// Amount of time pass is in the air
		int		no;						// player making pass
		int		an;						// Animation
		int		maxspeed;				// Maximum allowed speed for pass
		int		speed;					// Selected planar speed
		int		rise;					// Selected vertical speed
		bool	bounce;					// Bounce flag
		//void	(*caller)(playert *);	// Routine
		char	*caller;
		} PassEvent;

	static void	PrintPass(PassEvent *e);

	PassEvent	PassHistory[PH_SIZE];
	int			PassIndex=0;
#else
	#define	RECORD_PASS1(p,s,b,c)
	#define	RECORD_PASS2(s,r,t)
#endif

//icon passing masks
int pass_mask[5]={
	CTRL_C_DOWN,
	CTRL_C_LEFT,
	CTRL_C_UP,
	CTRL_C_RIGHT,
	CTRL_FIRE_A
};


struct {
	int	xco;
	int	yco;
	int	zco;
	int	angle;
	int	head_tilt;
	int	head_twist;
	int	pitch;

	int	last_top_anim;
	int	last_top_frame;
	int	top_anim;
	int	top_frame;
	int	top_blend_ctr;

	int	last_leg_anim;
	int	last_leg_frame;
	int	leg_anim;
	int	leg_frame;
	int	leg_blend_ctr;

}recvr_vals[3*ONE_SEC];


struct
{
	void ((*rou)(playert *plyr));
	int	 top;
	int  rate;
	int  angle;
}pass_list[]={
//dribbling
 {chest_pass,  TOP_CP1, 0xc0, 0},
 {chest_pass, -TOP_CPR1, 0x100, 0x2000},
 {chest_pass,  TOP_DISHL1, 0x100, 0x4000},
 {chest_pass,  TOP_OSP1, 0x100, 0x6000},
 {chest_pass, -TOP_OSP1, 0x100, -0x8000},
 {chest_pass, -TOP_OSP1, 0x100, -0x6000},
 {chest_pass, -TOP_DISHL1, 0x100, -0x4000},
 {chest_pass,  TOP_CPR1, 0x100, -0x2000},
//standing
 {turn_chest_pass,  TOP_CP1, 0xc0, 0},
 {turn_chest_pass, -TOP_CPR1, 0x100, 0x2000},
 {turn_chest_pass, -TOP_CPR1, 0xc0, 0x2000},
 {chest_pass,  TOP_OSP1, 0x100, 0x6000},
 {chest_pass, -TOP_OSP1, 0x100, -0x8000},
 {chest_pass, -TOP_OSP1, 0x100, -0x6000},
 {turn_chest_pass,  TOP_CPR1, 0xc0, -0x2000},
 {turn_chest_pass,  TOP_CPR1, 0x100, -0x2000},

 //dribbling bounce passes	   0x10
 {bounce_pass,  TOP_BP1, 0x100, 0},
 {bounce_pass, -TOP_BPR1, 0x100, 0x2800},
 {bounce_pass, -TOP_DISHR1, 0x100, 0x4000},
 {bounce_pass, -TOP_BBBP1, 0x100, 0x6000},
 {bounce_pass, TOP_BBBP1, 0x100, -0x8000},
 {bounce_pass, TOP_BBBP1, 0x100, -0x6000},
 {bounce_pass,  TOP_DISHR1, 0x100, -0x4000},
 {bounce_pass,  TOP_BPR1, 0x100, -0x2800},
//standing bounce pass
 {bounce_pass,  TOP_BP1, 0x100, 0},
 {bounce_pass, -TOP_BPR1, 0x100, 0x2800},
 {turn_bounce_pass, -TOP_BPR1, 0x100, 0x2800},
 {bounce_pass, -TOP_BBBP1, 0x100, 0x6000},
 {bounce_pass, TOP_BBBP1, 0x100, -0x8000},
 {bounce_pass, TOP_BBBP1, 0x100, -0x6000},
 {turn_bounce_pass,  TOP_BPR1, 0x100, -0x2800},
 {bounce_pass,  TOP_BPR1, 0x100, -0x2800},

 //stood up passes		   0x20
 {turn_chest_pass, TOP_OP1, 0x100, 0},
 {turn_chest_pass, -TOP_OPR1, 0x100, 0x2800},
 {turn_chest_pass, -TOP_OPR1, 0x100, 0x2800},
 {turn_chest_pass, -TOP_OPR1, 0x100, 0x2800},
 {turn_chest_pass, TOP_OPR1, 0x100, -0x2800},
 {turn_chest_pass, TOP_OPR1, 0x100, -0x2800},
 {turn_chest_pass, TOP_OPR1, 0x100, -0x2800},
 {turn_chest_pass, TOP_OPR1, 0x100, -0x2800},
//long distance passes (running)
 {overhead_pass,  TOP_OHP0, 0x100, 0},
 {overhead_pass,  TOP_OHP0, 0x100, 0x0},
 {chest_pass,  -TOP_HOOKP1, 0x200, 0x4000},
 {chest_pass,  -TOP_HOOKP1, 0x200, 0x4000},
 {chest_pass,  TOP_HOOKP1, 0x200, -0x4000},
 {chest_pass,  TOP_HOOKP1, 0x200, -0x4000},
 {chest_pass,  TOP_HOOKP1, 0x200, -0x4000},
 {overhead_pass,  TOP_OHP0, 0x100, 0x0},


//soft pass (dribbling)	   0x30
 {turn_chest_pass,  TOP_SHOV1, 0x100, 0},
 {turn_chest_pass,  TOP_SHOV1, 0x100, 0},
 {turn_chest_pass,  TOP_SHOV1, 0x100, 0},
 {turn_chest_pass,  TOP_SHOV1, 0x100, 0},
 {turn_chest_pass,  TOP_SHOV1, 0x100, 0},
 {turn_chest_pass,  TOP_SHOV1, 0x100, 0},
 {turn_chest_pass,  TOP_SHOV1, 0x100, 0},
 {turn_chest_pass,  TOP_SHOV1, 0x100, 0},
 //soft pass standing
 {turn_chest_pass, TOP_OP1, 0x80, 0},
 {turn_chest_pass, -TOP_OPR1, 0x80, 0x2800},
 {turn_chest_pass, -TOP_OPR1, 0x80, 0x2800},
 {turn_chest_pass, -TOP_OPR1, 0x80, 0x2800},
 {turn_chest_pass, TOP_OPR1, 0x80, -0x2800},
 {turn_chest_pass, TOP_OPR1, 0x80, -0x2800},
 {turn_chest_pass, TOP_OPR1, 0x80, -0x2800},
 {turn_chest_pass, TOP_OPR1, 0x80, -0x2800},

 //long pass (standing)		0x40
 {base_pass,  TOP_BASEP1, 0x200, 0},
 {base_pass,  TOP_BASEP1, 0x200, 0},
 {base_pass,  TOP_BASEP1, 0x200, 0},
 {base_pass,  TOP_BASEP1, 0x200, 0},
 {base_pass,  TOP_BASEP1, 0x200, 0},
 {base_pass,  TOP_BASEP1, 0x200, 0},
 {base_pass,  TOP_BASEP1, 0x200, 0},
 {base_pass,  TOP_BASEP1, 0x200, 0},

//no look passes taken out

//dribbling
 {chest_pass,  TOP_CP1, 0xc0, 0},
 {chest_pass, -TOP_CPR1, 0x100, 0x2000},
 {chest_pass,  TOP_DISHL1, 0x100, 0x4000},
 {chest_pass,  TOP_DISHL1, 0x100, 0x4000},
 {chest_pass,  TOP_DISHL1, 0x100, 0x4000},
 {chest_pass, -TOP_DISHL1, 0x100, -0x4000},
 {chest_pass, -TOP_DISHL1, 0x100, -0x4000},
 {chest_pass,  TOP_CPR1, 0x100, -0x2000},
//standing
 {turn_chest_pass,  TOP_CP1, 0xc0, 0},
 {turn_chest_pass, -TOP_CPR1, 0x100, 0x2000},
 {turn_chest_pass, -TOP_CPR1, 0xc0, 0x2000},
 {turn_chest_pass, -TOP_CPR1, 0xc0, 0x2000},
 {turn_chest_pass,  TOP_CPR1, 0xc0, -0x2000},
 {turn_chest_pass,  TOP_CPR1, 0xc0, -0x2000},
 {turn_chest_pass,  TOP_CPR1, 0xc0, -0x2000},
 {turn_chest_pass,  TOP_CPR1, 0x100, -0x2000},

 //dribbling bounce passes	   0x10
 {bounce_pass,  TOP_BP1, 0x100, 0},
 {bounce_pass, -TOP_BPR1, 0x100, 0x2800},
 {bounce_pass, -TOP_DISHR1, 0x100, 0x4000},
 {bounce_pass, -TOP_DISHR1, 0xc0, 0x4000},
 {bounce_pass,  TOP_DISHR1, 0xc0, -0x4000},
 {bounce_pass,  TOP_DISHR1, 0xc0, -0x4000},
 {bounce_pass,  TOP_DISHR1, 0x100, -0x4000},
 {bounce_pass,  TOP_BPR1, 0x100, -0x2800},
//standing bounce pass
 {bounce_pass,  TOP_BP1, 0x100, 0},
 {bounce_pass, -TOP_BPR1, 0x100, 0x2800},
 {turn_bounce_pass, -TOP_BPR1, 0x100, 0x2800},
 {turn_bounce_pass, -TOP_BPR1, 0xc0, 0x2800},
 {turn_bounce_pass, -TOP_BPR1, 0xc0, 0x2800},
 {turn_bounce_pass,  TOP_BPR1, 0xc0, -0x2800},
 {turn_bounce_pass,  TOP_BPR1, 0x100, -0x2800},
 {bounce_pass,  TOP_BPR1, 0x100, -0x2800},

};


void hands_up(playert *plyr, int t_left)
{
int time;

	//standing receivers bring up hands with half sec to go
	//running receivers leave it to 1/4 sec
	time = (plyr->last_speed) ? HALF_SEC/2:HALF_SEC;

	if (t_left <= time)
	{
		//for standing guys, take care of legs

		switch(abs(plyr->next_anim))
		{

			case TOP_CATCH_FRONT:
			if ((plyr->xvel | plyr->yvel) == 0)		start_blend_leg_anim(plyr, LEG_RDY);
			break;

			case TOP_CATCH_OH:
			if ((plyr->xvel | plyr->yvel) == 0)		start_blend_leg_anim(plyr, LEG_STAND);
			break;

			case TOP_CATCH_HP1:
			case TOP_CATCH_LP1:
			plyr->look_at_ball_ctr = t_left;
			break;
		}

		start_blend_anim(plyr, plyr->next_anim);
		plyr->top_routine = NULL;					//stop top doing something else
	}
}


/* *************************************************************************/
/* start_post_pass()*/
/* *************************************************************************/
/* decide which type of pass to make once PASS is pressed.*/
/* *************************************************************************/
/* Inputs   - 	player data ptr*/
/* outputs  -*/
/* *************************************************************************/

void start_post_pass(playert *plyr)
{
playert *recvr;
int pass_angle;
int pass_index;
int pass_dist;
int p_x, p_y, r_x, r_y;
int time;

	CallChainP(start_post_pass);

	timeout_called = 0;
	alley_flag     = 0;

	//mask off pass buttons
	jmask(CTRL_PASS+CTRL_POST_PASS);

	get_post_recvr();

	recvr = &player[int_recvr];
	if (recvr->zco)		return;

	pass_flag = TRUE;

	if (alley_test(plyr, recvr))	return;


	pass_angle = LFPAtn(recvr->proj_x-plyr->proj_x, recvr->proj_y-plyr->proj_y);
	pass_index = ((pass_angle-plyr->angle+0x1000)>>13) & 7;
	pass_dist  = MANHATTAN(recvr->proj_x-plyr->proj_x, recvr->proj_y-plyr->proj_y);

	//printf("\npass %x plyr %x index %d\n", pass_angle, plyr->angle, pass_index);

	//standing passes
	if (((plyr->xvel | plyr->yvel) == 0))
	{
		//test for standing up pass
		switch (abs(plyr->top_anim))
		{
		case TOP_OVER_BALL:
		case TOP_PVT2F:
		case TOP_PVT2B:

			pass_index += 0x20;
			if ((pass_dist < 0x400000) && (in_play_flag))
			{
				//shovel pass
				pass_index = (pass_index & 7) + 0x38;
			}
			goto got_pass;
			break;

		default:

			if (pass_dist > 0x1000000)
			{
				//overhead
				pass_index += 0x40;
				goto got_pass;
			}
			else if ((pass_dist < 0x400000) && (in_play_flag))
			{
				//shovel pass
				pass_index = (pass_index & 7) + 0x30;
				goto got_pass;
			}
			pass_index += 8;

			break;
		}
	}
	//test for running over head pass
	else if (pass_dist > 0xc00000)
	{
		pass_index += 40;
		goto got_pass;
	}

	//test for bounce pass
	if (recvr->basket_dist < 0x600000)
	{
		if ((pass_dist > 0x300000) && (pass_dist < 0x600000))
		{
			if (pass_list[pass_index+16].rou)
			{
				pass_index += 16;
			}
		}
	}

got_pass:
	plyr->angle2 = pass_angle - (pass_list[pass_index].angle);

	plyr->main_routine    = pass_list[pass_index].rou;
	start_blend_anim(plyr, pass_list[pass_index].top);
	plyr->top_rate    = pass_list[pass_index].rate;
//	plyr->top_blend_speed = pass_list[pass_index].rate/4;
	plyr->top_routine = NULL;
}










/* *************************************************************************/
/* start_pass()*/
/* *************************************************************************/
/* decide which type of pass to make once PASS is pressed.*/
/* *************************************************************************/
/* Inputs   - 	player data ptr*/
/* outputs  -*/
/* *************************************************************************/

void start_pass(playert *plyr)
{
playert *recvr;
int pass_angle;
int pass_index;
int pass_dist;
int p_x, p_y, r_x, r_y;
int time;

	CallChainP(start_pass);

	timeout_called = 0;
	alley_flag     = 0;
	SetShootStage(start_pass,0);

	recvr = &player[int_recvr];
	if (recvr->flags & FALLING)	return;

	if (recvr->no==bhp->no)
		return;

	//stop changing receiver mid-pass
	pass_flag = TRUE;

	//mask off pass button
	jmask(CTRL_PASS+CTRL_POST_PASS);

	if (plyr->control == 0)
	{
		if (alley_test(plyr, recvr))	return;
	}


	if (int_recvr<0)
		return;

	//project recvr forward
	time = (recvr->ball_dist/CH_PASS_SPD) + (ONE_SEC/3);
	r_x  = recvr->proj_x;
	r_y  = recvr->proj_y;
	p_x  = plyr->proj_x;
	p_y  = plyr->proj_y;

	pass_angle = LFPAtn(r_x - p_x, r_y - p_y);
	pass_index = ((pass_angle-plyr->angle+0x1000)>>13) & 7;
	pass_dist  = MANHATTAN(r_x - p_x, r_y - p_y);


	//standing passes
	if (((plyr->xvel | plyr->yvel) == 0))
	{
		//test for standing up pass
		switch (abs(plyr->top_anim))
		{
		case TOP_OVER_BALL:
		case TOP_PVT2F:
		case TOP_PVT2B:

			pass_index += 0x20;
			if ((pass_dist < 0x400000) && (in_play_flag))
			{
				//shovel pass
				pass_index = (pass_index & 7) + 0x38;
			}
			goto got_pass;
			break;

		default:

			if (pass_dist > 0x1000000)
			{
				//base ball pass
				pass_index += 0x40;
				goto got_pass;
			}
			else if ((pass_dist < 0x400000) && (in_play_flag))
			{
				//shovel pass
				pass_index = (pass_index & 7) + 0x30;
				goto got_pass;
			}
			pass_index += 8;

			break;
		}
	}
	else
	{
		//test for running over head pass
		if (pass_dist > 0xc00000)
		{
			pass_index += 40;
			goto got_pass;
		}
		else if (pass_dist < 0x200000)
		{
			//shovel pass
//			pass_index = (pass_index & 7) + 0x30;
//			goto got_pass;
		}

	}

	//test for bounce pass
	if (recvr->basket_dist < 0x600000)
	{
		if ((pass_dist > 0x300000) && (pass_dist < 0x600000))
		{
			if (pass_list[pass_index+16].rou)
			{
				pass_index += 16;
			}
		}
	}

got_pass:
	if (abs(pass_list[pass_index].angle) > 0x5000)
	{
		if ((bhp->plyrROM->ub___pAttrPass < 70) || (pass_dist > 0x400000))
		{
			pass_index = pass_index+0x48;
		}
	}


	plyr->angle2 = pass_angle - (pass_list[pass_index].angle);
	plyr->main_routine    = pass_list[pass_index].rou;
	start_blend_anim(plyr, pass_list[pass_index].top);
	plyr->top_rate       = pass_list[pass_index].rate;
//	plyr->top_blend_speed = pass_list[pass_index].rate/4;
	plyr->top_routine     = NULL;
}



bool alley_test(playert *plyr, playert *recvr)
{
SW  a_diff;
int receiver_dist;
int ball_y;

	if (recvr->basket_dist > 0x380000)			return FALSE;
	if (recvr->basket_dist < 0x0a0000)			return FALSE;
	if (plyr->basket_dist  > 0xa00000)			return FALSE;

	//is paser facing recvr
	a_diff = plyr->angle - recvr->ball_angle;
	if (abs(a_diff) < 0x5000)					return FALSE;

	a_diff = plyr->basket_angle - recvr->basket_angle;
	if (abs(a_diff) < 0x2000)					return FALSE;

	if (blocked_basket_test(recvr) != 0xe)		return FALSE;

	if (!in_play_flag)							return FALSE;

//	if (recvr->basket_dist < (2<<20))
//	{
		//tip in dunk
		a_diff = plyr->basket_angle - plyr->angle;
		receiver_dist = 1000>>4;
//	}


	alley_flag = TRUE;

//	recvr->target_x = -LFPCos(recvr->basket_angle) * receiver_dist;
//	recvr->target_y = current_basket_y - (LFPSin(recvr->basket_angle) * receiver_dist);

	SetMain(alley_test,recvr,receive_alley1);
	recvr->fouler=NULL;
	last_blocker=-1;
	recvr->top_routine  = top_deflt;

	SetMain(alley_test,plyr,alley_pass);
	Comment( COMMENT_ALLEY_OOP, plyr, 0 );

	if (ball.yco < (bhp->scale*(5<<10)))
	{
		if (clear_pass(recvr) == 0xe)
		{
			start_anim2(plyr, TOP_SHOV1, 8*TIME_FACTOR);
		}
		else
		{
			SetMain(alley_test,plyr,alley_pass0);
			start_anim2(plyr, TOP_OHP0, 7*TIME_FACTOR);
		}
	}
	else
	{
		start_anim(plyr, TOP_OP1);
		SetMain(alley_test,plyr,alley_pass);
	}

	plyr->top_routine = NULL;
	return TRUE;
}



//bring ball to overhead position, then go into regular pass
void alley_pass0(playert *plyr)
{
	CallChainP(alley_pass0);

	current_ctrlr->force   = 0x10;
	current_ctrlr->d_angle = plyr->basket_angle;
	current_ctrlr->ctrlr   &= ~CTRL_SHUFFLE;

//	if (current_ctrlr->force)		current_ctrlr->d_angle = plyr->angle2;

	if (end_animation_test(plyr))
	{
		//now ball is overhead which pass did I want
		plyr->angle2 = player[int_recvr].ball_angle-0x8000;

		start_anim(plyr, TOP_OP1);
		SetMain(alley_pass0,plyr,alley_pass);
	}
}



void alley_pass(playert *plyr)
{
int time;
int target_x, target_y;
int r_angle;
int x_diff, y_diff, z_diff;

	CallChainP(alley_pass);

	current_ctrlr->d_angle = plyr->basket_angle;
	current_ctrlr->force   = 0x10;

	if (end_animation_test(plyr))
	{
		if (!project_flag)
		{
			pass_flag = FALSE;
			SetPossession(alley_pass,FALSE);

			r_angle  = player[int_recvr].basket_angle;
			target_x = -LFPCos(r_angle) * (550>>4); //(768>>4);
			target_y = current_basket_y - (LFPSin(r_angle) * (550>>4)); //(768>>4));

			ball.target_x = target_x;
			ball.target_y = target_y;

			time	  = plyr->basket_dist/CH_PASS_SPD;
			if (time==0)	time=1;

			if (time < 20)	time = 20;

			x_diff    = target_x - ball.xco;
			ball.xvel = x_diff/time;

			y_diff    = target_y - ball.yco;
			ball.yvel = y_diff/time;

			z_diff    = ALLEY_Z - ball.zco;
			ball.zvel = (z_diff/time) + ( (time-1)*(LITTLE_G/2) );

			SetMain(alley_pass,&ball,pass_ball_move);
			ball.ctr2		  = time;

			SetLastHandler(alley_pass,plyr->no);
			assister = plyr->no;

			SetMain(alley_pass,plyr,end_chest_pass);
			start_next_anim(plyr);
		}
	}
}










/* *************************************************************************/
/* receive pass(playert *plyr)*/
/* *************************************************************************/
/* stop running, turn and face the ball
/* *************************************************************************/
/* Inputs   - 	ptr to plyr data*/
/* *************************************************************************/

void receive_pass(playert *plyr)
{

	CallChainP(receive_pass);

	if ((possession_flag) & (!project_flag))
	{
		SetMain(receive_pass,plyr,deflt);
		if (!plyr->leg_routine)
		{
			plyr->leg_routine = leg_deflt;
		}
		return;
	}

	current_ctrlr->ctrlr  =
	current_ctrlr->mctrlr = CTRL_SHUFFLE;

	current_ctrlr->force = 0;
	return;





	if (plyr->last_speed)
	{
		//stop
		current_ctrlr->d_angle = (SW) plyr->angle+0x8000;
		current_ctrlr->force   = 0;
	}
	else
	{
		//face the ball
		if (plyr->ball_angle != plyr->angle)
		{
			current_ctrlr->d_angle = (SW) plyr->ball_angle;
			current_ctrlr->force   = 0x10;
		}
		else
		{
			current_ctrlr->force   = 0;
		}
	}
}


void save_pass_vals(playert *plyr, int time)
{
	recvr_vals[time].xco			= plyr->xco;
	recvr_vals[time].yco			= plyr->yco;
	recvr_vals[time].zco			= plyr->zco;
	recvr_vals[time].angle			= plyr->angle;
	recvr_vals[time].pitch			= plyr->pitch;

	recvr_vals[time].last_top_anim	= plyr->last_top_anim;
	recvr_vals[time].last_top_frame	= plyr->last_top_frame;
	recvr_vals[time].top_anim		= plyr->top_anim;
	recvr_vals[time].top_frame		= plyr->top_frame;
	recvr_vals[time].top_blend_ctr	= plyr->top_blend_ctr;

	recvr_vals[time].last_leg_anim	= plyr->last_leg_anim;
	recvr_vals[time].last_leg_frame	= plyr->last_leg_frame;
	recvr_vals[time].leg_anim		= plyr->leg_anim;
	recvr_vals[time].leg_frame		= plyr->leg_frame;
	recvr_vals[time].leg_blend_ctr	= plyr->leg_blend_ctr;
}



void playback_pass_vals(playert *plyr)
{
int time;

	CallChainP(playback_pass_vals);

	if (((possession_flag) & (!project_flag)) || (!in_play_flag) || loose_flag)
	{
		SetMain(playback_pass_vals,plyr,deflt);
		plyr->leg_routine  = leg_deflt;
		plyr->top_routine  = top_deflt;
		release_flag=0;
		return;
	}

	time = ball.ctr2-1;
	if (time<0)
	{
		BRK;
		time=0;
	}

//	if (abs(recvr_vals[time].xco-plyr->xco) > 0x100000)		BRK;
//	if (abs(recvr_vals[time].yco-plyr->yco) > 0x100000)		BRK;

	plyr->xco            = recvr_vals[time].xco;
	plyr->yco            = recvr_vals[time].yco;
	plyr->zco            = recvr_vals[time].zco;
	plyr->angle          = recvr_vals[time].angle;
	plyr->pitch          = recvr_vals[time].pitch;

	plyr->last_top_anim  = recvr_vals[time].last_top_anim;
	plyr->last_top_frame = recvr_vals[time].last_top_frame;
	plyr->top_anim       = recvr_vals[time].top_anim;
	plyr->top_frame      = recvr_vals[time].top_frame;
	plyr->top_blend_ctr  = recvr_vals[time].top_blend_ctr;

	plyr->last_leg_anim  = recvr_vals[time].last_leg_anim;
	plyr->last_leg_frame = recvr_vals[time].last_leg_frame;
	plyr->leg_anim       = recvr_vals[time].leg_anim;
	plyr->leg_frame      = recvr_vals[time].leg_frame;
	plyr->leg_blend_ctr  = recvr_vals[time].leg_blend_ctr;
}


#define	SG(global)	__##global = global
#define	LG(global)	global = __##global

/* *************************************************************************/
/* project(plyr, time)*/
/* *************************************************************************/
/* start pass to receiver*/
/* *************************************************************************/
/* Inputs   - 	ptr to plyr data*/
/* Inputs   - 	no of AI cycles*/
/* *************************************************************************/

void project (playert *plyr, int time, bool saveFlag)
{
int x_diff;
int y_diff;

	// Global flags that should remain unaltered
	int		__dunk_flag;
	int		__rebound_flag;
	int		__possession_flag;
	bool	__picked_up_flag;
	int		__loose_flag;
	teamt*	__cur_team;

	CallChainP(project);

	if (project_flag)
	{
		BRK;
		return;
	}

	// Save out global variables
	SG(dunk_flag);
	SG(rebound_flag);
	SG(possession_flag);
	SG(picked_up_flag);
	SG(loose_flag);
	SG(cur_team);

	project_flag = TRUE;

    memcpy( (void *)&DUMMY, (void *)plyr, sizeof(playert));
	ai_team[2]=*cur_team;
	cur_team = &ai_team[2];

    do 
	{
		if (plyr->control)
		{
			memcpy(ctrlrs, ctrlrs+plyr->control, sizeof(ctrlrs[0]));
			//no shots or special dribbles or passes
			ctrlrs[0].mctrlr &= ~(CTRL_FIRE_A+CTRL_FIRE_B + CTRL_C_DOWN);
			ctrlrs[0].raw    &= ~(CTRL_FIRE_A+CTRL_FIRE_B + CTRL_C_DOWN);
			ctrlrs[0].tap    &= ~(CTRL_FIRE_A+CTRL_FIRE_B + CTRL_C_DOWN);
		}
		else
		{
			ctrlrs[0].mctrlr  = 0;
			ctrlrs[0].ctrlr   = 0;
			ctrlrs[0].force   = 0;
			ctrlrs[0].d_angle = 0;
		}
 		current_ctrlr = ctrlrs;

		pivot_flag2 = FALSE;	//pivot forward by default;

		check_routines(&DUMMY);

		/* move */
		if (DUMMY.main_routine)	DUMMY.main_routine(&DUMMY);

		DUMMY.force   = current_ctrlr->force;  // keep copies of the controller settings
		DUMMY.d_angle = current_ctrlr->d_angle;

		/* move legs */
		if (DUMMY.leg_routine)	DUMMY.leg_routine(&DUMMY);
		/* move top */
		if (DUMMY.top_routine)	DUMMY.top_routine(&DUMMY);

		animate(&DUMMY);

		x_diff = -DUMMY.xco;
		y_diff = current_basket_y - DUMMY.yco;
		DUMMY.basket_dist  = MANHATTAN(x_diff, y_diff);
		DUMMY.basket_angle = LFPAtn(x_diff, y_diff);

		x_diff = ball.xco - DUMMY.xco;
		y_diff = ball.yco - DUMMY.yco;
		DUMMY.ball_dist  = MANHATTAN(x_diff, y_diff);
		DUMMY.ball_angle = LFPAtn(x_diff, y_diff);

		time--;

//		if (DUMMY.no == 4)		printf("t %d, dx %x, dy %x\n", time, DUMMY.xco, DUMMY.yco);

		if (saveFlag)
		{
			hands_up(&DUMMY, time);
			save_pass_vals(&DUMMY, time);
		}

		check_boards(&DUMMY);
	}
	while (time>0);

	project_flag = FALSE;

	// Restore globals
	LG(dunk_flag);
	LG(rebound_flag);
	LG(possession_flag);
	LG(picked_up_flag);
	LG(loose_flag);
	LG(cur_team);
}





static SW running_catch_anims[8]=
{
	TOP_CATCH_LEAD,
	TOP_CATCH_RIGHT,
	TOP_CATCH_BACK,
	TOP_CATCH_BACK,

	-TOP_CATCH_BACK,
	-TOP_CATCH_BACK,
	-TOP_CATCH_RIGHT,
	-TOP_CATCH_LEAD,
};


void release_tipoff(playert *plyr, int top_speed, bool asdf)
{
	RECORD_PASS1(plyr,top_speed,asdf,release_tipoff)
	release_pass(plyr,top_speed,asdf);
}



/* *************************************************************************/
/* release_pass()*/
/* *************************************************************************/
/* start pass to receiver*/
/* *************************************************************************/
/* Inputs   - 	ptr to plyr data*/
/* Inputs   - 	ptr to receiver data*/
/*				top speed of ball*/
/* Output   -   number of loops ball will take to reach receiver*/
/* *************************************************************************/

void release_pass(playert *plyr, int top_speed, bool asdf)
{
int	x_diff;
int	y_diff;
int	z_diff;
int	time, last_time;
int ball_angle;

int intercepter, z;
bool iflag;
int i;

playert *recvr;
static playert or;

#if defined(LOGGING) && defined(DEBUG)
	if (PassHistory[PassIndex].lp!=lp_ctr)
		BRK;
#endif

	CallChainP(release_pass);

	//stop steal routine projection
	if (project_flag)	   return;

	bounce_flag=asdf;

	pick_ctr = 0;

	stealable_flag=in_play_flag? TRUE : FALSE;
	
	iflag = FALSE;
	scored_flag  = 0;


	if (!in_play_flag)
	{
		in_play_flag = TRUE;
		stealable_flag=FALSE;

		iflag = (five_sec_clock>=2.5*ONE_SEC);


		//play jingle if inbounded in home team's half
		if ((plyr->no<5) && (ball.yco < 0))
		{
			if (lp_ctr>jingle_time)
			{
				int j;

				jingle_time = lp_ctr+ONE_MIN;
//old				j = RANDOM(8) + AUDIO_CROWD_J11;
//old				AudioPlayCrowdSfx(j);
			}
		}
		else if ((plyr->no>4) && (ball.yco>0))
		{
			if (lp_ctr>defense_time)
			{
				defense_time = lp_ctr+ONE_MIN;
				defense_on   = TRUE;
//old				AudioPlayCrowdSfx(AUDIO_CROWD_DEFENSE);
			}
		}
	}





	release_flag = plyr->control;

	ball_place(plyr);

	SetPossession(release_pass,FALSE);
	pass_flag		= FALSE;

	recvr			= player+int_recvr;
	time			= recvr->ball_dist/top_speed;
	last_time		= time+1;
	i = 0;

	or=*recvr;

	if (!project_flag && ArcadeMode && MOM_MAX(plyr->team))
		BallTrail=TRUE;

	do
	{
		last_time = time;
		x_diff = recvr->xco - ball.xco + time*recvr->xvel;
		y_diff = recvr->yco - ball.yco + time*recvr->yvel;

		time   = pythag(x_diff, y_diff)/top_speed;

		break;

		i++;
		if (i==4)	break;
	}
	while (time != last_time);

	if (time > (2*ONE_SEC-1))	time = 2*ONE_SEC-1;

	if (time < 5)		time = 5;
	if (bounce_flag)	time += ONE_SEC/4;

	current_ctrlr = &ctrlrs[5];				//use separate controller

	current_ctrlr->ctrlr  = 0;
	current_ctrlr->mctrlr = 0;
	project(recvr, time, FALSE);
	time=last_time = pythag(DUMMY.xco-ball.xco, DUMMY.yco-ball.yco)/top_speed;

	//was receiver running and has stopped not facing ball ?
	if ((DUMMY.last_speed == 0) && (DUMMY.angle != DUMMY.ball_angle))
	{
		//re project using receive pass as main routine
		SetMain(release_pass,recvr,receive_pass);
		project(recvr, time, FALSE);
	}
	current_ctrlr = ctrlrs+plyr->control;	//restore original controller


	if (DUMMY.last_speed)
	{
		ball_angle =  DUMMY.angle;
		ball_angle -= LFPAtn(ball.xco - DUMMY.xco, ball.yco - DUMMY.yco);
		ball_angle =  (ball_angle >> 13) & 7;

		recvr->next_anim = running_catch_anims[ball_angle];

		//running backwards use front catch not lead
		if (recvr->top_anim == TOP_BACK)		recvr->next_anim = TOP_CATCH_FRONT;

		DUMMY.top_anim = recvr->next_anim;
	}
	else
	{
		if ((recvr->last_speed) || (abs(plyr->top_anim) == TOP_SHOV1) || ((DUMMY.ball_dist < 0x300000) && (ball.zco < 0x200000)))
		{
			recvr->next_anim = TOP_CATCH_FRONT;
			DUMMY.leg_anim   = LEG_RDY;
		}
		else
		{
			switch (recvr->top_anim)
			{
			case TOP_CATCH_HP1:
			case -TOP_CATCH_HP1:
			case TOP_CATCH_LP1:
			case -TOP_CATCH_LP1:
				recvr->next_anim = recvr->top_anim;
				break;

			default:
				if (bounce_flag)
				{
					recvr->next_anim = TOP_CATCH_FRONT;
					DUMMY.leg_anim   = LEG_RDY;
				}
				else
				{
					recvr->next_anim = TOP_CATCH_OH;
					DUMMY.leg_anim   = LEG_STAND;
				}
				break;
			}

		}
	}

		get_pass_ball_vels(recvr, time, bounce_flag);
		RECORD_PASS2(MANHATTAN(ball.xvel,ball.yvel),ball.zvel,time);

	// First run of pass comments
	Comment( COMMENT_PASS, plyr, 0 );
	assister=plyr->no;
	SetLastHandler(release_pass,plyr->no);

	//static interception code

	//don't attempt to steal when pass is going out of bounds
	if ((!iflag) && (player_inbounds_check(&DUMMY) == 0))
	{
		intercepter = i_check_pass(&time, &z);
	}
	else
	{
		intercepter = -1;
	}


	if (intercepter>=0)
	{
		//make intercepter the receiver
		recvr = player+intercepter;
		assister=-1;

		current_ctrlr->ctrlr  = 0;
		current_ctrlr->mctrlr = 0;

		SetMain(release_pass,recvr,intercept_pass);

		if ((recvr->last_speed == 0) || (recvr->shuffle))
		{
			if (z > (0x800*plyr->scale))	recvr->next_anim = TOP_CATCH_OH;
			else							recvr->next_anim = TOP_CATCH_FRONT;
		}
		else
		{
			if (z > (0x800*plyr->scale))	recvr->next_anim = TOP_CATCH_OH2;
			else							recvr->next_anim = TOP_CATCH_FRONT;
		}

		get_pass_ball_vels(recvr, time, FALSE);
		RECORD_PASS2(MANHATTAN(ball.xvel,ball.yvel),ball.zvel,time);
	}

	memcpy( (void *)&RECVR, (void *)&DUMMY, sizeof(playert));

	if (recvr->flags&FALLING)
	{
		*recvr=or;
	}
	else
	{
		SetMain(release_pass,recvr,playback_pass_vals);
		recvr->top_routine  =
		recvr->leg_routine  = NULL;
	}

	return;
}




void get_pass_ball_vels(playert *recvr, int time, bool bounce_flag)
{
int	x_diff;
int	y_diff;
int	z_diff;

	if (time==0)	time=1;

	project(recvr, time, TRUE);
	DUMMY.top_blend_ctr = 0;
	PlayGfxEvalBall(&DUMMY, &x_diff, &z_diff, &y_diff);

	x_diff -= ball.xco;
	y_diff -= ball.yco;

	ball.angle = LFPAtn(x_diff, y_diff);
	ball.ctr2  = time;

	if (!bounce_flag)
	{
		z_diff -= ball.zco;

		ball.xvel = x_diff/time;
		ball.yvel = y_diff/time;
		ball.zvel = (z_diff/time) + ( (time-1)*(LITTLE_G/2) );

		ball.target_y = 0;	//not a bounce pass
	}
	else
	{
		float time_frac, dist_frac;
		int   t1;

		//what portion of time spent before bounce
		time_frac = (float)(ball.zco)/(float)(ball.zco + z_diff);

		//adjust time_frac for integer time values  .9 to compensate for bounce vel lower
		t1 = (time * time_frac * .9);
		if (t1 == 0) t1 =1;
		time_frac = (float)(t1)/(float)(time);

		//what portion of distance covered before bounce
		dist_frac = time_frac/(time_frac + (0.75*(1-time_frac)));

		x_diff = x_diff * dist_frac;
		y_diff = y_diff * dist_frac;

		ball.zvel = -(ball.zco+40)/t1 + ((t1-1)*(LITTLE_G/2));
		ball.xvel = x_diff/t1;
		ball.yvel = y_diff/t1;

		ball.target_y = z_diff;
	}

	SetMain(get_pass_ball_vels,&ball,pass_ball_move);

	project_ball(time);
}










/* *************************************************************************/
/* void hp_catch_wait(playert *plyr)
/* *************************************************************************/
/* wait until ball is caught
/* *************************************************************************/
/* Inputs   - 	ptr to plyr data*/
/* outputs  -*/
/* *************************************************************************/


void hp_catch_wait(playert *plyr)
{
	CallChainP(hp_catch_wait);

	if (blend_to_end(plyr, TOP_STAND_BALL, LEG_RDY, 4))
	{
		SetMain(hp_catch_wait,plyr,stand_with_ball);
		plyr->leg_routine  = leg_deflt;
	}
}






global bool start_jump_pass(playert *plyr)
{
SW pass_angle;
SW diff;
int t;

	CallChainP(start_jump_pass);

	if (player[int_recvr].flags & FALLING)	return FALSE;

	if (int_recvr == plyr->no)				return FALSE;

	t = time_till_land(plyr);

	plyr->flags&=~SHOOT_MASK;

	if (t>5)
	{
		t = 5;
		jmask(CTRL_PASS+CTRL_POST_PASS);
		pass_flag = TRUE;

		pass_angle = player[int_recvr].ball_angle - 0x8000;

		diff = pass_angle - plyr->angle;

		if (diff < 0)
		{
			start_blend_anim2(plyr, TOP_JPL1, t);
			pass_angle -= 0x2000;
		}
		else
		{
			start_blend_anim2(plyr, -TOP_JPL1, t);
			pass_angle += 0x2000;
		}

		diff = pass_angle-plyr->angle;
		plyr->angle_vel = diff/t;

		SetMain(start_jump_pass,plyr,jump_pass);
		return TRUE;
	}
	return FALSE;
}






global void jump_pass(playert *plyr)
{
int zco;

	CallChainP(jump_pass);

	collision (plyr, plyr->xvel, plyr->yvel, 0);

	zco		= plyr->zco;
	zco		+=plyr->zvel;
    plyr->zvel  -=LITTLE_G;

	if (zco < 0)	zco	= 0;
	plyr->zco = zco;

	plyr->angle += plyr->angle_vel;

	if (end_animation_test(plyr))
	{
		RECORD_PASS1(plyr,CH_PASS_SPD,FALSE,jump_pass)
		release_pass(plyr, CH_PASS_SPD, FALSE);
		start_next_anim2(plyr, time_till_land(plyr));
		SetMain(jump_pass,plyr,jump_pass2);
	}
}


global void jump_pass2(playert *plyr)
{
int zco;

	CallChainP(jump_pass2);

	collision (plyr, plyr->xvel, plyr->yvel, 0);

	zco		= plyr->zco;
	zco		+=plyr->zvel;
    plyr->zvel  -=LITTLE_G;

	if (zco < 0)	zco	= 0;
	plyr->zco = zco;

	if (end_animation_test(plyr))
	{
		start_next_anim(plyr);
		SetMain(jump_pass2,plyr,jump_pass3);
	}
}




global void jump_pass3(playert *plyr)
{
	CallChainP(jump_pass3);

	if (end_animation_test(plyr))
	{
		start_anim(plyr, TOP_RDY);
		start_leg_anim(plyr, LEG_RDY);
		SetMain(jump_pass3,plyr,deflt);
		plyr->leg_routine  = leg_deflt;
		plyr->top_routine  = top_deflt;
	}
}


static int angle_scores[32]={
	0x28,0x20,0x18,0x14,		   // 45 deg
	0x10,0xe,0xc,0xa,		   // 90
	0x0,0x0,0x0,0x0,		   // 135
	0x0,0x0,0x0,0x0,		   // 180
	0x0,0x0,0x0,0x0,		   // 225
	0x0,0x0,0x0,0x0,		   // 270
	0x0,0xa,0xc,0xe,		   // 315
	0x10,0x14,0x18,0x20		   // 360
};


static int dist_scores[48]={
	0x00,0x10,0x18,0x20,
	0x1c,0x1a,0x18,0x16,
	0x15,0x14,0x13,0x12,
	0x11,0x10,0x0f,0x0e,

	0x0d,0x0c,0x0b,0x0a,
	0x09,0x08,0x07,0x06,
	0x06,0x06,0x06,0x06,
	0x06,0x06,0x06,0x06,

	0x06,0x06,0x06,0x06,
	0x06,0x06,0x06,0x06,
	0x06,0x06,0x06,0x06,
	0x06,0x06,0x06,0x06,
};



static int bdist_scores[48]={
	0x30,0x2f,0x2e,0x2d,
	0x2c,0x2b,0x2a,0x29,
	0x28,0x27,0x26,0x25,
	0x24,0x23,0x22,0x21,

	0x20,0x1f,0x1e,0x1d,
	0x1c,0x1b,0x1a,0x19,
	0x18,0x17,0x16,0x15,
	0x14,0x13,0x12,0x11,

	0x10,0x0f,0x0e,0x0d,
	0x0c,0x0b,0x0a,0x09,
	0x08,0x07,0x06,0x05,
	0x04,0x03,0x02,0x01,
};






void get_post_recvr(void)
{
SW pass_angle;
UW angle_diff;
int p_no;
int	base;
int score, best_score;
int best_so_far;
playert *plyr2;

	if ((bhp->control == 0) || (!possession_flag) || (pass_flag))	return;

	base	= ((bhp->no < 5) ? 0:5);

	//look for lowest possible score function
	best_so_far = -1;
	plyr2	= &player[base];
	best_score = 0;

	for (p_no=0; p_no<5; p_no++)
	{
		if (plyr2 != bhp)
		{
			if (player_inbounds_check(plyr2) == 0)
			{
				angle_diff = (plyr2->ball_angle - bhp->angle - 0x7c00);

				plyr2->score =
				score      = angle_scores[angle_diff>>11]
							 +dist_scores[plyr2->ball_dist >> 20]
							 + 0x220 - (plyr2->basket_dist>>16);

				if (plyr2->flags & FALLING)	score-=0x10000;


				if (score > best_score)
				{
					best_so_far	= p_no;
					best_score  = score;
				}
			}
		}
		plyr2++;
	}

	if (best_so_far==-1)	best_so_far = 0;

	int_recvr = best_so_far+base;

	plyr2 = player+int_recvr;
	if (plyr2->basket_dist > 0x400000)
	{
		if (blocked_basket_test(plyr2) == 0xe)
		{
			if (plyr2->main_routine == deflt)
			{
				if (in_play_flag)	new_main(plyr2, cut_to_basket);
			}
		}
	}
}




void cut_to_basket(playert *plyr)
{
	CallChainP(cut_to_basket);

	if (plyr->basket_dist>0x200000)
	{
		current_ctrlr->force   = 0xf0;
		current_ctrlr->d_angle = plyr->basket_angle;
	}
	else
	{
		new_main(plyr, deflt);
		new_top(plyr, top_deflt);
	}

}



void cut_to_basket2(playert *plyr)
{
	int	an;

	CallChainP(cut_to_basket2);

	// Handle ballhandler stuff here
	if (plyr->no==bhp->no)
	{
		if (current_ctrlr->mctrlr & CTRL_SHOOT)
		{
			// Do a running dunk if valid
			if ((an=dunk_test(plyr)))
			{
				dunk_start(plyr,an);
				return;
			}

			// Do a standing dunk if valid
			if (sdunk_test(plyr))
				return;

			if (finger_roll_test(plyr))
				return;

			// Do a standard floor shot if no dunk available
			shoot(plyr,select_shot(plyr));
			return;
		}

		/*  make pass */
		if (	(CTL_DOWN(current_ctrlr,CTRL_PASS) && icon_flag==ICON_OFF) ||
				CTL_TAP(current_ctrlr,CTRL_PASS) )
		{
			start_pass(plyr);
			return;
		}

		if ((current_ctrlr->mctrlr & CTRL_POST_PASS) && (icon_flag == ICON_OFF))
		{
			start_post_pass(plyr);
			return;
		}

		if (player[plyr->col_flags].team!=plyr->team)
			goto end_cut;
	}

	// Handle general stuff here
	if (plyr->basket_dist>0x200000)
	{
		current_ctrlr->force   = 0xf0;
		current_ctrlr->d_angle = plyr->basket_angle;
	}
	else
	{
end_cut:
		SetMain(cut_to_basket2,plyr,dribble);
		new_top(plyr,dribble_animate);
	}

}



/* *************************************************************************/
/* get_recvr()*/
/* *************************************************************************/
/* decide who I would be passing to*/
/* *************************************************************************/
/* Inputs   - 	ptr to ball handler data*/
/* outputs  -*/
/* *************************************************************************/

void get_recvr()
{
SW pass_angle;
UW angle_diff;
int p_no;
int	base;
int score, best_score;
int best_so_far;
playert *plyr2;
ctrlrT	*ctrl;

	if ((bhp->control == 0) || (!possession_flag) || (pass_flag))	return;

	base = (bhp->no < 5) ? 0:5;

	//icon passing mode
	if (icon_flag == ICON_ALL)
	{
		ctrl=&ctrlrs[bhp->control];

		// Loop to correct player and make the appropriate move
		for(p_no=0; p_no <5; p_no++)
		{
			int_recvr = base + p_no;
			if (CTL_TAP(ctrl,pass_mask[p_no]))
			{

				//don't pass to self and don't pass to somebody jumping
				if ((int_recvr != ball_handler) && (player[int_recvr].zco == 0))
				{
					CTL_SETTAP(&ctrlrs[bhp->control],CTRL_PASS);
					break;
				}
				else
				{
					ctrlrs[bhp->control].mctrlr &= ~CTRL_PASS;
					ctrlrs[bhp->control].ctrlr  &= ~CTRL_PASS;
					break;
				}
			}
			else if (CTL_HOLD(ctrl,pass_mask[p_no]) && in_play_flag)
			{
				if (int_recvr!=ball_handler && player[int_recvr].zco==0)
					new_main(&player[int_recvr],cut_to_basket);
			}
		}
		return;
	}


    if (ctrlrs[bhp->control].force <= 0x40)	pass_angle = bhp->angle;
	else									pass_angle = ctrlrs[bhp->control].d_angle;


	//look for lowest possible score function
	best_so_far = -1;
	plyr2	= &player[base];
	best_score = 0;

	for (p_no = 0; p_no<5; p_no++)
	{
		if (plyr2 != bhp)
		{
			if (player_inbounds_check(plyr2) == 0)
			{
				angle_diff = (plyr2->ball_angle - pass_angle - 0x7c00);

				//plyr2->score =
				score      = angle_scores[angle_diff>>11]
							 +dist_scores[plyr2->ball_dist >> 20];

				if (plyr2->flags & FALLING)
				{
					score -= 0x1000;
				}

				if (plyr2->main_routine==set_pick || plyr2->main_routine==picked)
					score-=0x1000;

				/*
				if ((plyr2->no == play_pass) && (play_phase >= 0))
				{
					score += 0x10;
				}
				*/


				if (score > best_score)
				{
					best_so_far	= p_no;
					best_score  = score;
				}
			}
		}
		plyr2++;
	}

	int_recvr = best_so_far+base;

	if (player[int_recvr].zco)
	{
		ctrlrs[bhp->control].mctrlr &= ~CTRL_PASS;
		ctrlrs[bhp->control].ctrlr  &= ~CTRL_PASS;
	}
}


void turn_chest_pass(playert *plyr)
{
	CallChainP(turn_chest_pass);

	if (plyr->force < 0x80)
	{
		current_ctrlr->force   = 0x10;
	}
	else
	{
		current_ctrlr->force   = 0x80;
	}

	current_ctrlr->d_angle = plyr->angle2;
	current_ctrlr->ctrlr   &= ~CTRL_SHUFFLE;

	if (end_animation_test(plyr))
	{
		release_chest_pass	(plyr);
		current_ctrlr->force   = 0x10;
		current_ctrlr->d_angle = plyr->angle2;

		start_next_anim(plyr);

		SetMain(turn_chest_pass,plyr,end_turn_chest_pass);
	}
	else
	{
		if (in_play_flag)	dribble_inbounds(plyr);
	}
}






void base_pass(playert *plyr)
{
int time;
SW diff;

	CallChainP(base_pass);

	diff = plyr->angle-plyr->angle2;
	plyr->top_rate=0x200;
	time = ((frames_to_go(plyr)-1)<<8)/0x200;

	if (time>0)
	{
		plyr->angle -= diff/time;

//		plyr->xco += (18*LFPCos(plyr->angle)) >> 4;
//		plyr->yco += (18*LFPSin(plyr->angle)) >> 4;

  		collision(plyr,
			      (18*LFPCos(plyr->angle)) >> 4,
				  (18*LFPSin(plyr->angle)) >> 4,
				  COL_DI);
	}
	else
	{
		release_chest_pass(plyr);
		current_ctrlr->force   = 0x10;
		current_ctrlr->d_angle = plyr->angle2;

		start_next_anim(plyr);
		SetMain(base_pass,plyr,base_pass2);
	}
}


void base_pass2(playert *plyr)
{
	CallChainP(base_pass2);

  	collision(plyr,
		(18*LFPCos(plyr->angle)) >> 4,
		(18*LFPSin(plyr->angle)) >> 4,
		COL_DI);

	if (end_animation_test(plyr))
	{
		start_anim(plyr, TOP_RDY);
		start_leg_anim(plyr, LEG_RDY);
		plyr->leg_routine  = leg_deflt;
		plyr->top_routine  = top_deflt;
		SetMain(base_pass2,plyr,deflt);

		plyr->last_speed = 0;
	}
	else
	{
		dribble_inbounds(plyr);
	}
}








void turn_bounce_pass(playert *plyr)
{
	CallChainP(turn_bounce_pass);

	if (plyr->force < 0x80)
	{
		current_ctrlr->force   = 0x10;
	}
	else
	{
		current_ctrlr->force   = 0x80;
	}


	current_ctrlr->d_angle = plyr->angle2;
	current_ctrlr->ctrlr   &= ~CTRL_SHUFFLE;

	if (end_animation_test(plyr))
	{
		RECORD_PASS1(plyr,CH_PASS_SPD,TRUE,turn_bounce_pass)
		release_pass(plyr, CH_PASS_SPD, TRUE);
		start_next_anim(plyr);

		SetMain(turn_bounce_pass,plyr,end_chest_pass);
	}
	else
	{
		dribble_inbounds(plyr);
	}
}




void down_first_pass(playert *plyr)
{
	CallChainP(down_first_pass);

	current_ctrlr->force   = 0x10;
	current_ctrlr->d_angle = plyr->angle2;
	current_ctrlr->ctrlr   &= ~CTRL_SHUFFLE;

	if (end_animation_test(plyr))
	{
		SetMain(down_first_pass,plyr,turn_chest_pass);
		start_anim(plyr, TOP_SHOV1);
	}
	else
	{
		dribble_inbounds(plyr);
	}
}



void bounce_pass(playert *plyr)
{
	CallChainP(bounce_pass);

	current_ctrlr->force = 0;

	if (end_animation_test(plyr))
	{
		RECORD_PASS1(plyr,CH_PASS_SPD,TRUE,bounce_pass)
		release_pass(plyr, CH_PASS_SPD, TRUE);

		start_next_anim(plyr);

		SetMain(bounce_pass,plyr,end_chest_pass);
	}
	else
	{
		dribble_inbounds(plyr);
	}
}


//bring ball to overhead position, then go into regular pass
void overhead_pass(playert *plyr)
{
	CallChainP(overhead_pass);

	//slow down to stop travelling
	if (current_ctrlr->force>0x80)	current_ctrlr->force   = 0x80;
	current_ctrlr->d_angle = player[int_recvr].ball_angle-0x8000;
	current_ctrlr->ctrlr   &= ~CTRL_SHUFFLE;

//	if (current_ctrlr->force)		current_ctrlr->d_angle = plyr->angle2;

	if (end_animation_test(plyr))
	{
		//now ball is overhead which pass did I want
		plyr->angle2 = player[int_recvr].ball_angle-0x8000;

		start_anim(plyr, TOP_OP1);
		SetMain(overhead_pass,plyr,turn_chest_pass);
	}
	else
	{
		dribble_inbounds(plyr);
	}
}



void chest_pass(playert *plyr)
{
	CallChainP(chest_pass);

	//don't turn while making pass
	current_ctrlr->ctrlr   &= ~CTRL_SHUFFLE;
	if (current_ctrlr->force)
	{
		current_ctrlr->d_angle = plyr->angle2;
	}

	if (end_animation_test(plyr))
	{
		release_chest_pass(plyr);
		current_ctrlr->force   = 0x10;
		current_ctrlr->d_angle = plyr->angle2;

		start_next_anim(plyr);

		SetMain(chest_pass,plyr,end_chest_pass);
	}
	else
	{
		if (in_play_flag)	dribble_inbounds(plyr);
	}
}


/* ************************************************************************ */
/* release_chest_pass()													    */
/* ************************************************************************ */
/* Inputs   - 	ptr to plyr data										    */
/* outputs  -															    */
/* ************************************************************************ */

void release_chest_pass (playert *plyr)
{
int ball_speed;

	CallChainP(release_chest_pass);

	switch (abs(plyr->top_anim))
	{
	case TOP_SHOV1:
		ball_speed = SHOV_PASS_SPD;
		break;

	case TOP_BASEP1:
		ball_speed = BASE_PASS_SPD;
		break;

	case TOP_OSP1:
		ball_speed = OSH_PASS_SPD;
		break;

	case TOP_OP1:
	case TOP_OPR1:

		if (player[int_recvr].ball_dist > 0xc00000)
		{
			ball_speed = (player[int_recvr].ball_dist/0xc000) * (CH_PASS_SPD/256);
			if (ball_speed<CH_PASS_SPD)
				BRK;
		}
/*
		else if ((player[int_recvr].ball_dist < 0x200000) && (player[int_recvr].last_speed==0))
		{
			ball_speed = CH_PASS_SPD/2;
		}
*/else
		{
			ball_speed = CH_PASS_SPD;
		}
		break;


	default:

		if (player[int_recvr].ball_dist < 0x200000)
		{
#if defined(DEBUG)
			char	*msg="Speed/2\n";
			PCwrite(-1,msg,strlen(msg));
#endif
			ball_speed = CH_PASS_SPD/2;
		}
		else if (player[int_recvr].ball_dist > 0x400000)
		{
			ball_speed = CH_PASS_SPD;
		}
		else
		{
#if defined(DEBUG)
			char	*msg="Scaled Speed\n";
			PCwrite(-1,msg,strlen(msg));
#endif
			ball_speed = (player[int_recvr].ball_dist/0x4000) * (CH_PASS_SPD/256);
		}
		break;
	}

	RECORD_PASS1(plyr,ball_speed,FALSE,release_chest_pass)
	release_pass(plyr, ball_speed, FALSE);
}



void end_chest_pass(playert *plyr)
{
	CallChainP(end_chest_pass);

	plyr->hand_check_flag = 0;

	if (blend_to_end(plyr, TOP_RDY, 0 , 4) || (!in_play_flag))
	{
		SetMain(end_chest_pass,plyr,deflt);
		plyr->top_routine  = top_deflt;
	}
}

void end_turn_chest_pass(playert *plyr)
{
	CallChainP(end_turn_chest_pass);

	current_ctrlr->force   = 0x10;
	current_ctrlr->d_angle = plyr->angle2;

	end_chest_pass(plyr);
}

#if defined(LOGGING)

extern char *a_names[];
extern int ccf;
#define PLAY_LOG 0
void PrintPass(PassEvent *e)
{
	int		i;
	char	msg[256];
	char	lp[16];
	char	s[16],ms[16];
	char	r[16];
	char	t[16];
	char	tl[16];
	char	sf[16];

	int		m;
	int		m10;
	int		s10;
	int		sec;
	int		tt;

	if (!e->caller)
	{
		char	txt[]="Bug: Two calls to release_chest_pass\n";
		PCwrite(-1,txt,strlen(txt));
		return;
	}

	for (i=0; i<16; i++)
		lp[i]=s[i]=ms[i]=r[i]=t[i]=tl[i]=sf[i]=0;

	IntToDecStr(e->lp,lp);
	IntToHexStr(e->speed,s);
	IntToHexStr(e->maxspeed,ms);
	IntToHexStr(e->rise,r);
	IntToDecStr(e->time,t);
	IntToDecStr(((float)e->rise/(float)e->speed)*1024,sf);

	tt=e->tl/ONE_SEC;

	m=tt/60;
	tt-=m*60;
	m10=m/10;
	m-=m10*10;

	s10=tt/10;
	sec=tt-s10*10;

	sprintf(msg,"%s: Pass spd:%s/%s rise:%s time:%s [%s]\n",lp,s,ms,r,t,e->caller);
	PCwrite(-1,msg,strlen(msg));
#if PLAY_LOG
	if (ccf!=-1)
		PCwrite(ccf,msg,strlen(msg));
#endif

	sprintf(msg,"       %c%c:%c%c spdfac:%s anim:%s\n",m10+'0',m+'0',s10+'0',sec+'0',sf,a_names[abs(e->an)]);
	PCwrite(-1,msg,strlen(msg));
#if PLAY_LOG
	if (ccf!=-1)
		PCwrite(ccf,msg,strlen(msg));
#endif
}

#endif

