
#include "generic.h"
#include "lfptypes.h"

#include "define.h"
#include "ml.h"

#ifdef PC
 #include "fontcode.h"
 #include "dbugtxt.h"
#endif

#include "ctrl.h"

extern s8 ShowTrails;

static void	set_shuffle_speed(playert *plyr);
static bool	can_stop_shuffle(playert *plyr);
static void	check_anim_quick_change(playert *plyr);
static void	loop_shuffle_animation(playert * plyr);


/* local variables */


#define RUN_TURN 0x1800

#define SHUF_FACT 0xc0;

SW ctrlr_force;

int sshuf_legs_tbl[]= { LEG_GUARD1, LEG_GUARD2, LEG_GUARD3, LEG_GUARD4 };

SW shuffle_lookup[3][16]={
//start
-LEG_SKIPS_ST,
-LEG_SKIPSSE_ST,
-LEG_SKIPSE_ST,
-LEG_SKIPESE_ST,

-LEG_SKIPE_ST,
LEG_SKIPENE_ST,
-LEG_SKIPNE_ST,
LEG_SKIPNNE_ST,

-LEG_SKIPN_ST,
-LEG_SKIPNNE_ST,
LEG_SKIPNE_ST,
-LEG_SKIPENE_ST,

LEG_SKIPE_ST,
LEG_SKIPESE_ST,
LEG_SKIPSE_ST,
LEG_SKIPSSE_ST,

//loop1
-LEG_SKIPS_LP,
-LEG_SKIPSSE_LP,
-LEG_SKIPSE_LP,
-LEG_SKIPESE_LP,

-LEG_SKIPE_LP,
-LEG_SKIPENE_LP,
-LEG_SKIPNE_LP, // from NE !!!!
-LEG_SKIPNNE_LP,

-LEG_SKIPN_LP,
LEG_SKIPNNE_LP,
LEG_SKIPNE_LP, // from NE !!!!
LEG_SKIPENE_LP,

LEG_SKIPE_LP,
LEG_SKIPESE_LP,
LEG_SKIPSE_LP,
LEG_SKIPSSE_LP,

//end
-LEG_SKIPS_END,
-LEG_SKIPSSE_END,
-LEG_SKIPSE_END,
-LEG_SKIPESE_END,

-LEG_SKIPE_END,
LEG_SKIPENE_END,
-LEG_SKIPNE_END,
LEG_SKIPNNE_END,

-LEG_SKIPN_END,
-LEG_SKIPNNE_END,
LEG_SKIPNE_END,
-LEG_SKIPENE_END,

LEG_SKIPE_END,
LEG_SKIPESE_END,
LEG_SKIPSE_END,
LEG_SKIPSSE_END,
};

#define	FSHU1_000	54
#define	FSHU1_022	49
#define	FSHU1_045	68
#define	FSHU1_067	71
#define	FSHU1_090	60
#define	FSHU1_112	48
#define	FSHU1_135	68
#define	FSHU1_157	51
#define	FSHU1_180	55

#define	SSHUS_000	16
#define	SSHUS_022	21
#define	SSHUS_045	26
#define	SSHUS_067	19
#define	SSHUS_090	19
#define	SSHUS_112	19
#define	SSHUS_135	16
#define	SSHUS_157	16
#define	SSHUS_180	16

#define	SSHUE_000	16	
#define	SSHUE_022	17
#define	SSHUE_045	22
#define	SSHUE_067	20
#define	SSHUE_090	21
#define	SSHUE_112	20
#define	SSHUE_135	17
#define	SSHUE_157	21
#define	SSHUE_180	16


