
#include "generic.h"
#include "lfptypes.h"
#include "misc.h"
#include "define.h"
#include "ml.h"

#include "playgfx.h"


#define STEAL_TIME 4
#define FOUL_TIME  5


bool	can_steal=CAN_STEAL;

static int steal_z;		//projected z of ball when steal pressed

/*
 * steal has been pressed. can i do it?
 */


void limit_acel(playert *plyr, int xvel, int yvel, int limit)
{
int x_diff, y_diff;
int dvel;

	//limit the acceleration
	x_diff = xvel - plyr->xvel;
	y_diff = yvel - plyr->yvel;

	dvel = MANHATTAN(x_diff, y_diff);
	if (dvel > limit)
	{
		int frac;

		frac = (limit<<8)/dvel;

		xvel = ((frac * x_diff) >> 8) + plyr->xvel;
		yvel = ((frac * y_diff) >> 8) + plyr->yvel;
	}
	plyr->xvel = xvel;
	plyr->yvel = yvel;
}




void foul_start(playert *plyr)
{
playert *op;
int lowest_score;
int foulee;

	CallChainP(foul_start);

	lowest_score = 0x7fffffff;
	foulee       =
	plyr->pickee = -1;



	for (op=player+bhp->base; op<player+bhp->base+5; op++)
	{
		int x_diff, y_diff;
		SW  a_diff;

		x_diff = op->xco - plyr->xco;
		y_diff = op->yco - plyr->yco;

		a_diff = plyr->angle - LFPAtn(x_diff, y_diff);

		if (abs(a_diff) < 0x4000)
		{
			int dist;

			dist = MANHATTAN(x_diff, y_diff);
			if (dist < 0x300000)
			{
				int score;

				score = dist + (abs(a_diff)*0x40);
				if (op==bhp)	score -= 0x180000;

				if (score < lowest_score)
				{
					lowest_score = score;
					foulee		 = op->no;
				}
			}
		}
	}

	if (foulee >= 0)
	{
		plyr->pickee = foulee;

		start_blend_anim2(plyr, TOP_FOUL1, FOUL_TIME);

		plyr->ctr2         = FOUL_TIME;
		SetMain(foul_start,plyr,foul_rou);
		plyr->top_routine  = NULL;
		plyr->leg_routine  = foul_move;

		foul_rou(plyr);
	}
}



void foul_move(playert *plyr)
{
SW  target_angle;
SW  move_angle;
SW  a_diff;
int speed;

	CallChainP(foul_move);

	if (BALL_HANDLER)
	{
		BRK;
		plyr->leg_routine=leg_deflt;;
		return;
	}

	collision(plyr, plyr->xvel, plyr->yvel, COL_DI);
	target_angle = LFPAtn(player[plyr->pickee].xco - plyr->xco,
						  player[plyr->pickee].yco - plyr->yco);
	turn_to(plyr, target_angle);

	if ((plyr->ctr2 == FOUL_TIME) && (speed > 0x4000))
	{
		move_angle = LFPAtn(plyr->xvel, plyr->yvel);
		plyr->shuffle_angle =
		a_diff				= ((move_angle - plyr->angle + 0x800) >> 12) & 0xf;

		if (plyr->leg_anim == LEG_RDY)
		{
			start_leg_anim(plyr, shuffle_lookup[0][a_diff]);
		}
		else
		{
			start_blend_leg_anim(plyr, shuffle_lookup[0][a_diff]);
		}

		speed = MANHATTAN(plyr->xvel, plyr->yvel);
		plyr->leg_rate = (speed << 6)/
			(plyr->scale * shuffle_speed[plyr->shuffle_stage][plyr->shuffle_angle]);
	}

	plyr->ctr2--;
}


