	

#include "generic.h"
#include "lfptypes.h"

#include "audio.h"
#include "crowd.h"

#include "res/playerid.h"

#ifdef N64
#include "defs.h"
#endif

#include "ctrl.h"

#define  MEM_DEBUG 0

#include "define.h"
#include "ml.h"
#include "playgfx.h"
#include "comment.h"

#include "min.h"

#define GLASS 0x80

#define	UNDER_DIST		0x140000		// Distance close enough to be considered under the rim
#define	CLOSE_DIST		0x500000		// Fairly close to the basket
#define	JSFADE_DIST		0x300000		// Minimum distance away to perform running fade
#define JSFADE_X		0x1F0000
#define	RUNJ_Y			0xA7D000

#define	FAKE_DIST		0x200000	// 140000
#define	FAKE_CONE		0x7000		// 3300
#define	MAX_FAKES		3

#define	SHOT_PASS_CONE	0x3000		// 37 degrees
#define	SHOT_PASS_DIST	0x140000
#define	SHOT_PASS_DZ	3			// maximum time until vertical intercept

global bool pt3_flag;			//was shot in 3pt range, 1=yes, 0=no
global int	shot_at_time;		//lp_ctr for time of release
global int  shot_dist;			//dist of shot from hoop (micrometres)
global int  shot_speed;			//how fast was i running when shoot pressed
global int  shot_angle;			//which direction was I facing when shoot pressed

global int  shoot_stage;		//0=no shot, 1=fake, 2= in air, 3=started release

bool piece_of_shit_fastbreak_points_flag=FALSE;

bool off_glass;

bool	may_fake;
int		fake_count;
bool	pass_it_flag;

/*
int start_shot;
int down_time;
int up_time;
*/


int projected_release_time;
int projected_release_x;
int projected_release_y;


void		_print_shot(void);
char		*print_shot(void);
void		release_jump_shot(playert *plyr);
void		IncShotAttempts(playert *plyr);
void		DecShotAttempts(playert *plyr);
static bool should_i_fake(playert *plyr);
static int	miller_test(playert *plyr);
static int	find_receiver(playert *plyr, int cutoff);

playert	*check_shooting_foul(playert *plyr);

#if defined(SHOT_TRACKING)
int	tracking_flag=0;
struct
{
	bool	pt3;		// 3-point shot flag
	int		range;		// Shooter's range rating
	int		zone;		// Shooter's zone
	int		attr_pct;	// Shooter's attribute percentage
	int		base_pct;
	int		moment;
	int		angle;
	int		release;
	int		block;
	int		assist;		// Change due to assistance
} last_shot;
#endif

struct
{
	int	width_3pt;		// Distance from the 3 point line at which full-strength attribute is used
	int	dist_3pt;		// Roughly distance to the three-point line
	int	falloff_3pt;	// % of shot % that rolls off beyond the maximum-strength 3 point stripe

	int	dist_zone[5];	// Maximum distance of each zone
	int	zone_reduce;	// % to decrease for each zone beyond shooting zone

	int	dist_db_max;	// Maximum distance away from the defender

	int	release_max;	// Speed at which release factor is maximized
	int	release_factor;	// Maximum % loss due to release

	int	angle_factor;	// Maximum % loss due to facing

	int	intangible;		// Automatic random deduction
} shot_pct=	{	0x100000,0x750000,33,
				{0x240000,0x370000,0x600000,0x750000,0x1FFF0000},50,
				0x160000,
				0x300,20,
				5
			};

int shoot_zone;

int tmp_range[5]={2,3,2,1,0};

#define	WIDTH_3PT		shot_pct.width_3pt
#define	DIST_3PT		shot_pct.dist_3pt
#define	FALLOFF_3PT		shot_pct.falloff_3pt
#define	ZONE_REDUCE		shot_pct.zone_reduce
#define	RANGE			plyr->plyrROM->ub___pAttrRange
#define	DIST_DB_MAX		shot_pct.dist_db_max
#define RELEASE_MAX		shot_pct.release_max
#define RELEASE_FACTOR	shot_pct.release_factor
#define ANGLE_FACTOR	shot_pct.angle_factor
#define	INTANGIBLE		(shot_pct.intangible+1)

/*
ball bounce lists
dist, angle from centre of hoop, z diff

time, dist, angle from centre of hoop, z diff
*/

static UB bounce2_in[]={
0x10,0x40,0x28,
0xc0,0x10,0x80,0x28,
0xa0,0x00,0x0,0,
MADE};

static UB bounce_in[]={
0x10,0x40,0x28,
0xc0,0x00,0x0,0,
MADE};

static UB in_n_out_n_in[]={
0xe,0x80,0x28,
0xe2,0x8,0x80,8,
0xe2,0x8,0x80,8,
0xe2,0x8,0x80,8,
0xe2,0x8,0x80,8,
0xe2,0x8,0x80,8,
0xe2,0x8,0x80,8,
0xa0,0x0,0x80,8,
MADE};

static UB in_n_out_n_in2[]={
0xe,0x80,0x28,
0xe2,0x8,0x80,8,
0xa0,0x0,0x80,8,
MADE};

static UB bounce_glass_in[]={
0xe,0x0,0x28,
0x90,0,0,0x88,
0,0,0,8,
MADE};

static UB glass_in[]={
0x0,0x0,0x8+GLASS,
0x0,0,0,8,
MADE};

static UB rattle_in[]={
0xe,0x80,0x28,
0xe2,0x8,0x80,0x14,
0xe3,0x8,0x80,0x12,
0xe3,0x8,0x80,0x10,
0xe2,0x8,0x80,0x0,
0x0,0,0,0,
MADE};

static UB swish[]={
0,0,8,
MADE};

static UB clunk[]={
0xc,0x80,0x18,
0xe1,0x0,0x80,8,
MADE};

/***************************** misses ***************************/

static UB air_ball[]={
0x30,0,0,
RIM,0};

static UB off0[]={
/*UM KOBE 1	0x12,0xff,0x18,
RIM_RAND,0x18};
*/
0x12,0xff,0x28,
RIM_RAND,0x1a};

static UB off2[]={
0x12,0x80,0x18,
RIM_RAND,0x18};
//0x12,0x0,0x18,
//RIM_RAND,0x1c};

static UB off1[]={
0x10,0xff,0x20,
RIM,0x18};

static UB glass_out[]={
0x10,0,0x14,
RIM,0x18};

static UB straight_out[]={
0x10,0x80,0x18,
0xa0,0x29,0x80,0x2a,
RIM,0x0};

static UB rattle_out[]={
0xe,0x80,0x28,
0xe2,0x8,0x80,0x10,
0xe3,0x8,0x80,0x20,
RIM,0x18};
/*UM KOBE 1
0xe,0x80,0x28,
0xe2,0x8,0x80,0x20,
0xe2,0x8,0x80,0x18,
0xe2,0x8,0x80,0x10,
0xe3,0x8,0x80,0x20,
RIM,0x18};
*/

static UB in_n_out_n_out[]={
0xe,0x80,0x28,
0xe2,0x8,0x80,8,
0xe2,0x8,0x80,8,
0xe2,0x8,0x80,8,
0xe2,0x8,0x80,8,
0xe2,0x8,0x80,8,
0xe2,0x8,0x80,8,
0xa0,0xe,0x80,0x28,
RIM,0x18};

static UB bounce2_out[]={
0x10,0xff,0x28,
//0xc0,0x10,0x80,0x28,
0xc0,0x15,0xa0,0x28,
RIM,0x18,
};

static UB bounce_glass_out[]={
0xe,0x0,0x28,
0x90,0,0,0x8+GLASS,
0x70,0x10,0x80,0x28,
RIM,0x18};




ball_path_listT miss_list[]=
{
0x0,255,0,0xc0,off1,

0,255,0,255,glass_out,
0,255,0,255,glass_out,
0x0,255,0,0xc0,off1,
0x0,255,0,0xc0,off1,
0x0,255,0,255,rattle_out,
0x0,255,0,255,rattle_out,
//0x0,255,0x0,255,bounce2_out,	// These tend to go into the hoop like a made shot
//0x0,255,0x0,255,bounce2_out,
0x0,255,4,0xc0,off0,	// Do this one least of all, front rim - straight back

0x0,255,4,255,off2,		//Deflect off back of rim
0x0,255,4,255,off2,		//Deflect off back of rim
//0x0,255,0,255,bounce_glass_out,		//May use this later

0x0,0x30,0x70,0xff,air_ball,
0xd0,0xff,0x70,0xff,air_ball,
0xd0,0xff,0x70,0xff,air_ball,
0xd0,0xff,0x70,0xff,air_ball,
0xd0,0xff,0x70,0xff,air_ball,
0x0,0xff,0xa0,0xff,air_ball,

255,255,0,255,swish,

/* UM KOBE 1
0x0,255,0,0xc0,off1,
0x0,255,4,0xc0,off0,
0x0,255,4,255,off2,
0x0,255,0,255,rattle_out,

0x30,0x50,0,0xc8,bounce_glass_out,
0x0,255,0x40,0x80,bounce2_out,
0x0,0x30,0x70,0xff,air_ball,
0xd0,0xff,0x70,0xff,air_ball,
0xd0,0xff,0x70,0xff,air_ball,
0xd0,0xff,0x70,0xff,air_ball,
0xd0,0xff,0x70,0xff,air_ball,
0x0,0xff,0xa0,0xff,air_ball,
0x0,255,0,0xc0,off1,
0x0,255,0x40,0x80,in_n_out_n_out,
255,255,0,255,swish,
*/
};