SW shuffle_speed[3][16] =
{
	SSHUS_000, SSHUS_022, SSHUS_045, SSHUS_067,
	SSHUS_090, SSHUS_112, SSHUS_135, SSHUS_157,
	SSHUS_180, SSHUS_157, SSHUS_135, SSHUS_112,
	SSHUS_090, SSHUS_067, SSHUS_045, SSHUS_022,

	FSHU1_000, FSHU1_022, FSHU1_045, FSHU1_067,
	FSHU1_090, FSHU1_112, FSHU1_135, FSHU1_157,
	FSHU1_180, FSHU1_157, FSHU1_135, FSHU1_112,
	FSHU1_090, FSHU1_067, FSHU1_045, FSHU1_022,

	SSHUE_000, SSHUE_022, SSHUE_045, SSHUE_067,
	SSHUE_090, SSHUE_112, SSHUE_135, SSHUE_157,
	SSHUE_180, SSHUE_157, SSHUE_135, SSHUE_112,
	SSHUE_090, SSHUE_067, SSHUE_045, SSHUE_022,
};

static SW shuf_speed_map[] =
{
	0x0  ,0x8*8,0x8*8,0x9*8,
	0x9*8,0xa*8,0xa*8,0xb*8,
	0xb*8,0xc*8,0xc*8,0xd*8,
	0xd*8,0xe*8,0xe*8,0xf*8,0xf*8,
};

static SW shuf_speed_map2[] =
{
	72 , 72, 72, 82,
	192 , 82, 72, 72,
	72 , 72, 72, 82,
	90 , 82, 72, 72
};




void shuffle_from_run_init(playert *plyr)
{
SW a_diff;
int anim;
SW pangle;

	CallChainP(shuffle_from_run_init);

	plyr->shuffle = TRUE;
	plyr->last_speed = 0;

	// turn to the angle we will want the shuffle on...
	if (BALL_HANDLER) 	plyr->shuffle_target_angle = plyr->basket_angle^0x8000;
	else				set_shuffle_target_angle(plyr);

	//which direction are we turning
	a_diff = plyr->shuffle_target_angle - plyr->angle;

	pangle = plyr->angle;


	plyr->leg_rate = 0x280;

	if (a_diff > 0x4000)
	{
		anim   = -LEG_RUNSHUF;
		if (BALL_HANDLER)	pangle += 0x1800;
	}
	else if (a_diff < -0x4000)
	{
		anim   = LEG_RUNSHUF;
		if (BALL_HANDLER)	pangle -= 0x1800;
	}
	else
	{
		anim = LEG_RDY;
		start_blend_leg_anim(plyr, anim);
		plyr->leg_blend_speed = 0x20;
		plyr->leg_blend_ctr   = 0x1ff;
		plyr->leg_routine	  = shuffle_from_run2;
		shuffle_from_run2(plyr);
		return;
	}


	start_vels(plyr, (plyr->leg_anim == LEG_BACK) ? -45: 45, pangle);
	start_blend_leg_anim(plyr, anim);
	plyr->leg_routine = shuffle_from_run;
	shuffle_from_run(plyr);
}





