
#include "lfptypes.h"
#include "define.h"
#include "ml.h"

#include "main.h"
#include "audio.h"
#include "comment.h"


#include "gamefx.h"

extern u8
	*GameBank;


typedef struct _FoulEvent
	{
	int	type;		// Foul type
	int	time;		// lp_ctr when the incident occured
	int	fouler;		// Index of player committing the foul
	int	foulee;		// Index of the player getting fouled
	} FoulEvent;

#define	FE_SIZE	50			// Number of elements in the fouler array

FoulEvent	FoulHistory[FE_SIZE];
int			FoulIndex=0;

#define	FE_FOUL(ty,t,fr,to)		\
			FoulHistory[FoulIndex].type=(ty);		\
			FoulHistory[FoulIndex].time=(t);		\
			FoulHistory[FoulIndex].fouler=(fr);	\
			FoulHistory[FoulIndex].foulee=(to);	\
			if (++FoulIndex==FE_SIZE) FoulIndex=0;


/**/
/**/
/**/

int fouler;
int foul_flag;
int foul_flag2;

int		fy;
int		fx;
bool	ufy;

static u8 HackSound=0;

void foul_check(void)
{
	if (project_flag)	return;
	
	if (!foul_flag2)	return;

	if ((ball.main_routine == shot_ball_move) || (dunk_flag) || shoot_stage)	return;

	if (possession_flag && bhp->zco)
		return;

#if defined(DEBUG)
	{
		int		i;
		char	txt[128];
		char	num[16];

		for (i=0; i<16; i++)
			num[i]=0;

		IntToDecStr(lp_ctr,num);
		sprintf(txt,"%s: foul_check %d\n",num,foul_flag2);
		PCwrite(-1,txt,strlen(txt));
	}
#endif

	time_rate=0x100;

	if (foul_flag2==CHARGING)
	{
		foul_flag2 = 0; 
		foul_set(player+fouler, CHARGING);
	}
	else if ((foul_flag2 == FLAGRANT) && (free_thrower !=last_shooter))
	{
		foul_flag2 = 0; 
		foul_set(player+fouler, FLAGRANT);
	}
	else if (foul_flag2==SHOT_CLOCK)
	{
		foul_flag2=0;
		ufy=TRUE;
		foul_set(bhp,foul_flag2);
		ufy=FALSE;
		SetHalfFlag(foul_check,FALSE);
	}
	else
	{
		foul_flag2 = 0; 
		if (scored_flag)
		{
			foul_set(player+fouler, HACKING1);
		}
		else
		{
			foul_set(player+fouler, pt3_flag? HACKING3 : HACKING2);
		}

		free_thrower = ball_handler;
	}
}




int BestFT(int t)
{
	int	s,e,i,p,h;

	s=(t)? 1 : 6;
	e=s+4;

	p=s-1;
	h=player[p].plyrROM->ub___pAttrFT;

	for (i=s; i<e; i++)
		if (player[i].plyrROM->ub___pAttrFT>h)
		{
			h=player[i].plyrROM->ub___pAttrFT;
			p=i;
		}

	return p;
}


void CheckForFoulingOut(playert *plyr);