void foul_rou(playert *plyr)
{
int x_diff, y_diff;
int x_vel, y_vel;
int dvel;

	CallChainP(foul_rou);

	if ((!in_play_flag) || (foul_flag2) || (pass_flag))
	{
		set_default(plyr);
		return;
	}

	if (plyr->ctr2 > 0)
	{
//		project(player+plyr->pickee, plyr->ctr2, FALSE);

		plyr->target_x = player[plyr->pickee].xco;
		plyr->target_y = player[plyr->pickee].yco;

		x_diff = plyr->target_x - plyr->xco;
		y_diff = plyr->target_y - plyr->yco;

		x_vel = x_diff/plyr->ctr2;
		y_vel = y_diff/plyr->ctr2;

		limit_acel(plyr, x_vel, y_vel, 0x10000);

		if (plyr->control && (current_ctrlr->ctrlr & CTRL_FOUL) == 0)
		{
			set_default(plyr);
			return;
		}
	}
	else
	{
		int dist;

		plyr->xvel = 0;
		plyr->yvel = 0;

		dist = MANHATTAN(player[plyr->pickee].xco - plyr->xco,
						 player[plyr->pickee].yco - plyr->yco);

		start_next_anim(plyr);
		start_blend_leg_anim(plyr, LEG_RDY);
		SetMain(foul_rou,plyr,foul_over);
		plyr->leg_routine  = NULL;
		if (plyr->ikBlend && plyr->ikBlendSpeed>=0)
			plyr->ikBlendSpeed=-plyr->ikBlend/6;

		if (!(pass_flag || ball.main_routine==pass_ball_move) || plyr->pickee!=int_recvr)
			if ( (in_play_flag) && (foul_flag2==0) )
				if (dist < 0x140000 && player[plyr->pickee].zco<0x108000)
				{
					if ((plyr->pickee==ball_handler))
					{
						if (DEFENSIVE_FOULS!=0)
						{
							if (plyr->zco)
							{
								if (shoot_stage)
									FoulSet(foul_rou,plyr, HACKING2);
							}
							else
								FoulSet(foul_rou,plyr, REACHING_IN);
						}
						if (dunk_flag)
						{
							SetDunkFlag(foul_rou,FALSE);
							tempo=mtempo;
						}
					}
					else
					{
						if (!bhp->zco)	// Limitation due to drop_ball(), truly extraneous to situation
							if (DEFENSIVE_FOULS!=0 && !shoot_stage && !dunk_flag)
								FoulSet(foul_rou,plyr,FLAGRANT);
					}
					free_thrower = plyr->pickee;
					start_fall(player+plyr->pickee, (SW) (LFPAtn(player[plyr->pickee].xco - plyr->xco,
																 player[plyr->pickee].yco - plyr->yco) - 0x8000));
				}
	}
}



void foul_over(playert *plyr)
{
	CallChainP(foul_over);

	if (end_animation_test(plyr))
	{
		start_anim (plyr, TOP_RDY);

		SetMain(foul_over,plyr,deflt);
		plyr->leg_routine  = leg_deflt;
		plyr->top_routine  = top_deflt;
	}
}



bool steal_test(playert *plyr)
{
SW a_diff;
int x_diff, y_diff;
int v_diff;
int threshold;

	if (!plyr->control && !can_steal)
		return FALSE;

#ifdef DEBUG
//	return FALSE;
#endif

	//don't try to steal from out of bounds play
	if (!in_play_flag)					return FALSE;

	//does anyone have the ball?
	if (!possession_flag)				return FALSE;

	if (lp_ctr-special_time < ONE_SEC)	return FALSE;

	//am i facing the ball
	a_diff = plyr->angle - plyr->ball_angle;
	if (abs(a_diff) > 0x4000)			return FALSE;

	//am I close enough to ball to make attempt a steal
	if (plyr->ball_dist > 0x1c0000)		return FALSE;


	if (ball.zco > 0x180000)
	{
		if (plyr->top_anim != TOP_GRDH)
		{
			return FALSE;
		}
	}
	else
	{
		//don't come through ball handler
		a_diff = bhp->ball_angle - plyr->ball_angle;
		threshold = (bhp->last_speed) ? 0x5000: 0x4000;
		
		if (abs(a_diff) < threshold)		return FALSE;
	}

	//if ball handler in the air
	project(bhp, STEAL_TIME, FALSE);
	if (DUMMY.zco)						return FALSE;

	PlayGfxEvalBall(&DUMMY, &x_diff, &steal_z, &y_diff);

	if (steal_z > 0x180000)
	{
		if ((plyr->top_anim != TOP_LOW_TO_HI) && (plyr->top_anim != TOP_GRDH))
		{
			return FALSE;
		}
	}

	x_diff -= plyr->xco + (LFPCos(plyr->angle) * 0x40);
	y_diff -= plyr->yco + (LFPSin(plyr->angle) * 0x40);

	v_diff = MANHATTAN(plyr->xvel - (x_diff/STEAL_TIME), plyr->yvel - (y_diff/STEAL_TIME));

	//limit on how much change in velocity we are prepared to tolerate.
	//adjust for player ratings?
	return (v_diff < 0x40000);
}