void shuffle_from_run(playert *plyr)
{
SW  a_diff;
int turn_speed;
int max_turn_speed;
int time;
int ftg;
int angle, ad;

	CallChainP(shuffle_from_run);

	//let go of trigger ?
	if ((current_ctrlr->ctrlr & CTRL_SHUFFLE)==0)
	{
		if (plyr->control)
		{
			if (BALL_HANDLER)
			{
				angle = LFPAtn(plyr->xvel, plyr->yvel);

				a_diff = plyr->angle-angle;
				if (a_diff==0)
				{
					a_diff = plyr->shuffle_target_angle-plyr->angle;
					a_diff = (a_diff>0) ? 1:-1;
				}

				if (turbo_test(plyr, TURBO_SPIN))
				{
					if (a_diff>0)
					{
						//spin left
						start_blend_anim(plyr, -TOP_DRIB360);
						angle -= 0x2000;
						ad    = 0x10000 - ((plyr->angle-angle)&0xffff);
						ad    >>= 8;
						plyr->top_rate  = 0x160;
						plyr->top_frame = plyr->last_leg_frame;
						plyr->angle_vel = (ad*plyr->top_rate)/frames_to_go(plyr);
					}
					else
					{
						//spin right

						start_blend_anim(plyr, TOP_DRIB360);
						angle += 0x2000;
						ad    = -((plyr->angle-angle)&0xffff);
						ad    >>= 8;
						plyr->top_rate  = 0x160;
						plyr->top_frame = plyr->last_leg_frame;
						plyr->angle_vel = (ad*plyr->top_rate)/frames_to_go(plyr);
					}

					plyr->angle += plyr->angle_vel;
					start_vels(plyr, 80, (SW)angle);

					special_time = lp_ctr;

					SetMain(shuffle_from_run,plyr,spin_dribble);
					plyr->top_routine  = NULL;
					plyr->leg_routine  = NULL;

					if (ArcadeMode && MOM_MAX(plyr->team))
						ShowTrails=TRUE;

					return;
				}
			}
		}
		else
		{
			plyr->leg_routine = leg_deflt;
			leg_deflt(plyr);
			return;
		}
	}



	ftg = leg_frames_to_go(plyr);
	if (plyr->leg_rate==0)	plyr->leg_rate = 0x100;
	time = ((ftg - 1) << 8)/plyr->leg_rate;

	if (time <= 0)
	{
		start_shuffle(plyr);
		return;
	}

	max_turn_speed = (BALL_HANDLER) ? RUN_TURN: RUN_TURN/3;
	a_diff = plyr->shuffle_target_angle - plyr->angle;
	turn_speed = a_diff/time;

	if (turn_speed > max_turn_speed)		turn_speed = max_turn_speed;
	else if (turn_speed < -max_turn_speed)	turn_speed = -max_turn_speed;
	plyr->angle += turn_speed;

	if ((plyr->control == 0) || (!in_play_flag))
	{
		int xvel, yvel;

		//make player go exactly to target

		xvel = (plyr->target_x - plyr->xco)/time;
		if (abs(xvel - plyr->xvel) < 0x10000)
		{
			yvel = (plyr->target_y - plyr->yco)/time;
			if (abs(yvel - plyr->yvel) < 0x10000)
			{
				plyr->xvel = xvel;
				plyr->yvel = yvel;
			}
		}
	}
	plyr->col_flags = run_collision(plyr, plyr->xvel, plyr->yvel);

	if (plyr->col_flags != -1)
	{
		plyr->flags |= COLLIDE;
		collision_react(plyr, plyr->col_flags);
	}
}





void shuffle_from_run2(playert *plyr)
{
SW  a_diff;
int turn_speed;
int max_turn_speed;
int time;

	CallChainP(shuffle_from_run2);

	time = (plyr->leg_blend_ctr & 0xff)/ plyr->leg_blend_speed;
	if (time <= 0)
	{
		start_shuffle(plyr);
		return;
	}

	max_turn_speed = (BALL_HANDLER) ? RUN_TURN: RUN_TURN/3;
	a_diff = plyr->shuffle_target_angle - plyr->angle;
	turn_speed = a_diff/time;

	if (turn_speed > max_turn_speed)		turn_speed = max_turn_speed;
	else if (turn_speed < -max_turn_speed)	turn_speed = -max_turn_speed;
	plyr->angle += turn_speed;

	plyr->col_flags = run_collision(plyr, plyr->xvel, plyr->yvel);
	if (plyr->col_flags != -1)
	{
		plyr->flags |= COLLIDE;
		collision_react(plyr, plyr->col_flags);
	}
}



void start_shuffle(playert *plyr)
{
SW a_diff;

	CallChainP(start_shuffle);

	ctrlr_force = current_ctrlr->force;

	plyr->shuffle    = TRUE;
	plyr->pitch = 0;

	a_diff = ((current_ctrlr->d_angle - plyr->angle + 0x800) >> 12) & 0xf;
	plyr->shuffle_angle = a_diff;

/* start shuffle animation from standing entry */


	if (ctrlr_force > 0x10)
	{
		if (backward_test(plyr))
		{
			backward_init(plyr);
			return;
		}

		plyr->shuffle_stage = 0;
		start_leg_anim(plyr,shuffle_lookup[0][a_diff]);

		//save angle for moving in reference to
		plyr->angle2 = plyr->angle;
		plyr->leg_rate = 0;
		plyr->leg_routine = shuffling;
	}
/* if trigger pressed but joystick held still */
	else
	{
		start_blend_leg_anim(plyr, LEG_RDY);
		plyr->leg_routine = shuffle_stand;
		shuffle_stand(plyr);
	}
}