ball_path_listT perfect_swish[]={
0x0,0xff,0,255,swish,
255,255,0,255,swish,
};


ball_path_listT made_list[]={

0x0,0xff,0,255,swish,
0x0,0xff,0,255,swish,
0x0,0x40,0,255,swish,
0x0,0x30,0,255,swish,
0x0,0xff,0,255,swish,
0x0,0x40,0,255,swish,
0x0,0x30,0,255,swish,


0x0,0xff,0,255,swish,		//doubled the number of possible swishes
0x0,0xff,0,255,swish,
0x0,0x40,0,255,swish,
0x0,0x30,0,255,swish,
0x0,0xff,0,255,swish,
0x0,0x40,0,255,swish,
0x0,0x30,0,255,swish,


0x0,255,0,255,clunk,
0x0,255,0,255,clunk,


0x30,0x50,0x20,0x50,bounce_glass_in,
0x10,0x70,0x10,255,glass_in,
0x10,0x30,0x0,0x60,glass_in,
0x50,0x70,0x0,0x60,glass_in,
0x0,255,0x40,0x60,in_n_out_n_in,
0x0,255,0x40,0x80,in_n_out_n_in2,

0x0,255,0x60,255,rattle_in,
0x0,255,0,255,bounce2_in,
0x0,255,0,255,bounce_in,




/*  UM KOBE 1
//0x0,255,0x60,255,rattle_in,

0x0,0xff,0,255,swish,
0x0,0xff,0,255,swish,
0x0,0x40,0,255,swish,
0x0,0x30,0,255,swish,
0x0,0xff,0,255,swish,
0x0,0x40,0,255,swish,
0x0,0x30,0,255,swish,
//255,255,0,0,swish,

0x0,255,0,255,clunk,
0x0,255,0,255,clunk,


0x30,0x50,0x20,0x50,bounce_glass_in,
0x10,0x70,0x10,255,glass_in,
0x10,0x30,0x0,0x60,glass_in,
0x50,0x70,0x0,0x60,glass_in,
0x0,255,0x40,0x60,in_n_out_n_in,
0x0,255,0x40,0x80,in_n_out_n_in2,

0x0,255,0x60,255,rattle_in,
0x0,255,0,255,bounce2_in,
0x0,255,0,255,bounce_in,
*/

255,255,0,255,swish,
};

ball_path_listT lay_up_made[]={
0x10,0x70,0x0,255,glass_in,
0x10,0x70,0x0,255,glass_in,
0x0,0xff,0,255,swish,
0x0,0xff,0,255,swish,
0x0,0xff,0,255,swish,
255,255,0,0,swish,
};

ball_path_listT ft_miss_list[]={
0x0,255,0,0x60,straight_out,
0x0,255,0,0x60,glass_out,
255,255,255,255,swish,
};




#if defined(SHOT_TRACKING)

static char  track_buf[128];
char *print_shot(void)
{
	return track_buf;
}

void _print_shot(void)
{
	int		i;
	char	c_pt3;
	char	c_range;
	char	c_zone;
	char	attr_pct[4];
	char	base_pct[4];
	char	moment[4];
	char	angle[4];
	char	release[4];
	char	block[4];

	for (i=0; i<4; i++)
		attr_pct[i]=base_pct[i]=moment[i]=angle[i]=release[i]=block[i]=0;

	c_pt3=last_shot.pt3? '3' : '2';
	c_range='0'+last_shot.range;
	c_zone='0'+last_shot.zone;
	IntToDecStr(last_shot.attr_pct,attr_pct);
	IntToDecStr(last_shot.base_pct,base_pct);
	IntToDecStr(last_shot.moment,moment);
	IntToDecStr(last_shot.angle,angle);
	IntToDecStr(last_shot.release,release);
	IntToDecStr(last_shot.block,block);

#ifdef ML
	sprintf(track_buf, "r %c sh %s pc %s m %s  a %s r %s b %s",c_range,attr_pct,base_pct,
			moment,angle,release,block);
#else
	sprintf(track_buf, "%c pt %c:%c %s:%s %s %s %s %s",c_pt3,c_zone,c_range,attr_pct,base_pct,
			moment,angle,release,block);
#endif
}

#endif



bool finger_roll_test(playert *plyr)
{
	UW  adiff;

	CallChainP(finger_roll_test);

	if (plyr->last_speed < 0x800)
		return FALSE;

	adiff = plyr->angle-plyr->basket_angle+0x1000;
	if (adiff > 0x2000)
		return FALSE;

	if ((plyr->basket_dist>0x200000) && (plyr->basket_dist<0x400000))
	{
		int lr;

		SetMain(finger_roll_test,plyr,finger_roll1);
		plyr->top_routine=NULL;
		plyr->leg_routine=NULL;
		lr=plyr->leg_rate;
		start_blend_anim(plyr, TOP_FGR0);
		plyr->top_rate= lr*3/4;
		start_vels(plyr, 80, (SW)plyr->basket_angle);

		BigPoints=HotSpot_Check(plyr);
		if (!project_flag)
		{
			db_out(finger_roll_test,"Increment shot attempts");
			IncShotAttempts(plyr);
			project_dunk_ball(plyr, 17, TRUE);
		}

		SetDunkFlag(finger_roll_test,1);
		scored_flag=0;

		return TRUE;
	}

	return FALSE;
}