void foul_set (playert *plyr, int foul_type)
{
	if (ArcadeMode && foul_type!=SHOT_CLOCK && foul_type!=OUT_OF_BOUNDS)
		return;

	crossX = crossY = 0;

	if (time_left <= 0)
		switch(foul_type)
		{
			case HACKING1:
			case HACKING2:
			case HACKING3:
				break;

			default:
				return;
		}

	if (foul_flag2)		return;

	if (foul_type==OUT_OF_BOUNDS && (!BOUNDARIES || C3PT))
	{
		if (!possession_flag)
			shove_back_inbound(&ball);

		return;
	}

	switch (foul_type)
	{
	//whistle (buzzer sounded already for shot clock)
	//hacking blown already
	case SHOT_CLOCK:
	case HACKING1:
	case HACKING3:
		break;

	case HACKING2:
		if (HackSound)
			break;

		HackSound=1;

	default:
//old		AudioPlaySfx(SFX_ID_WHISTLE,22050,255,7);
		Audio_SfxPlay( GameBank, SFX_WHISTLE, SfxVolume );
	}


	foul_flag = foul_type;
	fouler    = plyr->no;

	if (foul_type!=OVER_THE_TOP)
		if ((ball.main_routine == shot_ball_move) || (dunk_flag) || ((shoot_stage) && !(foul_type==SHOT_CLOCK || foul_type==TEN_SECOND)) )
		{
			foul_flag2 = foul_type;
			return;
		}

	HackSound=0;

	if (possession_flag && bhp->zco && foul_type==SHOT_CLOCK)
	{
		fx=ball.xco;
		fy=ball.yco;
		foul_flag2=foul_type;
		return;
	}

	got_pos_flag = FALSE;
	in_play_flag = FALSE;
	time_flag    = FALSE;
	SetDunkFlag(foul_set,FALSE);
	pass_flag    = FALSE;
	fast_break_flag = FALSE;

	if (ball.main_routine == pass_ball_move)
	{
		set_default(player+int_recvr);
	}

	#ifdef N64
	CamStopSpecial();
	#endif

//place ball at edge of court
	if (ufy)
	{
		ball.target_x=(fx > 0) ? SIDE_LINE+(EDGE/2): -SIDE_LINE-(EDGE/2);
		ball.target_y=fy;
	}
	else
	{
		ball.target_x = (ball.xco > 0) ? SIDE_LINE+(EDGE/2): -SIDE_LINE-(EDGE/2);
		ball.target_y = ball.yco;
	}

	//last_handler = plyr->no;

	switch(inbounds_flag)
	{
	case 1:
	case 2:
		ball.target_x = (ball.xco > 0) ? SIDE_LINE/2: -SIDE_LINE/2;
		ball.target_y = (ball.yco < 0) ?-BASE_LINE-EDGE: BASE_LINE+EDGE;
		break;

	case 3:
	case 4:
		ball.target_x = (ball.xco < 0) ?-SIDE_LINE-EDGE: SIDE_LINE+EDGE;
		if (ball.target_y > BASKET_Y)	ball.target_y = BASKET_Y;
		if (ball.target_y < -BASKET_Y)  ball.target_y = -BASKET_Y;
		break;

	}

	scored_flag = 0;
	free_throws = 0;

	switch (foul_type)
	{
	case THREE_SECOND:
	case TEN_SECOND:
	case FIVE_SECOND:
	case SHOT_CLOCK:
		SetLastHandler(foul_set,plyr->no);
		SetHalfFlag(foul_set,FALSE);
		plyr->teamRAM->cl___tStatGame.uw___tTO++;
		break;

	case CHARGING:
		SetLastHandler(foul_set,plyr->no);
//old		AudioPlayCrowdSfx(AUDIO_CROWD_ROWDY+(lp_ctr&1));
		stats_foul(plyr,FOUL_TYPE_OFFENSIVE);
//		ai_team[plyr->no/5].fouls_left += 1;  stats_fouls won't dec anymore
		stats_TO(plyr);
		break;

	case FLAGRANT:
		if (++plyr->plyrRAM->ExtraPlayerGameStats.FlagrantFouls==2)
			CheckForFoulingOut(plyr);	//	plyr->plyrRAM->cl___pStatGame.ub___pDQ=1;

		SetLastHandler(foul_set,plyr->no);
//old		AudioPlayCrowdSfx(AUDIO_CROWD_ROWDY+(lp_ctr&1));
		stats_foul(plyr,FOUL_TYPE_DEFENSIVE);
		free_throws=2;
		break;

	case ILLEGAL_DEFENSE:
		if (++ai_team[fouler/5].illegalD>1)	// Has this foul occurred before?
		{
			//foul_flag=TECHNICAL;
			//free_thrower=ball_handler;	// choose technical guy here
			free_thrower=BestFT(bhp->team^1);
			free_throws=1;
		}
		else
			last_handler=fouler;	// Not true, but gives the ball to the right team

		break;

	case REACHING_IN:
		SetLastHandler(foul_set,plyr->no);
//old		AudioPlayCrowdSfx(AUDIO_CROWD_ROWDY+(lp_ctr&1));
		stats_foul(plyr,FOUL_TYPE_DEFENSIVE);
		if ((ai_team[fouler/5].fouls_left < 0) || (shoot_stage==2))	free_throws=2;
		break;

	case TECHNICAL:
		//say technical foul
		SetLastHandler(foul_set,plyr->no);
//old		AudioPlayCrowdSfx(AUDIO_CROWD_ROWDY+(lp_ctr&1));
		free_throws=1;
		free_thrower=BestFT(plyr->team^1);
		break;

	case HACKING1:
	case HACKING2:
	case HACKING3:
//old		AudioPlayCrowdSfx(AUDIO_CROWD_ROWDY+(lp_ctr&1));
		free_throws = (1+foul_type-HACKING1);
		stats_foul(plyr,FOUL_TYPE_DEFENSIVE);
		break;

	case HALF_COURT:
	case OUT_OF_BOUNDS:
		SetLastHandler(foul_set,plyr->no);

		if (plyr->no==last_handler && plyr->no==last_shooter && !possession_ticks)	// Don't charge a shooter for out of bounds
			break;

		if (plyr->no==last_handler && plyr->no==last_blocker)
			break;

		if (possession_ticks>1 && last_handler!=last_blocker)
		{
			turn_over();
		}
		else if (plyr->no/5 == last_handler/5)
		{
			turn_over();
		}

		if (foul_type==HALF_COURT)
			SetHalfFlag(foul_set,TRUE);

		break;

	default:
		break;
	}

	if (foul_type<OUT_OF_BOUNDS)
	{
		new_shot_clock();
	}


	if (free_throws)
	{
		ball.target_x = 0;
		ball.target_y = (plyr->no > 4) ? FOUL_LINE+EDGE:-FOUL_LINE-EDGE;
	}


	if (possession_flag)	drop_ball(bhp);
	start_drop_bounce(&ball);

	tempo=mtempo;		// Always make sure that slo-mo is turned off

	last_bx  = ball.xco;
	last_by  = ball.yco;

	if (ball.zco<0x100000)	ball.zco = 0x100000;
	last_bz  = ball.zco;

	ball.xvel = ball.yvel = ball.zvel = 0;

	Comment( COMMENT_FOUL, plyr, foul_type );
}