void shuffling(playert *plyr)
{
SW a_diff;
int speed;
SW turn_speed;

	CallChainP(shuffling);

	plyr->shuffle = TRUE;

/* take a local copy of the current controller force, cos we might modify it */

	ctrlr_force = current_ctrlr->force;

	if ( (ctrlr_force < 0x20) || (!(current_ctrlr->ctrlr & CTRL_SHUFFLE)) )
	{
		if (can_stop_shuffle(plyr))
		{
  			plyr->leg_routine = shuffle_stand;
			shuffle_stand(plyr);
			return;
		}
		else
		{
			current_ctrlr->d_angle = plyr->angle + (plyr->shuffle_angle<<12);
			ctrlr_force            = 0x20;
		}
	}

	//check for backwards
	if (backward_test(plyr))
	{
		backward_init(plyr);
		return;
	}

	// change the players angle. ie make face ball (or back to basket)

	set_shuffle_target_angle(plyr);
	a_diff = (SW)(plyr->shuffle_target_angle - plyr->angle);
	turn_speed = (BALL_HANDLER) ? 0x400: 0x800;

	if (a_diff < -turn_speed)	plyr->angle -= turn_speed;
	if (a_diff > turn_speed)	plyr->angle += turn_speed;

	check_anim_quick_change(plyr);

	// do the move and collision detection
	set_shuffle_speed(plyr);
	if (player[plyr->marker].basket_dist < 0x200000)
		current_ctrlr->force = 0x100;
	else
		current_ctrlr->force = 0x100 + ((0x200000 - player[plyr->marker].basket_dist) >> 15);
	run_collision(plyr,plyr->xvel,plyr->yvel);
	speed = MANHATTAN(plyr->xvel, plyr->yvel);

	if (speed > 0x4000)
	{
		//change animation if moving
		loop_shuffle_animation(plyr);
		plyr->leg_rate = (speed << 6)/
			(plyr->scale * shuffle_speed[plyr->shuffle_stage][plyr->shuffle_angle]);
	}
	else
	{
		//force next step to start at beginning
		plyr->leg_rate = 0;
		plyr->last_speed = 0;
		plyr->shuffle_stage = 2;
     	start_blend_leg_anim(plyr,LEG_RDY);
	}
}



/* if the button is pressed but the player is not moving the stick */

void shuffle_stand(playert * plyr)
{
SW a_diff;
int	an;

	CallChainP(shuffle_stand);

	if (!(current_ctrlr->ctrlr & CTRL_SHUFFLE))
	{
		plyr->leg_routine = leg_deflt;
		leg_deflt(plyr);
		return;
	}


	plyr->leg_rate=0x80;

	plyr->shuffle = TRUE;
 	ctrlr_force = current_ctrlr->force;

	plyr->xvel =
	plyr->yvel =
	plyr->last_speed = 0;

	if ((ctrlr_force>0x10) && (current_ctrlr->ctrlr & CTRL_SHUFFLE))
	{
		start_shuffle(plyr);
		return;
	}


	push_back(plyr,plyr->bumped_into_me);

	if (shuffle_stand_test(plyr))	return;

	if (ATTACKING)
	{
		//an=(plyr->no==ball_handler)? LEG_STDDRIB : LEG_RDY;
		an=LEG_RDY;
	}
	else
	{
		if (plyr->markee==ball_handler)
			an=flip_for_angle(plyr,sshuf_legs_tbl[2]);
		else
			an=sshuf_legs_tbl[is_boxing(plyr)];
	}

	if (plyr->leg_anim != an)
	{
     	start_blend_leg_anim(plyr,an);
	}

	if (!(current_ctrlr->ctrlr & CTRL_SHUFFLE))
	{
		plyr->leg_routine = leg_deflt;
		leg_deflt(plyr);
		return;
	}


	set_shuffle_target_angle(plyr);
  	a_diff = (plyr->shuffle_target_angle - plyr->angle);
    if		(a_diff > RUN_TURN/2)		a_diff = RUN_TURN/2;
	else if (a_diff < -RUN_TURN/2)		a_diff = -RUN_TURN/2;
	plyr->angle += a_diff;
}