void steal_start(playert *plyr)
{
SW a_diff;
int anim;

	CallChainP(steal_start);

	if (bhp->zco==0)
	{
		plyr->ctr2 = STEAL_TIME;

		if (plyr->control)
		{
			int x_diff, y_diff;

			project(bhp, 4, FALSE);
			PlayGfxEvalBall(&DUMMY, &x_diff, &steal_z, &y_diff);
		}

		if (steal_z > 0x180000)
		{
			anim = TOP_STEALH1;
		}
		else
		{
			anim = abs(DUMMY.top_anim);
			anim = (anim > TOP_HIGH_DRIB) ? TOP_STEALD1: TOP_STEAL1;
		}

		//decide which hand to use
		a_diff = plyr->angle - plyr->ball_angle;
		if (a_diff<0)		anim = -anim;

		start_blend_anim2(plyr, anim, STEAL_TIME);

		SetMain(steal_start,plyr,steal_rou);
		plyr->top_routine  = NULL;
		plyr->leg_routine  = steal_move;

		steal_rou(plyr);
	}
}


/*
 * leg routine for stealing players
 */

void steal_move(playert *plyr)
{
SW  target_angle;
SW  move_angle;
SW  a_diff;
int speed;

	CallChainP(steal_move);

	plyr->xco += plyr->xvel;
	plyr->yco += plyr->yvel;

	target_angle = LFPAtn(plyr->target_x - plyr->xco, plyr->target_y - plyr->yco);
	turn_to(plyr, target_angle);

	speed = MANHATTAN(plyr->xvel, plyr->yvel);

	if ((plyr->ctr2 == STEAL_TIME) && (speed > 0x4000))
	{
		move_angle = LFPAtn(plyr->xvel, plyr->yvel);
		plyr->shuffle_angle =
		a_diff				= ((move_angle - plyr->angle + 0x800) >> 12) & 0xf;

		if (plyr->leg_anim == LEG_RDY)
		{
			start_leg_anim(plyr, shuffle_lookup[0][a_diff]);
		}
		else
		{
			start_blend_leg_anim(plyr, shuffle_lookup[0][a_diff]);
		}

		plyr->leg_rate = (speed << 6)/
			(plyr->scale * shuffle_speed[0][plyr->shuffle_angle]);
	}

	plyr->ctr2--;
}