UB fouls_ok[4]={
1,
2,
3,
5,
};

bool foul_trouble(playert *plyr)
{
int q;

	q = pcl__gMatch->sb___mQuarter;
	if (q>3)	q=3;
	return (plyr->plyrRAM->cl___pStatGame.uw___pPF > fouls_ok[q]);
}


#if defined(DEBUG)

void _FoulSet
		(
		char	*routine,
		playert	*plyr,
		int		foul_type
		)
{
	int		i;
	char	txt[128];
	char	num[16];

	static char *FoulTxt[]=
					{
					"None",
					"Hacking1",
					"Hacking2",
					"Hacking3",
					"ReachingIn",
					"Flagrant",
					"Charging",
					"Technical",
					"Travelling",
					"ThreeSecond",
					"TenSecond",
					"FiveSecond",
					"ShotClock",
					"HalfCourt",
					"IllegalDefense",
					"OutOfBounds",
					"OverTheTop"
					};

	for (i=0; i<16; i++)
		num[i]=0;

	IntToDecStr(lp_ctr,num);
	sprintf(txt,"%s: foul_set(%d,%s) [%s]\n",num,plyr->no,FoulTxt[foul_type],routine);
	PCwrite(-1,txt,strlen(txt));

	foul_set(plyr,foul_type);
}
	
#endif