void shoot(playert *plyr, int an)
{
	int		spd=0x100;
	int		af;		// animation flags
	int		ta;		// target angle
	int		t;		// how long till ball release
	SW		da;		// angle delta
	SW		sa;		// Shooting angle (delta from the basket)
	SW		fa;		// basket facing angle
	bool	sf=FALSE;	// Speed flag

	//start_shot = lp_ctr;
	//down_time  = 0;

	CallChainP(shoot);

	plyr->ctr2=0;
	may_fake=FALSE;
	jmask(CTRL_SHOOT);
	if (dribble_flag)
		SetDribbleFlag(shoot,2);
	plyr->fouler=NULL;

	//save for shot % calculations
	shot_angle = plyr->angle;
	shot_speed = plyr->last_speed;

	plyr->top_routine = NULL;
	plyr->leg_routine = NULL;

	af=plyr->flags&(~SHOOT_MASK);
	ta=plyr->angle2;
	da=plyr->angle-plyr->basket_angle;
	fa=plyr->basket_angle-0x4000;
	sa=0;
	if (plyr->team)
		fa=-fa;

	// Set the appropriate animation speed
	switch(an)
	{
		case TOP_3PTSHOT11:
			spd = 0xc0;
			plyr->xvel=plyr->yvel=0;
			af|=SHOOT_PIVOT;
			may_fake=TRUE;
			break;

		case TOP_BAKER1:
			if (fa>0)
				an=-an;
			af|=SHOOT_TURN|MOVE_ROOT;
			spd=0x200;
			break;

		case TOP_CHAPMAN1:
			if (da>0)
				an=-an;
			af|=SHOOT_TURN|MOVE_ROOT;
			break;

		case TOP_DUNCAN1:
			//if (da>0)
			sa=-0x2000;
			if (plyr->top_anim<0)
				an=-an;

			af|=SHOOT_TURN|MOVE_ROOT|SHOOT_AIM;
			break;

		case TOP_EWING1:
			if (fa>0)
				an=-an;
			af|=SHOOT_PIVOT|SHOOT_AIM;
			spd=0x200;
			break;

		case TOP_FCRTSHOT1:
			plyr->xvel>>=2;
			plyr->yvel>>=2;
			plyr->xvel=plyr->yvel=0;
			af|=SHOOT_TURN|SHOOT_AIM|MOVE_ROOT|HOLD_ROOT;
			break;

		case TOP_HOOK1:
			spd = 0xc0;
			sa = 0x5000;
			if (da>0)
				an=-an;
			start_vels(plyr, 66, (SW)plyr->angle);
			af |= SHOOT_AIM;
			break;

		case TOP_JSHOT1:
			sa = -0x800;
			spd=0x200;
			plyr->xvel>>=3;
			plyr->yvel>>=3;
			af|=SHOOT_PIVOT|SHOOT_AIM;
			may_fake=TRUE;
			break;

		case TOP_JSHOTR1:
			af|=SHOOT_PIVOT|SHOOT_AIM|SHOOT_STOP;
			sa = -0xc00;
			spd=0x100;
			start_vels(plyr, 70, plyr->angle);
			break;

		case -TOP_JSHOTR1:
			af|=SHOOT_PIVOT|SHOOT_AIM|SHOOT_STOP;
			sa = -0xc00;
			spd=0x100;
			start_vels(plyr, 70, plyr->angle);
			break;


		case TOP_JSFADER1:
			sa = -0x400; 
		case TOP_JSFADEL1:
			spd=0x180;
			af|=SHOOT_TURN|MOVE_ROOT|SHOOT_AIM;
			break;	

		case TOP_JSTAFA1:
			af|=MOVE_ROOT|SHOOT_TURN|SHOOT_AIM;
			break;

		case TOP_KEMP1:
			if (fa>0)
				an=-an;
			af|=MOVE_ROOT|SHOOT_TURN;
			spd=0x200;
			break;

		case TOP_MALONE1:
			if (da<0)
				an=-an;
			af|=SHOOT_TURN|MOVE_ROOT;
			spd=0x200;
			break;

		case  TOP_MILLER1:
		case -TOP_MILLER1:
			af|=SHOOT_TURN|MOVE_ROOT;
			spd=0x200;
			break;

		case TOP_OLAJUWAN1:
			if (fa<0)
				an=-an;
			af|=SHOOT_TURN|MOVE_ROOT|SHOOT_AIM;
			spd=0x200;
			break;

		case TOP_RICHMOND1:
			if (fa<0)
				an=-an;
			af|=SHOOT_TURN|MOVE_ROOT;
			spd=0x200;
			break;

		case TOP_SJBANKBL1:
			plyr->xvel=plyr->yvel=0;
			af|=MOVE_ROOT;
			if (plyr->angle-16384>0)
				an=-an;
			break;

		case TOP_SJSHOT1:
			plyr->xvel=plyr->yvel=0;
			af|=SHOOT_TURN|SHOOT_AIM;
			sa = -0x1800;
			may_fake=TRUE;
			break;

		case TOP_SJSPIV1:
			af|=SHOOT_TURN|MOVE_ROOT|SHOOT_AIM;
			if (plyr->top_anim<0)	// Switch hands
				an=-an;
			spd=0x200;
			break;

		case TOP_WILLIS1:
			if (da>0)
				an=-an;
			plyr->xvel>>=2;
			plyr->yvel>>=2;
			af|=SHOOT_TURN|MOVE_ROOT;
			break;

		default:
			af|=SHOOT_PIVOT;
			break;
	}

	SetMain(shoot,plyr,fake_shot_rou);

	if (an<0)	sa = -sa;
	plyr->target_angle=sa;

	if (plyr->top_anim!=an)
		sf=TRUE;

	start_blend_anim(plyr, an);

	plyr->top_rate=spd;

	plyr->flags  = af;
	plyr->angle2 = ta;

	SetShootStage(shoot,1);
	scored_flag=0;

	if (!project_flag)
	{
		t = project_shot_ball(plyr);
		projected_release_time = lp_ctr+t;

		projected_release_x = ball_cos[(3*t)];
		projected_release_y = ball_cos[(3*t)+1];
	}
}



bool pt3_detect(playert *plyr)
{
int	yco;
int	xco;
int sqr;

	xco	= abs(plyr->xco);
	if (xco > 0x670000)		return 1;

	yco	= current_basket_y - plyr->yco;
	yco	= abs(yco);

	if (yco > 0x798000)		return 2;

	//adjust sqr 'cos Russ hasn't made 3pt arc a circle
	sqr = (0x7b0*0x7b0)-(xco>>5);

	xco>>=12;
	yco>>=12;

	if ( ((yco*yco)+(xco*xco)) > sqr )
	{
		return 3;
	}

	return 0;
}





void set_ball (playert *bl, char *path_list, int t)
{
int dist;
int x_diff, y_diff;
SW  angle;

	if (t==0) t = 1;	/* stop */

	dist    = *path_list++;
	angle   = *path_list++;

	if (angle == (SW)(-1))
	{
		angle = ReadRnd250();
	}

	x_diff = -bl->xco;
	y_diff = current_basket_y - bl->yco;
    angle  = LFPAtn(x_diff, y_diff) + (angle << 8) + 0x8000;
    x_diff += (dist * LFPCos(angle));
    y_diff += (dist * LFPSin(angle));

	if (*path_list & GLASS)
	{
		int old_y_diff;
		int glass_y;
		int temp;

		off_glass=TRUE;
		bl->no2++;

		//go for glass
		bl->zvel = ( BASKET_Z - bl->zco + (( (*path_list++ & 0x7f) - 8) << 12) )/t
                    + ((t-1) * LITTLE_G/2);

		glass_y	 = (current_basket_y > 0) ? GLASS_Y-2: -GLASS_Y+2;
		db_out(set_ball,"Off glass");

		old_y_diff = y_diff;
		y_diff     = glass_y - bl->yco;

		temp    = ((y_diff*2) - old_y_diff)>>8;	//projected y
		if (temp==0)	 temp = 1;
		temp	= y_diff/temp;					//dist to glass/dist to projected y

		x_diff  = (x_diff>>8)*temp;				//adjust x_diff
		temp    = (t * temp)>>8;				//adjust time
		if (temp==0)	 temp = 1;

		bl->markee = (t-temp);
		t		= temp;
	}
	else
	{
		off_glass=FALSE;
		bl->zvel= ( BASKET_Z - bl->zco + ((*path_list++) << 12) )/t
                + ((t-1) * (LITTLE_G/2));
	}

	bl->xvel  = x_diff/t;
	bl->yvel  = y_diff/t;

    bl->angle = LFPAtn(x_diff, y_diff);
	bl->ctr2  = t;

	bl->path_list = path_list;
}




int clear_shot_test(playert *plyr)
{
int x_diff, y_diff;
int dist;
int nDist;
int lowest;
int score;

playert *plyr2;

	lowest = 0x100;

	//look thru opposing team for some one who might be blocking my view of basket
	for (plyr2 = ai_team[plyr->team^1].plyr1; plyr2 < ai_team[plyr->team^1].plyr1+5; plyr2++)
	{
		if (plyr2->basket_dist < plyr->basket_dist)
		{
			x_diff = plyr2->xco - plyr->xco;
			y_diff = plyr2->yco - plyr->yco;

			dist   = MANHATTAN(x_diff, y_diff);
			if (dist < 0x200000)
			{
				//dist off line to basket
				nDist =  (x_diff>>14)*LFPSin(plyr->basket_angle) - (y_diff>>14)*LFPCos(plyr->basket_angle);
				
				if (nDist<0xc0000)
				{
					int head_height;
					int arm_height;

					//plyr head_height
					head_height  = (2000<<2)*plyr->scale;

					//blocker arm_height
					arm_height   = (2000<<2)*plyr2->scale + plyr2->zco;

					if (dist<COL_DI)	dist=COL_DI;

					score = (arm_height-head_height)/(dist>>7);
					score =  0x100-score;
					score += (plyr2->plyrROM->ub___pAttrBlock-50);

					if ((plyr2->control!=0) && (bhp->control==0))
					{
						switch (DIFFICULTY)
						{
							case 0:
							score += score;
							break;

							case 1:
							score += score/2;
							break;
						}
					}


					if (score < 0x10)	score = 0x10;
					if (score<lowest)	lowest=score;
				}
			}
		}
	}

	if (plyr->basket_dist<0x400000)
	{
		if (ai_team[0].controllers[0] | ai_team[1].controllers[0])
		{
			score  = 0x100 - lowest;
			lowest = 0x100 - (score * (0x400000+plyr->basket_dist) )/0x600000;
		}
	}

	//rookie
	if ((DIFFICULTY==0) && (bhp->control) && (ai_team[bhp->team^1].controllers[0]==0))
	{
		return 0x100 - ((0x100-lowest)/2);
	}

	return lowest;
}