/* now work out the new speeds */
void set_shuffle_speed(playert *plyr)
{
	SW	m_angle;
	SW	shuf_speed;
	static int ss[]={0xC0,0x100,0x110};

	//use angle2
	m_angle = plyr->angle2 + ((plyr->shuffle_angle<<12));

	if ((plyr->leg_blend_ctr > 0x100) && (plyr->control) && (in_play_flag) )
	{
		SW a_diff;

		a_diff  = (plyr->last_shuffle_angle - plyr->shuffle_angle) << 12;
		a_diff  = ((int)(a_diff) * (plyr->leg_blend_ctr & 0xff)) >> 8;
		m_angle += a_diff;
	}
	else
	{
		m_angle = current_ctrlr->d_angle;
	}


	if (ctrlr_force)
	{
		
		if (plyr->shuffle_stage != 1)
		{
			//start speed
			shuf_speed = 72;
		}
		else
		{
			//looped speed
			shuf_speed = shuf_speed_map[ctrlr_force>>4];
			switch(plyr->shuffle_angle)
			{
				case 3:
				case 5:
				case 11:
				case 13:
				shuf_speed+=shuf_speed/4;
				break;

				case 4:
				case 12:
				shuf_speed+=shuf_speed/3;
			}


		}

		if (BALL_HANDLER)
		{
			shuf_speed = (shuf_speed * (DRIB_FACT-0x40))>>8;
		}

#ifdef FLAG60
		shuf_speed = shuf_speed/2;
#endif

		if (!plyr->control && !ai_team[plyr->team].controllers[0])
			shuf_speed = (shuf_speed*ss[DIFFICULTY]) >> 8;

		plyr->xvel = (shuf_speed * LFPCos(m_angle)) >> 4;
		plyr->yvel = (shuf_speed * LFPSin(m_angle)) >> 4;
		plyr->last_speed = shuf_speed << 4;
	}
}



bool shuffle_stand_test(playert *plyr)
{

	if (!project_flag)
	{
		if (BALL_HANDLER)
		{
			if (plyr->basket_dist>0x600000)
			{
				if (plyr->main_routine == stand_with_ball)	return FALSE;
				if (plyr->main_routine == stand_with_ball2)	return FALSE;
			}
		}
		
		if (plyr->force==0)
		{
			if (plyr->bumped_into_me)
			{
				if ( ((playert *)(plyr->bumped_into_me))->shuffle)
				{
					int x,y;
					int speed;
					SW  angle;

					x = plyr->xco;
					y = plyr->yco;
					//shuffle_collide_react(plyr, (playert *)(plyr->bumped_into_me), &(plyr->xco), &(plyr->yco));
					x -= plyr->xco;
					y -= plyr->yco;

					plyr->bumped_into_me = 0;

					angle = LFPAtn(x,y) - plyr->angle;
					plyr->shuffle_angle = ((angle+0x800) >> 12) & 0xf;
					loop_shuffle_animation(plyr);

					plyr->leg_rate = (MANHATTAN(x,y) << 6)/
						(plyr->scale * shuffle_speed[plyr->shuffle_stage][plyr->shuffle_angle]);

					return TRUE;
				}
			}
		}
	}
	return FALSE;
}











int blend_speeds[9]={
	0x100/3,
	0x100/4,
	0x100/5,
	0x100/6,
	0x100/7,
	0x100/8,
	0x100/8,
	0x100/8,
	0x100/8
};