void steal_rou(playert *plyr)
{
int bx, by, bz;
int px, py, pz;
int x_diff, y_diff;
int x_vel, y_vel;
int saved_blend_ctr;
int	pctH,pctM,pctL;

	CallChainP(steal_rou);

	if ((pass_flag) || (!possession_flag) || (!in_play_flag))	goto stop_steal;

	if (plyr->ctr2 > 0)
	{
		project(bhp, plyr->ctr2, FALSE);

		PlayGfxEvalBall(&DUMMY, &bx, &bz, &by);

		//don't try to steal from someone in the air
		if (DUMMY.zco > 0)	goto stop_steal;

		// Don't try to steal if ball is not in play
		if (!in_play_flag)
			goto stop_steal;

		saved_blend_ctr     = plyr->top_blend_ctr;
		plyr->top_blend_ctr = 0;
		PlayGfxEvalBall(plyr, &px, &pz, &py);
		plyr->top_blend_ctr = saved_blend_ctr;

		x_diff = bx - px;
		y_diff = by - py;

		plyr->target_x = bx;
		plyr->target_y = by;

		x_vel = x_diff/plyr->ctr2;
		y_vel = y_diff/plyr->ctr2;

		//limit the acceleration
		x_diff = x_vel - plyr->xvel;
		y_diff = y_vel - plyr->yvel;

		limit_acel(plyr, x_vel, y_vel, 0x10000);
	}
	else
	{
	int dist;

		plyr->xvel = 0;
		plyr->yvel = 0;

		plyr->top_blend_ctr = 0;
		PlayGfxEvalBall(plyr, &px, &pz, &py);

		dist = MANHATTAN(px - ball.xco, py - ball.yco);

		start_next_anim(plyr);
		start_blend_leg_anim (plyr, LEG_RDY);
		SetMain(steal_rou,plyr,steal_over);


		if (!project_flag)
		{
			if (dist < 0x60000 && !(shoot_stage && bhp->control) )
			{
				int foul_rating;
				int pickup_rating;
				int steal_rating;
				int nothing_rating;
				int random;
				SW  a_diff;

				foul_rating = 0;

				a_diff=LFPAtn(plyr->xco-bhp->xco,plyr->yco-bhp->yco)-bhp->angle;
				if (abs(a_diff)>0x4000 && DEFENSIVE_FOULS)
				{
					if (plyr->plyrROM->ub___pAttrSteal+rand()%50<bhp->plyrROM->ub___pAttrDribble+rand()%20)
					{
						SetDunkFlag(steal_rou,FALSE);
						if (bhp->control)	CtrlMotorOn(bhp->control-1, 2);
						FoulSet(steal_rou,plyr, REACHING_IN);
						free_thrower = bhp->no;
						if (CAMERAS==1)	CameraSpecialEnd();
					}
					return;
				}

				a_diff = LFPAtn(bhp->xco - ball.xco, bhp->yco - ball.yco) -
						 LFPAtn(plyr->xco - ball.xco, plyr->yco - ball.yco);

				a_diff = abs(a_diff);

				pctH=(PLY(bhp)>0)? 50 : 15;
				pctM=(PLY(bhp)>0)? 30 : 7;
				pctL=(PLY(bhp)>0)? 10 : 2;

				if (a_diff < 0x2000)
				{
					a_diff = MIN_MAX2(a_diff, 0, 0x2000, pctH, pctM);
					status_var4 = a_diff;
					foul_rating = DEFENSIVE_FOULS*a_diff;
				}
				else if (a_diff < 0x4000)
				{
					a_diff = MIN_MAX2(a_diff, 0x2000, 0x4000, pctM, pctL);
					status_var4 = a_diff;
					foul_rating = DEFENSIVE_FOULS*a_diff;
				}

				steal_rating   = plyr->plyrROM->ub___pAttrSteal + (100-bhp->plyrROM->ub___pAttrDribble);

				if (!half_flag)	steal_rating /= 2;
				if (bhp->main_routine==standing_crossover || bhp->main_routine==crossover)
					steal_rating*=2;
				nothing_rating = (200-steal_rating)/2;
				pickup_rating  = (200-steal_rating)/2;
				
				switch (abs(bhp->top_anim))
				{

				//definite steals
				case TOP_OVER_BALL:
				case TOP_BALL_DOWN:
				case TOP_PVT2F:
				case TOP_PVT2B:
				case TOP_OP1:
				case TOP_OPR1:
				case TOP_SPIN180:

					pickup_rating  = 0;
					nothing_rating = 0;
					foul_rating    = 0;
					break;

				case TOP_PRT_DRIBL:
				case TOP_PRT_DRIB:
					pickup_rating +=steal_rating/2; 
					steal_rating  = steal_rating/4;
					break;

				case TOP_STAND_BALL:
					pickup_rating = 0;
					break;

				//low steal likelyhood
				case TOP_STDCROSS:
				case TOP_STDXL1:
				case TOP_STDXL2:
				case TOP_STDXR1:
				case TOP_STDXR2:

					steal_rating  = steal_rating/2;
					pickup_rating = 0;
					break;

				//hi steal tops
				case TOP_STD_DRIBC:
				case TOP_PRT_DRIBC:
				case TOP_WALK_DRIBC:
				case TOP_JOG_DRIBC:
				case TOP_RUN_DRIBC:
				case TOP_RUN_DRIB2C:
				case TOP_TURBO_DRIBC:
				case TOP_STIFF_DRIBC:
				case TOP_LOW_DRIBC:
				case TOP_HIGH_DRIBC:
				case TOP_TURBO_DRIB:
				case TOP_DRIB_BB:
				case TOP_DRIB180:

					steal_rating *= 2;
					break;
				}					

				// Do not steal ball if handler is doing fancy dribble crap
				if (bhp->main_routine==first_step)
				{
					pickup_rating  = 0;
					nothing_rating = 0;
					foul_rating    = 0;
					steal_rating=0;
				}


#ifdef DEBUG
				//foul_rating = 0;
				//nothing_rating = 100;
				//pickup_rating = 100;
				//steal_rating = 0;
#endif

				//nothing_rating*=2;
				foul_rating/=2;
				//steal_rating/=2;
				pickup_rating/=2;

				random = ((foul_rating+nothing_rating+pickup_rating+steal_rating) * ReadRnd250()) >> 8;

				if (random<steal_rating)
				{
					SetDunkFlag(steal_rou,FALSE);
					if (bhp->control)	CtrlMotorOn(bhp->control-1, 2);
//old					AudioPlaySfx(SFX_ID_STEAL,22050,STEAL_VOL,7);
					steal_flag = TRUE;
					drop_ball(bhp);
					SetLastHandler(steal_rou,plyr->no);
					loseball_commentary( bhp, plyr );
					if (CAMERAS==1)	CameraSpecialEnd();
				}
				else if (random < steal_rating+foul_rating)
				{
					SetDunkFlag(steal_rou,FALSE);
					if (bhp->control)	CtrlMotorOn(bhp->control-1, 2);
					FoulSet(steal_rou,plyr, REACHING_IN);
					free_thrower = bhp->no;
					if (CAMERAS==1)	CameraSpecialEnd();
				}
				else if (random < steal_rating+foul_rating+pickup_rating)
				{
					SetDunkFlag(steal_rou,FALSE);
					if (plyr->control)	CtrlMotorOn(plyr->control-1, 2);
					do_grunt();
					pickup_dribble(bhp);
					if (CAMERAS==1)	CameraSpecialEnd();
				}
			}
		}
	}

	if (plyr->ikBlend && plyr->ikBlendSpeed>=0)
		plyr->ikBlendSpeed=-plyr->ikBlend/6;

	return;

stop_steal:
	if (plyr->ikBlend && plyr->ikBlendSpeed>=0)
		plyr->ikBlendSpeed=-plyr->ikBlend/6;

	SetMain(steal_rou,plyr,deflt);
	plyr->top_routine  = top_deflt;
	plyr->leg_routine  = leg_deflt;
	start_blend_leg_anim(plyr, LEG_RDY);
}