int get_shot_percent(playert *plyr, float dist)
{
float a, b, range;
int pt3_rating, p3;
int	rating;

	dist *= 0.8;

	p3 = plyr->plyrROM->ub___pAttr3P;
	
	if ((ai_team[plyr->team].controllers[0]==0) && (ai_team[plyr->team^1].controllers[0]!=0))
	{
		//CPU vs human
		//v higher if difficulty lower
		p3 += (DIFFICULTY-1)*7;
		if (p3<0)	p3=0;
	}
	else if ((ai_team[plyr->team].controllers[0]!=0) && (ai_team[plyr->team^1].controllers[0]==0))
	{
		//
		p3 -= (p3*DIFFICULTY)/16;
	}
	
	range      = (float)plyr->plyrROM->ub___pAttrRange;

	pt3_rating = ((p3+20)*0x8c)>>8;

	range += (50-p3)/(50/1.5);

	if (dist < 7.3)
	{
		//get limit for a
		a = (100-pt3_rating)/(7.3*7.3);

		//get range based a
		a = (2.5-range)*(a/1.5);

		b = ((pt3_rating-100)/7.3) - (a*7.3);

		rating=100 + (b*dist) + (a*dist*dist);
	}
	else if (dist < 10)
	{
		rating=pt3_rating * (1-(dist-7.3)/5.4);
	}
	else if (dist < 13)
	{
		rating=pt3_rating * (0.5-(dist-10)/12);
	}
	else if (dist < 16)
	{
		rating=pt3_rating * (0.25-(dist-13)/24);
	}
	else if (dist < 19)
	{
		rating=pt3_rating * (0.125-(dist-16)/48);
	}
	else if (dist < 21)
	{
		rating=pt3_rating * (0.0625-(dist-19)/96);
	}
	else
	{
		rating=2;
	}

	// Post-adjust the percentages here to please the design gods
	if (!C3PT)
	{
		if (plyr->basket_dist<0x600000)	// Higher percentage shots
		{
			int	dp,diff;

			dp=100-rating/2;
			diff=(0x600000-plyr->basket_dist)>>16;
			rating+=(dp/2)*diff/0x60;
		}
		else if (plyr->basket_dist<0x800000)	// Lower percentage shots
		{
			int	diff;

			diff=(plyr->basket_dist-0x600000)>>16;
			rating-=(rating*3/10)*diff/0x20;
		}
		else	// Bottom % shots
		{
			rating=rating*7/10;
		}

	}

	return rating;
}


#define TURN_MIN 66
#define SPEED_MIN 50


void release_jump_shot(playert *plyr)
{
int percent;
int turn_factor;
int speed_factor;
int block_factor;
int release_factor;
int dt;
float dist;

SW a_diff;
SW trig;

	if (project_flag)	return;

	SetShootStage(release_jump_shot,0);

	if (C3PT)
		block_factor=0x100;
	else
		block_factor = clear_shot_test(plyr);

	dist       = ((float)(pythag(plyr->xco, current_basket_y-plyr->yco))/0x100000);


	//how far have i turned
	turn_factor = 100;
	a_diff = shot_angle - plyr->angle;
	if (a_diff==-0x8000)	a_diff -= 1;
	a_diff = abs(a_diff);

	trig = 0x3000;
	if (a_diff > trig)
	{
		turn_factor = TURN_MIN + ((0x8000-a_diff)*(100-TURN_MIN))/(0x8000-trig);
	}

	//how fast was i running
	speed_factor = 100;
	trig = 0x800;
	if (shot_speed > trig)
	{
		speed_factor = SPEED_MIN + ((0x1700-shot_speed)*(100-SPEED_MIN))/(0x1700-trig);
	}

	release_factor = 0x100;
	if (plyr->control)
	{
		dt = abs(plyr->ctr2 - 4);
		if (dt>4) dt=4;
		release_factor = 0x140-(dt*0x20);
	}

	if (C3PT)
	{
		if (plyr->ctr2-4<0)
			dt*=dt;
		release_factor=0x140-dt*0x20;

		turn_factor    = 100;
		speed_factor   = 100;
	}


	switch (abs(plyr->top_anim))
	{
		case TOP_MALONE3:
		case TOP_MILLER3:
		case TOP_CHAPMAN3:
		case TOP_RICHMOND3:
		release_factor = 0x140;
		dist         = dist*2;
		block_factor = 0x100 - ((0x100-block_factor)/2);
		turn_factor  = 100;
		speed_factor = 100;
		break;
	
		case TOP_HOOK3:
		case TOP_WILLIS3:
		case TOP_KEMP3:
		case TOP_DUNCAN3:
		case TOP_BAKER3:
		case TOP_EWING3:
		case TOP_OLAJUWAN3:
		release_factor = 0x100;
		dist           = dist*2;
		block_factor   = 0x100 - ((0x100-block_factor)/2);
		turn_factor    = 100;
		speed_factor   = 100;
		break;

		default:
		break;
	}

	percent = get_shot_percent(plyr, dist);
	if (DIFFICULTY==0) // Easy-mode tweak
	{
		if (ai_team[plyr->team].controllers[0])
			percent=percent+20;
		else
			percent=percent-30;
	}
	percent-=25*((MAX_PLAYER_ENERGY-plyr->plyrRAM->sw___pEnergy)>>8)/(MAX_PLAYER_ENERGY>>8);

	status_var1 = speed_factor;
	status_var2 = turn_factor;
	status_var3 = (block_factor*100)/256;
	status_var4 = plyr->ctr2-4;
		//(release_factor*100)/256 + (dt*1000);
	status_var5 = percent;
	
	percent = (percent*turn_factor*speed_factor*block_factor)/10000;
	percent = (percent*release_factor)/(256*256);
	if (percent>99)	percent=99;

	if (!plyr->control && !C3PT && !ArcadeMode && !(DIFFICULTY==2))
		percent=percent*19/20;

	status_var6 = percent;

	percent *= 256;
	percent /= 100;

	// Momentum bonus
	if (!PracticeMode)
		if (plyr->team==mom_team)
		{
			int	boost;

			boost=momentum*(ArcadeMode? 3 : 1)/2;
			if (boost>50)
				boost=50+(momentum-50)/2;

			percent+=boost;
		}

	shoot_ball(plyr, percent, (UB *)made_list);

	ball_spinx = 0x800;
	ball_spiny = 0;
	ball_spinz = 0;

	Comment( COMMENT_SHOOT, plyr, 0 );
}



void IncShotAttempts(playert *plyr)
{
			switch(BigPoints)
			{
			case 0:
				if (pt3_flag)
				{
					plyr->plyrRAM->cl___pStatGame.uw___p3PA += 1;
					plyr->teamRAM->cl___tStatGame.uw___t3PA += 1;
				}
				else
				{
					plyr->plyrRAM->cl___pStatGame.uw___pFGA += 1;
					plyr->teamRAM->cl___tStatGame.uw___tFGA += 1;
				}
				break;

			case 5:
				plyr->plyrRAM->ExtraPlayerGameStats.Num5PA++;
				plyr->teamRAM->ExtraTeamGameStats.Num5PA++;
				break;

			case 10:
				plyr->plyrRAM->ExtraPlayerGameStats.Num10PA++;
				plyr->teamRAM->ExtraTeamGameStats.Num10PA++;
				break;

			case 15:
				plyr->plyrRAM->ExtraPlayerGameStats.Num15PA++;
				plyr->teamRAM->ExtraTeamGameStats.Num15PA++;
				break;
			}
}

void DecShotAttempts(playert *plyr)
{	// need this for layups

			switch(BigPoints)
			{
			case 0:
				if (pt3_flag)
				{
					plyr->plyrRAM->cl___pStatGame.uw___p3PA -= 1;
					plyr->teamRAM->cl___tStatGame.uw___t3PA -= 1;
				}
				else
				{
					plyr->plyrRAM->cl___pStatGame.uw___pFGA -= 1;
					plyr->teamRAM->cl___tStatGame.uw___tFGA -= 1;
				}
				break;

			case 5:
				plyr->plyrRAM->ExtraPlayerGameStats.Num5PA--;
				plyr->teamRAM->ExtraTeamGameStats.Num5PA--;
				break;

			case 10:
				plyr->plyrRAM->ExtraPlayerGameStats.Num10PA--;
				plyr->teamRAM->ExtraTeamGameStats.Num10PA--;
				break;

			case 15:
				plyr->plyrRAM->ExtraPlayerGameStats.Num15PA--;
				plyr->teamRAM->ExtraTeamGameStats.Num15PA--;
				break;
			}
}