void check_anim_quick_change(playert * plyr)
{
SW a_diff;
SB change;

	//only allow blended changes for players not involved in collisions
	//otherwise wait until blending is finished

	//if ((plyr->leg_blend_ctr) && (plyr->bumped_into == 0) && (plyr->bumped_into_me == 0))	return;
	if ((plyr->leg_blend_ctr) && (plyr->bumped_into == 0))		return;

	a_diff	= ((current_ctrlr->d_angle - plyr->angle + 0x800) >> (7+5)) & 0xf;
	change  = a_diff - plyr->shuffle_angle;
	if (change == 0)			return;

	change = (change << 4);

	if (ctrlr_force > 0x10)			  /* controller not central */
	{
		plyr->last_shuffle_angle = ((change > 0x60) || (change < -0x60))
										? a_diff: plyr->shuffle_angle;
		plyr->shuffle_angle		 = a_diff;
		start_blend_leg_anim_shuffle(plyr, shuffle_lookup[plyr->shuffle_stage][a_diff]);
		plyr->leg_blend_speed = blend_speeds[abs(change)>>4];

		plyr->angle2 = plyr->angle;
	}
}


void loop_shuffle_animation(playert * plyr)
{
SW stage;

	if ((end_leg_animation_test(plyr)) || (abs(plyr->leg_anim) == LEG_RDY) ||
		( (abs(plyr->leg_anim)>=LEG_GUARD1) && (abs(plyr->leg_anim)<=LEG_GUARD4) ) )
  // anim finished?
	{
		switch (plyr->shuffle_stage)
		{
		case 2:
			stage = 0;
 			break;

		default:
		case 0:
		case 1:
			//how hard are we pushing
			//if fast then go to looping stage (1)	else end (2)
			stage = (ctrlr_force < 0x80) ? 2: 1;
			break;
		}

		plyr->shuffle_stage = stage;

		if (plyr->leg_blend_ctr == 0)
		{
			plyr->last_leg_anim  = plyr->leg_anim;
			plyr->last_leg_frame = plyr->leg_frame;
		}
		else
		{
			plyr->last_leg_anim  = shuffle_lookup[stage][plyr->last_shuffle_angle];
			plyr->last_leg_frame = 0;
		}

		plyr->leg_anim  = shuffle_lookup[stage][plyr->shuffle_angle];
		plyr->leg_frame = 0;
	}
}



void set_shuffle_target_angle(playert *plyr)
{
//	plyr->shuffle_target_angle = 0xc000;
//	return;

	if (BALL_HANDLER)  // do I have the ball?
	{
		plyr->shuffle_target_angle = (plyr->basket_angle^0x8000)+(SW)(plyr->angle-plyr->ball_angle);
//		plyr->shuffle_target_angle = plyr->basket_angle ^ 0x8000;
  
	}
	else
	{
		if ( (ball.main_routine == shot_ball_move) || ((plyr->control) && (current_ctrlr->ctrlr & CTRL_BOX_OUT)) )
		{
			//box out
			plyr->shuffle_target_angle = plyr->basket_angle;
		}
		else
		{
			// face the ball
			if (!possession_flag)	plyr->shuffle_target_angle = plyr->ball_angle;
			else					plyr->shuffle_target_angle = LFPAtn(bhp->xco-plyr->xco, 
																		bhp->yco-plyr->yco);
		}
	}
}



bool can_stop_shuffle(playert *plyr)
{
	if ((plyr->control) && (in_play_flag))
	{
		if (plyr->leg_anim==LEG_RDY)
			return TRUE;

		if (abs(plyr->leg_anim)>=LEG_GUARD1 && abs(plyr->leg_anim)<=LEG_GUARD4)
			return TRUE;

		switch (plyr->shuffle_stage)
		{
		case 0:
			//have i gone too far?
			return (plyr->leg_frame < 0xc00);

		case 1:
			//fast shuffle must be in middle of animation
			return ((plyr->leg_frame >= 0x600) && (plyr->leg_frame <= 0xe00));

		case 2:
			//have i gone far enough to stop?
			return (plyr->leg_frame > 0x800);
		}
		return 0;
	}
	else
	{
		return 1;
	}
}