void steal_over(playert *plyr)
{
	CallChainP(steal_over);

	if (end_animation_test(plyr))
	{
		start_anim (plyr, TOP_RDY);

		SetMain(steal_over,plyr,deflt);
		plyr->leg_routine  = leg_deflt;
		plyr->top_routine  = top_deflt;
	}
}

/*
 * ball stolen from this player.
 */

void steal_react(playert *plyr)
{
	CallChainP(steal_react);

	current_ctrlr->force = 0;

	plyr->top_routine = NULL;

	//if (playerAnims[abs(plyr->top_anim)].loopFlag)	BRK;

	if (end_animation_test(plyr))
	{
		start_blend_anim(plyr, TOP_RDY);
		start_blend_leg_anim(plyr, LEG_RDY);

		plyr->leg_routine = leg_deflt;
		plyr->top_routine = top_deflt;
		SetMain(steal_react,plyr,deflt);
	}
}


void pickup_dribble(playert *plyr)
{
	CallChainP(pickup_dribble);

	if (!project_flag)
	{
		if (plyr->control)	CtrlMotorOn(plyr->control-1, 2);
		SetMain(pickup_dribble,plyr,stand_with_ball);
		plyr->leg_routine  = leg_deflt;
		SetDunkFlag(pickup_dribble,FALSE);
		pass_flag = FALSE;

		//discourage repeat attempts
		steal_ticks  = 0;		
		SetDribbleFlag(pickup_dribble,2);
		start_blend_anim(plyr, TOP_STAND_BALL);

		if (CAMERAS==1)	CameraSpecialEnd();

		reset_play();
	}
}