void shoot_ball(playert *plyr, int percent, UB *path_list)
{
int	x_diff;
int	y_diff;
int	dist;
int	angle;
int	t;
int	d;
char	*p;

UB *paths[sizeof(made_list)/sizeof(made_list[0])];
int no_paths;

	CallChainP(shoot_ball);

	if (!BALL_HANDLER)	return;

	if (!(ft_flag||free_throws))
		if(HSTEST)
			percent/=2;

	piece_of_shit_fastbreak_points_flag=fast_break_flag;

	reset_play();

	if (!project_flag)
	{
		last_blocker=-1;
		last_shooter=plyr->no;
		scored_flag=0;
		if (ArcadeMode && MOM_MAX(plyr->team))
			BallTrail=TRUE;
	}

	if ((time_left) && (!project_flag) && (foul_flag2 != CHARGING))
	{
		if (ft_flag)
		{
			plyr->plyrRAM->cl___pStatGame.uw___pFTA += 1;
			plyr->teamRAM->cl___tStatGame.uw___tFTA += 1;
		}
		else
		{
			db_out(shoot_ball,"IncShotAttempt");
			IncShotAttempts(plyr);
		}
#if 0
		if ((possession_ticks > ONE_SEC) | (plyr->basket_dist > 0xa00000))
		{
			assister = -1;
		}
#endif
	}

	shot_dist = plyr->basket_dist;

	ball.rim_bounce_count = 0;
	ball.no2=0;

	if (!project_flag)	follow_player(&ball);

	SetLastHandler(shoot_ball,plyr->no);

	x_diff	= -ball.xco;
	y_diff	= -ball.yco;
	y_diff	+= current_basket_y;
	dist	=  pythag(x_diff, y_diff);

    angle       = LFPAtn(x_diff, y_diff);       // get angle to basket
	ball.angle	= angle;
	angle		>>=8;
	if (plyr->no > 4)	angle += 0x80;			// correct for near basket
	angle 		&=0xff;

    t = ReadRnd250();

    if (t >= percent)
	{
		//choose from canned misses
		path_list = (UB *)miss_list;
	}

#ifdef DEBUG
	//path_list = (UB *)miss_list;
#endif

	no_paths = 0;
	d		 = dist>>16;
	if (d >= 0xff)	d = 0xff;	/*max distance */


    do
    {
		void	*ptr=((void **)path_list)[1];

		if (plyr->basket_dist>0x380000 && !
				(
				ptr==bounce_in ||
				ptr==glass_in ||
				ptr==swish ||
				ptr==clunk ||
				ptr==air_ball ||
				ptr==off0 ||
				ptr==off2 ||
				ptr==off1 ||
				ptr==glass_out ||
				ptr==straight_out ||
				ptr==bounce2_out
				)
			)
			continue;


		if (angle >= *path_list)
			if (angle <= *(path_list+1))
				if (d >= *(path_list+2))
					if (d <= *(path_list+3))
						paths[no_paths++] = *(UB **)(path_list+4);

		//path_list += 8;
	}
	while (*(path_list+=8) != 0xff);


	if (no_paths == 0)
	{
		paths[0] = air_ball;
		no_paths = 1;
	}

	/*if (percent & 0x100)	dist += BASKET_Z >> 2;
	*/

	//arc shot
	dist=(dist*3)/16;
/*
	if (plyr->top_anim==TOP_FJS2)	dist = (dist/4)+0x80000;
	else							dist = (dist*3)/16;
*/
	if (ball.zco > (BASKET_Z + 0x40000))	dist += ball.zco;
	else									dist += BASKET_Z + 0x40000;

    t   = (LFPSqrt( (dist-ball.zco)/(LITTLE_G/0x200))          /* time on way up */
          +LFPSqrt( (dist-BASKET_Z)/(LITTLE_G/0x200)) ) >> 4;  /* time on way down	*/

	p=(char *)paths[RANDOM(no_paths)];

	#if defined(DEBUG)
	{
		char	txt[64];
		char	num[16];

		memset(num,0,sizeof(num));
		IntToHexStr((int)p,num);
		sprintf(txt,"Selected Path $%s",num);
		db_out(shoot_ball,txt);
	}
	#endif

	set_ball (&ball, p, t);

	shot_at_time	  = time_left;
	SetMain(shoot_ball,&ball,shot_ball_move);

	if(!project_flag)
	{
		SetPossession(shoot_ball,FALSE);
		if ((free_throws==0) && (foul_flag!=TECHNICAL) &&
			(foul_flag!=FLAGRANT) && foul_flag!=ILLEGAL_DEFENSE)
		{
			//up for grabs
			human_reb_flag  = FALSE;

			//move to positions
			if (!C3PT)
				rebound_positions();
		}
	}
}





global bool fadeaway_test(playert *plyr)
{
SW angle_diff;

//test controller to see if pulled back for a fadeaway jumpshot

	angle_diff = current_ctrlr->d_angle - plyr->basket_angle;

	if (current_ctrlr->force > 0x80)
	{

		if (abs(angle_diff) > 0x6000)
		{
			plyr->xvel = -LFPCos(plyr->basket_angle)*3;
			plyr->yvel = -LFPSin(plyr->basket_angle)*3;
			return TRUE;
		}
	}

	//plyr->xvel = 0;
	//plyr->yvel = 0;
	return FALSE;
}




global void running_j_rou1(playert *plyr)
{
	CallChainP(running_j_rou1);

	collision(plyr, plyr->xvel, plyr->yvel, 0);

	if (end_animation_test(plyr))
	{
		pass_it_flag=FALSE;
		SetMain(running_j_rou1,plyr,jump_shot_rou);

		pt3_flag	= pt3_detect(plyr);

		plyr->zvel	= J_ZVEL;
		plyr->col_flags	= -1;
		plyr->flags		&=~(FALLING);

		start_next_anim(plyr);
	}
}



global void pivot_turn_to(playert *plyr, SW ideal_a)
{
SW diff;
SW pivot_angle;
SW turn_speed;
int pivot_dist;

	CallChainP(pivot_turn_to);

	diff = (ideal_a - plyr->angle);

#ifdef N64
#ifdef ANTI_PIRACY
	{
		extern int piracyTotal,breakNextTime;
		if(piracyTotal!=3)
		{
			breakNextTime++;
		}
	}
#endif
#endif

	if (abs(diff)<(TURN_SPEED/2))
	{
		turn_speed = diff;
	}
	else
	{
		turn_speed = (diff>0) ? TURN_SPEED/2:-TURN_SPEED/2;
	}


	//have i pivoted yet
	switch (pivot_flag)
	{
		case NO_PIVOT:
		if (turn_speed > 0)
		{
			pivot_dist = LFPSin(turn_speed/2);
			pivot_flag = LEFT_PIVOT;
			pivot_angle= -0x2000;		//angle of ball of pivot foot from c of player
		}
		else
		{
			pivot_dist = -LFPSin(turn_speed/2);
			pivot_flag =  RIGHT_PIVOT;
			pivot_angle= 0x2000;		//angle of ball of pivot foot from c of player
		}
		break;

		case LEFT_PIVOT:
		pivot_dist = LFPSin(turn_speed/2);
		pivot_angle= -0x2000;			//angle of ball of pivot foot from c of player
		break;

		case RIGHT_PIVOT:
		pivot_dist = -LFPSin(turn_speed/2);
		pivot_angle= 0x2000;			//angle of ball of pivot foot from c of player
		break;
	}

	pivot_dist *= (200*plyr->scale)>>(11+4);	//dist by centre during pivot
	pivot_angle += plyr->angle + (turn_speed/2);

	plyr->xco += (pivot_dist*LFPCos(pivot_angle)) >> 10;
	plyr->yco += (pivot_dist*LFPSin(pivot_angle)) >> 10;

/*
	run_collision(plyr,
					 (pivot_dist*LFPCos(pivot_angle)) >> 10,
					 (pivot_dist*LFPSin(pivot_angle)) >> 10);
*/

	plyr->angle += turn_speed;
}



static bool should_i_fake(playert *plyr)
{
	int		dx,dy;
	int		dist;
	SW		a;
	playert	*p,*e;

	if (fake_count>=MAX_FAKES)
		return FALSE;

	p=&player[5-plyr->base];
	e=p+5;
	while (p<e)
	{
		dx=p->xco-plyr->xco;
		dy=p->yco-plyr->yco;
		dist=MANHATTAN(dx,dy);
		a=LFPAtn(dx,dy);

		if (dist<FAKE_DIST && abs(plyr->basket_angle-a)<FAKE_CONE && !p->zco)
			if (ReadRnd250()<255-fake_count*80)
				return TRUE;

		p++;
	}

	return FALSE;
}



void fake_shot_return(playert *plyr)
{
	CallChainP(fake_shot_return);

	if (!end_animation_test(plyr))
		return;

		SetShootStage(fake_shot_return,0);

	if (plyr->control)	// Human player
	{
		SetMain(fake_shot_return,plyr,stand_with_ball);
		plyr->flags&=~SHOOT_MASK;
		plyr->top_routine  = NULL;
		plyr->leg_routine  = leg_deflt;
		start_blend_anim(plyr, TOP_STAND_BALL);
		SetShootStage(fake_shot_return,0);
	}
	else	// Computer player
	{
		if (!BigPoints && fake_count==MAX_FAKES)
		{
			int	rec;

			rec=find_receiver(plyr,0x00D00000);
			if (rec!=-1)
			{
				int_recvr=rec;
				start_pass(plyr);
			}
			else
				//shoot(plyr,TOP_JSHOT1);
				shoot(plyr,abs(plyr->top_anim));
		}
		else
			//shoot(plyr,TOP_JSHOT1);
			shoot(plyr,abs(plyr->top_anim));
	}
}



void finish_fake(playert *plyr)
{
	if (!project_flag)
		fake_count++;
	SetMain(finish_fake,plyr,fake_shot_return);
	plyr->flags&=~SHOOT_MASK;
	plyr->top_rate=-plyr->top_rate;
}



global void fake_shot_rou(playert *plyr)
{
playert *marker;
bool fake_flag;

	CallChainP(fake_shot_rou);

	SetShootStage(fake_shot_rou,1);

	//if ((!down_time) && !CCTL_DOWN(CTRL_SHOOT))		down_time = lp_ctr-start_shot;

	if (plyr->flags&MOVE_ROOT)
		move_by_anim(plyr);
	else if (plyr->xvel|plyr->yvel)
		collision(plyr, plyr->xvel, plyr->yvel, 0);

	if (plyr->flags&SHOOT_PIVOT)
		pivot_turn_to(plyr, (SW)plyr->basket_angle-plyr->target_angle);

	if (may_fake)
	{
		if (plyr->control)
		{
			if (!CTL_DOWN(current_ctrlr,CTRL_SHOOT))
			{
				finish_fake(plyr);
				return;
			}
		}
		/*
		else	// computer-controlled player
		{
			int	f;

			f=(playerAnims[abs(plyr->top_anim)].a->numFrames/2)<<8;
			if (plyr->top_frame>f && plyr->top_frame-plyr->top_rate<f) // Fake half-way through 1st anim
			{
				int	y;

				y = plyr->yco;
				if (plyr->no > 4)
					y = -y;

				if (y>FOUL_LINE+EDGE && abs(plyr->xco)<LANE_X && should_i_fake(plyr))
				{
					finish_fake(plyr);
					return;
				}]
			}
		}
		*/
	}

	if (end_animation_test(plyr))
	{
		if (abs(plyr->top_anim) == TOP_HOOK1)
		{
			plyr->xvel>>=1;
			plyr->yvel>>=1;
		}
		
		//up_time = 0;
		//status_var1 = lp_ctr-start_shot;

		if (plyr->flags&SHOOT_TURN)
			face_by_anim(plyr);

		// Switch to deflt should the ball have been prematurely blocked out of my hands
		if (!possession_flag)
		{
			SetMain(fake_shot_rou,plyr,deflt);
			plyr->leg_routine  = leg_deflt;
			plyr->top_routine  = top_deflt;
			start_leg_anim(plyr, LEG_RDY);
			start_anim(plyr, TOP_RDY);
			return;
		}

		if (plyr->flags&SHOOT_STOP)
		{
			plyr->xvel>>=2;
			plyr->yvel>>=2;
		}

		fake_flag = FALSE;
		pt3_detect(plyr);

		if (may_fake)
		{
			if (plyr->control == 0)
			{
				if (!project_flag)
				{
					if (should_i_fake(plyr))
					{
						finish_fake(plyr);
						if (plyr->flags&SHOOT_TURN)
							face_by_anim(plyr);
						return;
					}
				}
			}
			else
				fake_flag = ((current_ctrlr->ctrlr & CTRL_SHOOT) == 0);
		}

		if (fake_flag)
		{
			SetMain(fake_shot_rou,plyr,stand_with_ball2);
			plyr->top_routine  = NULL;
			plyr->leg_routine  = leg_deflt;
			start_blend_anim(plyr, TOP_OVER_BALL);
			SetShootStage(fake_shot_rou,0);
		}
		else
		{
			/* start jump shot */
			pass_it_flag=FALSE;
			SetMain(fake_shot_rou,plyr,jump_shot_rou);

			pt3_flag	= pt3_detect(plyr);

			plyr->zvel	= J_ZVEL;
			plyr->col_flags	= -1;
			plyr->flags		&=~(FALLING);

			// If fading away, switch to the appropriate anim
			if (fadeaway_test(plyr))
			{
				int an;

				switch(abs(plyr->top_anim))
				{
					case TOP_SJSPIV1:
						an=TOP_SJSPIVFA2;
						break;

					default:
						an=abs(plyr->top_anim)+1;
						break;
				}

				if (plyr->top_anim<0)
					an=-an;

				start_anim2(plyr, an , (time_till_land(plyr)/2)-3);
				plyr->flags&=~MOVE_ROOT;
			}
			else
				start_next_anim2(plyr, (time_till_land(plyr)/2)-3);
		}
	}
}



global void jump_shot_rou(playert *plyr)
{
int zco;
bool shoot_flag;
bool	facing_flag=TRUE;
bool	ik;
bool	dc;
playert	*fouler;

	CallChainP(jump_shot_rou);

	SetShootStage(jump_shot_rou,2);

	//if ((!down_time) && !CCTL_DOWN(CTRL_SHOOT))		down_time = lp_ctr-start_shot;
	
	if (CCTL_DOWN(CTRL_SHOOT))	plyr->ctr2++;

	// Update position
	if (plyr->flags&MOVE_ROOT)
	{
		move_by_anim(plyr);
	}
	else if (plyr->xvel|plyr->yvel)
		run_collision(plyr, plyr->xvel, plyr->yvel);

	if (plyr->flags&(SHOOT_PIVOT|SHOOT_AIM))
	{
		facing_flag=turn_to(plyr, plyr->basket_angle-plyr->target_angle);
		status_var1 = plyr->target_angle;
	}
	

	zco		= plyr->zco;
	zco		+=plyr->zvel;
    plyr->zvel  -=LITTLE_G;

	if (zco < 0)	zco	= 0;
	plyr->zco = zco;

	if (CCTL_DOWN(CTRL_PASS+CTRL_POST_PASS))
		pass_it_flag=TRUE;

	if (!project_flag)
	{
		if (!plyr->fouler)
			if ((plyr->fouler=check_shooting_foul(plyr)))
			{
				free_thrower=plyr->no;
				FoulSet(jump_shot_rou,plyr->fouler,HACKING2);
				if (last_blocker!=-1)
				{
					player[last_blocker].plyrRAM->cl___pStatGame.uw___pBLK -= 1;
					player[last_blocker].teamRAM->cl___tStatGame.uw___tBLK -= 1;
				}
			}

		// Check for computer passing out
		ik=abs(plyr->xco)<LANE_X && (PLY(plyr)>FOUL_LINE);
		dc=plyr->basket_dist<0x30000;
		if (!plyr->control && !(ik||dc) && shot_clock>ONE_SEC*3 &&
			plyr->main_routine==jump_shot_rou && !plyr->fouler && !BigPoints)
		{
			bool	pflag=FALSE;
			playert	*p,*e;
			int		dx,dy;
			int		dz;
			int		dv;			// difference between the velocities
			SW		a;

			p=&player[5-plyr->base];
			e=p+5;

			// Check to see if there is a defender in the air in position to hurt me good
			do
			{
				// If on the ground, not a threat
				if (!p->zco)
					continue;

				// Check to see if his verticality is a threat
				dz=p->zco-plyr->zco;
				if (dz<0)	// If he's below me, he can still be a threat
				{
					dv=p->zvel-plyr->zvel;
					if (dv<=0)		// below and slower: definitely not a threat
						continue;
					if (-(dz/dv)>SHOT_PASS_DZ)	// is he not at a threatening rate?
						continue;
				}

				// Check to see if between the me and the basket
				dx=p->xco-plyr->xco;
				dy=p->yco-plyr->yco;
				a=LFPAtn(dx,dy);
				if (abs(a-plyr->basket_angle)>SHOT_PASS_CONE)
					continue;

				// Check the distance away
				if (MANHATTAN(dx,dy)>SHOT_PASS_DIST)
					continue;

				//  All checks passed, pressure is officially on
				pflag=TRUE;
				break;

			} while(++p<e);

			// If the pressure is on, see if there's an open man
			if (pflag)
			{
				int		i;

				i=find_receiver(plyr,0x00D00000);
				if (i!=-1)
				{
					int_recvr=i;
					if (start_jump_pass(plyr))
					{
						SetShootStage(jump_shot_rou,0);
						if (plyr->flags&SHOOT_TURN)
							face_by_anim(plyr);

						plyr->flags&=~(SHOOT_TURN|MOVE_ROOT|HOLD_ROOT);
					}
				}
			}
		}
	}

	if (facing_flag)
	{
		if (possession_flag && !project_flag)	ball_place(plyr);

		if (end_animation_test(plyr))
		{
			if (pass_it_flag && !plyr->fouler)
				if (!project_flag)
					if (start_jump_pass(plyr))
					{
						SetShootStage(jump_shot_rou,0);
						if (plyr->flags&SHOOT_TURN)
							face_by_anim(plyr);
						return;
					}

			shoot_flag=1;
			SetMain(jump_shot_rou,plyr,jump_shot_rou2);

			if (shoot_flag)
			{
				if (plyr->flags&SHOOT_TURN)
					face_by_anim(plyr);

				start_next_anim2(plyr, 3);
			}
		}
	}
}



void jump_shot_rou2(playert *plyr)
{
int		zco;
playert	*fouler;

	CallChainP(jump_shot_rou2);

	SetShootStage(jump_shot_rou2,3);

	if (CCTL_DOWN(CTRL_SHOOT))	plyr->ctr2++;

	// Update position
	if (plyr->flags&MOVE_ROOT)
		move_by_anim(plyr);
	else if (plyr->xvel|plyr->yvel)
		collision(plyr, plyr->xvel, plyr->yvel, COL_DI/2);

	zco		   =  plyr->zco;
	zco		   += plyr->zvel;
    plyr->zvel -= LITTLE_G;
	plyr->zco  = zco;

	if (plyr->flags&SHOOT_AIM)
	{
		turn_to(plyr, plyr->basket_angle-plyr->target_angle);
		status_var1 = plyr->target_angle;
	}

	if (!plyr->fouler)
		if ((plyr->fouler=check_shooting_foul(plyr)))
		{
			free_thrower=plyr->no;
			FoulSet(jump_shot_rou2,plyr->fouler,HACKING2);
			if (last_blocker!=-1)
			{
				player[last_blocker].plyrRAM->cl___pStatGame.uw___pBLK -= 1;
				player[last_blocker].teamRAM->cl___tStatGame.uw___tBLK -= 1;
			}
		}

	if (end_animation_test(plyr))
	{
		//status_var3 = lp_ctr-start_shot;

		if (plyr->flags&SHOOT_TURN)
			face_by_anim(plyr);

		release_jump_shot(plyr);

		SetShootStage(jump_shot_rou2,0);
		start_next_anim2(plyr, time_till_land(plyr));
		SetMain(jump_shot_rou2,plyr,jump_shot_rou3);
	}
}



void jump_shot_rou3(playert *plyr)
{
int zco;

	CallChainP(jump_shot_rou3);

	// Update position
	if (plyr->flags&MOVE_ROOT)
		move_by_anim(plyr);
	else if (plyr->xvel|plyr->yvel)
		collision(plyr, plyr->xvel, plyr->yvel, 0);

	zco			= plyr->zco;
	zco		    +=plyr->zvel;
	plyr->zvel  -=LITTLE_G;

	if (zco <= 0)
	{
		if ((plyr->flags&SHOOT_TURN) || (abs(plyr->top_anim)==TOP_HOOK4))
			face_by_anim(plyr);
		plyr->flags|=MOVE_ROOT;	// Always finish with motion
		SetMain(jump_shot_rou3,plyr,jump_shot_rou4);
		start_next_anim(plyr);
		zco = 0;
	}
	plyr->zco	= zco;
}




void jump_shot_rou4(playert *plyr)
{
	CallChainP(jump_shot_rou4);
	
	// Update position
	if (plyr->flags&MOVE_ROOT)
		move_by_anim(plyr);
	else if (plyr->xvel|plyr->yvel)
		collision(plyr, plyr->xvel, plyr->yvel, COL_DI/2);

	if (plyr->control)
	{
		if ((plyr->force > 0xc0) && (frames_to_go(plyr)<0x500))
		{
		if (plyr->flags&SHOOT_TURN) 
			face_by_anim(plyr);

			SetMain(jump_shot_rou4,plyr,deflt);
			plyr->top_routine  = top_deflt;
			plyr->leg_routine  = leg_deflt;

			plyr->flags&=~(SHOOT_TURN|MOVE_ROOT|HOLD_ROOT);
		}
	}

	if (blend_to_end(plyr, TOP_RDY, LEG_RDY, 4))
	{
		if (plyr->flags&SHOOT_TURN)
			face_by_anim(plyr);

		SetMain(jump_shot_rou4,plyr,deflt);
		plyr->top_routine  = top_deflt;
		plyr->leg_routine  = leg_deflt;

		plyr->flags&=~(SHOOT_TURN|MOVE_ROOT|HOLD_ROOT);
	}
}



void layup_release(playert *plyr)
{
UB pct;

	pct	= (0xf8-100);	// + plyr->plyrRAM->ub___pPower;
//	if (foul_flag)	pct = pct>>1;

	SetDunkFlag(layup_release,FALSE);
	pt3_flag  = FALSE;

	shoot_ball(plyr,0xf8,(UB *)lay_up_made);
	if (!project_flag)
	{
		last_dunker=plyr->no;
		if (ArcadeMode && MOM_MAX(plyr->team))
			BallTrail=TRUE;
	}

	ball_spinx = -0x1000;
	ball_spiny = 0;
	ball_spinz = 0;

	if (!project_flag)
	{
		db_out(layup_release,"Deduct FGA");
		DecShotAttempts(plyr);
	}

	Comment( COMMENT_LAYUP, plyr, 0 );
}





void tip_release(playert *plyr)
{
	shoot_ball(plyr,0xff,(UB *)lay_up_made);
}



global bool hook_test(playert *plyr)
{
SW a_diff;
int x_diff, y_diff;

	if (plyr->basket_dist < 0x400000)
	{
		//will shooter be at right angles to basket at release

		x_diff = - plyr->xco - (7*plyr->xvel);
		y_diff = current_basket_y - plyr->yco - (7*plyr->yvel);

		a_diff = LFPAtn(x_diff, y_diff) - plyr->angle;

		if ((a_diff > 0x3000) && (a_diff < 0x5000))
			return TRUE;

		if ((a_diff < -0x3000) & (a_diff > -0x5000))
			return TRUE;
	}
	return FALSE;
}



global void finger_roll1(playert *plyr)
{
int dist;
int fact;

	CallChainP(finger_roll1);

	plyr->col_flags &= collision (plyr, plyr->xvel, plyr->yvel, COL_DI/2);		/* record result of this for % and/or foul */

	//check to make sure I won't go past basket
	dist = (MANHATTAN(plyr->xvel, plyr->yvel)*12) + (750<<10);
	if (dist>plyr->basket_dist)
	{
		fact=(plyr->basket_dist<<8)/dist;
		plyr->xvel = (fact*plyr->xvel)>>8;
		plyr->yvel = (fact*plyr->yvel)>>8;
	}


	if (end_animation_test(plyr))
	{
		pt3_flag   = FALSE;
		plyr->zvel = HC_ZVEL;
		start_next_anim(plyr);
		SetMain(finger_roll1,plyr,finger_roll2);
	}
}


global void finger_roll2(playert *plyr)
{
int zco;

	CallChainP(finger_roll2);

	//plyr->col_flags &= collision (plyr, plyr->xvel, plyr->yvel, COL_DI/2);		/* record result of this for % and/or foul */
	plyr->xco+=plyr->xvel;
	plyr->yco+=plyr->yvel;

	zco		= plyr->zco;
	zco		+=plyr->zvel;
    plyr->zvel  -=LITTLE_G;
	plyr->zco = zco;

	if (end_animation_test(plyr))
	{
		SetDunkFlag(finger_roll2,FALSE);
		if (!project_flag && possession_flag)
		{
			db_out(finger_roll2,"Decrementing shot attempts");
			DecShotAttempts(plyr);
		}
		shoot_ball (plyr, (plyr->plyrROM->ub___pAttrFG*256)/100, (UB *)made_list);

		SetMain(finger_roll2,plyr,finger_roll3);
		start_next_anim2(plyr, time_till_land(plyr));
	}
}


global void finger_roll3(playert *plyr)
{
int zco;

	CallChainP(finger_roll3);

	//plyr->col_flags &= collision (plyr, plyr->xvel, plyr->yvel, COL_DI/2);		/* record result of this for % and/or foul */
	plyr->xco+=plyr->xvel;
	plyr->yco+=plyr->yvel;

	zco		   =  plyr->zco;
	zco		   += plyr->zvel;
    plyr->zvel -= LITTLE_G;

	if (zco < 0)
	{
		start_next_anim(plyr);
		SetMain(finger_roll3,plyr,finger_roll4);
		start_vels(plyr, 60, (SW)plyr->angle);
		zco = 0;
	}

	plyr->zco = zco;
}


global void finger_roll4(playert *plyr)
{
	CallChainP(finger_roll4);

	plyr->col_flags &= collision (plyr, plyr->xvel, plyr->yvel, COL_DI/2);		/* record result of this for % and/or foul */

	if (end_animation_test(plyr))
	{
		SetMain(finger_roll4,plyr,deflt);
		plyr->leg_routine  = leg_deflt;
		plyr->top_routine  = top_deflt;
		start_leg_anim(plyr, LEG_RDY);
		start_anim(plyr, TOP_RDY);
	}
}





char data_string[15][30];



int select_shot(playert *plyr)
{
	int	an=TOP_JSHOT1;	// Default
	SW	a=plyr->basket_angle-plyr->angle;

	if (PLY(plyr)<0)
		return TOP_FCRTSHOT1;

	if (abs(a)>0x6000 /*plyr->shuffle*/)
	{
		if (plyr->basket_dist<UNDER_DIST)
			return TOP_SJBANKBL1;
#if 0
		else if ( IS_PLYR(REX_CHAPMAN_PHO) && MANHATTAN(plyr->xvel,plyr->yvel)>WALK_THRESHOLD && PLY(plyr)<BASE_LINE-2*METER)
			return TOP_CHAPMAN1;
#endif
		else if ( IS_PLYR(REGGIE_MILLER_IND) && pt3_detect(plyr) )
		{
			int	an2;

			an2=miller_test(plyr);
			if (an2)
				return an2;
		}
		else if (plyr->basket_dist>0x600000 && plyr->basket_dist<0x800000)
		{
			if (IS_PLYR(MITCH_RICHMOND_WAS))
				return TOP_RICHMOND1;
		}
		else if (plyr->basket_dist<0x500000 && plyr->basket_dist>0x300000)
		{
			if (BASE_LINE-abs(plyr->yco)<0x200000)
			{
				switch(PID)
				{
					case PID_HAKEEM_OLAJUWON_HOU:
						return TOP_OLAJUWAN1;

					case PID_PATRICK_EWING_NY:
						return TOP_EWING1;

					default:
						if (ArcadeMode)
						{
							switch(rand()%4)
							{
								case 1:
									return TOP_OLAJUWAN1;

								case 2:
									return TOP_EWING1;
							}
						}

						return TOP_SJSPIV1;
				}
			}
			else if (IS_PLYR(VIN_BAKER_SEA) && (!dribble || (plyr->main_routine!=stand_with_ball && plyr->main_routine!=stand_with_ball2)) )
				return TOP_BAKER1;

		}
		else if (IS_PLYR(SHAWN_KEMP_CLE) && plyr->basket_dist<0x300000)
			if (BASE_LINE-PLY(plyr)<0x200000)
				return TOP_KEMP1;

		return TOP_SJSPIV1;
	}

	if (plyr->basket_dist>UNDER_DIST && hook_test(plyr))
		return TOP_HOOK1;

	if (pt3_detect(plyr))
	{
		if (IS_PLYR(REGGIE_MILLER_IND) )
		{
			int	an2;

			an2=miller_test(plyr);
			if (an2)
				return an2;
		}

		return TOP_3PTSHOT11;
	}

	if (MANHATTAN(plyr->xvel,plyr->yvel)<WALK_THRESHOLD)	// Is the player stationary/walking?
	{
		SW da=plyr->basket_angle-plyr->angle;

		if (plyr->basket_dist<UNDER_DIST)
			return TOP_SJBANKBL1;
		else if (IS_PLYR(KEVIN_WILLIS_TOR) && abs(da)>0x6000 &&
				plyr->basket_dist>0x200000 && plyr->basket_dist<0x400000)
			return TOP_WILLIS1;
		else if (da>0x6000 || da<-0x6000)
			return TOP_JSTAFA1;
		else if (plyr->basket_dist<CLOSE_DIST)
		{
			if (IS_PLYR(TIM_DUNCAN_SA))
				if (BASE_LINE-abs(plyr->yco)<0x200000)
					if (abs(plyr->angle-plyr->basket_angle)<0x2000)
						return TOP_DUNCAN1;

			return TOP_SJSHOT1;

			/*
			if (abs(da) < 0x2000)	return TOP_SJSHOT1;
			else					return TOP_JSHOT1;
			*/
		}
		else if (plyr->basket_dist>0x480000 && plyr->basket_dist<0x600000)
			if (IS_PLYR(KARL_MALONE_UTA))
				if (abs(da)>0x3000 && abs(da)<0x5000)
					return TOP_MALONE1;

	}
	else	// The player is running
	{
		// Don't shoot if heading out of bounds, supposedly
		if ( plyr->yco + (plyr->yvel * (ONE_SEC/3)) > BASKET_Y)
			return an;

		if ((plyr->last_speed > JOG_THRESHOLD) &&
			abs(plyr->yco)<(BASKET_Y-0x10000) && 
			plyr->basket_dist>JSFADE_DIST &&
			abs(plyr->xco)>JSFADE_X )
		{
			if (a>8192-1024 && a<16384+8192-1024)
				return TOP_JSFADER1;
			if (a<-8192+1024 && a>-16384-8192+1024)
				return TOP_JSFADEL1;
		}
		else
		{
			if (plyr->last_speed > JOG_THRESHOLD && PLY(plyr)<BASE_LINE-0x200000)
			{
				if (a>0) return TOP_JSHOTR1;
				else	 return -TOP_JSHOTR1;
			}
			else
			{
				return TOP_JSHOT1;
			}
		}
	}

	return an;
}



#define	MILLER_CONE	0x800

int miller_test(playert *plyr)
{
	bool	l,m,r;
	playert	*p,*e;
	SW		da;

	l=m=r=FALSE;
	p=&player[(plyr->team)? 0:5];
	e=p+5;

	// Do a quick out if the player has dribbled
	if (dribble_flag)
		return 0;

	// If not facing the basket and moving slowly, can't do the move
	da=abs(plyr->basket_angle-plyr->angle);
	if (da>0x2000 || MANHATTAN(plyr->xvel,plyr->yvel)>WALK_THRESHOLD)
		return 0;

	// Check defender's position
	do
	{
		int	dx,dy;
		int	d;
		int	dba;		// Difference in basket angles
		int	onR;

		dba=p->basket_angle-plyr->basket_angle;
		if (abs(dba)>MILLER_CONE)
			continue;

		dx=p->xco-plyr->xco;
		dy=p->yco-plyr->yco;
		d=MANHATTAN(dx,dy);

		onR=(dba>0)? 0:1;
		dba=abs(dba);
		switch(dba>>10)		// Is the defender to the left, right, or ahead
		{
			case 0:
				if (d<0x1c0000)
					m=TRUE;
				break;

			case 1:
			case 2:
				if (d<0x200000)
				{
					if (onR)
						r=TRUE;
					else
						l=TRUE;

					if (d<0x100000)
						m=TRUE;
				}
				break;
		}
	} while(++p<e);

	// Determine type of shot
	if (m)
	{
		if (!l && !r)
			return (ReadRnd250()<128)? TOP_MILLER1 : -TOP_MILLER1;
		else if (!l)
			return -TOP_MILLER1;
		else if (!r)
			return TOP_MILLER1;
	}

	return 0;
}


int find_receiver(playert *plyr, int cutoff)
{
	int		i;
	int		score;				// current score
	int		best;
	int		selection=-1;
	playert	*p;

	best=cutoff;
	p=&player[plyr->base];

	// Check all of the teammates to see if they are open
	for (i=0; i<5; i++)
	{
		// I cannot be considered open to a pass from myself
		if (p[i].no==plyr->no)
			continue;

		// Determine score and handle apporpriately
		score=pass_scores[i];
		if (score<best)
		{
			best=score;
			selection=i+plyr->base;
		}
	}

	return selection;
}

playert	*check_shooting_foul(playert *plyr)
{
	playert	*fouler=NULL;

	if (!DEFENSIVE_FOULS)
		return NULL;

	if (project_flag)
		return NULL;

	// Determine if a defender has run into me
	if (plyr->bumped_into && plyr->bumped_into->no!=last_blocker)
	{
		if (plyr->bumped_into->base!=plyr->base)
			fouler=plyr->bumped_into;
	}
	else if (plyr->bumped_into_me && plyr->bumped_into_me->no!=last_handler)
		if(plyr->bumped_into_me->base!=plyr->base)
			fouler=plyr->bumped_into_me;

	// If no collision has occurred, then no foul has been committed
	if (!fouler)
		return fouler;

	// Decide if this collision is a foul
	if (ReadRnd250()>10)
		return NULL;

	return fouler;
}

void shooting_foul_rou(playert *plyr)
{
	CallChainP(shooting_foul_rou);

	jump_shot_rou(plyr);
	if (plyr->main_routine!=shooting_foul_rou)
		plyr->main_routine=shooting_foul_rou2;
}

void shooting_foul_rou2(playert *plyr)
{
	CallChainP(shooting_foul_rou2);

	jump_shot_rou2(plyr);
	if (plyr->main_routine!=shooting_foul_rou2)
		plyr->main_routine=shooting_foul_rou3;
}

void shooting_foul_rou3(playert *plyr)
{
	CallChainP(shooting_foul_rou3);

	jump_shot_rou3(plyr);
	if (plyr->main_routine!=shooting_foul_rou3)
		plyr->main_routine=shooting_foul_rou4;
}

void shooting_foul_rou4(playert *plyr)
{
	CallChainP(shooting_foul_rou4);

	jump_shot_rou4(plyr);
	if (plyr->main_routine!=shooting_foul_rou4)
	{
		FoulSet(shooting_foul_rou4,plyr->fouler,HACKING2);
		free_thrower=plyr->no;
	}
}
