

#include <stdio.h>
#include <io.h>
#include <system.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include "poolcue.h"
#include "poolball.h"
#include "keyboard.h"

#define VC_MAX 3200
#define ACC 100
#define pi 3.1415926
#define angle_trans 0.05236   //!WXC
#define zero 0.0001
#define n_zero -0.0001
#define sq_zero 0.01
#define PRODUCT 0.34    // PRODUCT = dx * vc , when dx = min(zero), vc = vc_max
#define edge_acc 0.95


//Audio
//1 = loud; 2 = low
#define IOWR_AUDIO_EN(data)\
		IOWR_8DIRECT(AUDIO_0_BASE, 0, data);

//Write to vga ram
#define IOWR_VGA_STRENGTHBAR(data) \
	IOWR_16DIRECT(DE2_VGA_RASTER_0_BASE, 128, data)
#define SERVELINE_EN(flag)\
	IOWR_16DIRECT(DE2_VGA_RASTER_0_BASE, 130, flag)

//Words
//Enable
//6:WIN! ; 5: GAME ; 4: NEW ; 3: network ; 2: single ; 1: PLR 2 ; 0: PLR1
#define IOWR_VGA_WORD_EN(data) \
	IOWR_16DIRECT(DE2_VGA_RASTER_0_BASE, 132, data)
#define IOWR_VGA_WORD_HL_EN(data) \
	IOWR_16DIRECT(DE2_VGA_RASTER_0_BASE, 134, data)
#define IOWR_VGA_WORD_POS_X(n, data) \
	IOWR_16DIRECT(DE2_VGA_RASTER_0_BASE, (68 + 2*n)*2, data)
#define IOWR_VGA_WORD_POS_Y(n, data) \
	IOWR_16DIRECT(DE2_VGA_RASTER_0_BASE, (69 + 2*n)*2, data)

struct balltype
{
	int pos_x,pos_y;
	int vc_x, vc_y;
	int count_x, count_y;
	short int dir_x, dir_y;
	short int flag;
	float dx, dy;
	int force_move;
	int bias_x, bias_y;
}ball[16];


int hole[6][2]={{24,158},{320,154},{615,158},
				{24,461},{320,465},{615,461}};

int player=0;
int change=1;
int oops = 0;
int plball[2]={0,0};
int i_0 =0;
int i_1 =0;
int ex = 1;
int cue_ready = 0;
int angle = 0;
int strength = 0;
int release = 0;
int begin_flag;
float swtich_d;

void decide_direction(int ball_num)
{
	if((ball[ball_num].dx * ball[ball_num].dx + ball[ball_num].dy * ball[ball_num].dy) >= zero)
	{
		if(ball[ball_num].dx >= zero)
		{
			ball[ball_num].vc_x = (int)(PRODUCT / ball[ball_num].dx);
			ball[ball_num].dir_x = 1;
		}
		else if (ball[ball_num].dx <= n_zero)
		{
			ball[ball_num].vc_x = - (int)(PRODUCT / ball[ball_num].dx);
			ball[ball_num].dir_x = -1;
		}
		else
		{
			ball[ball_num].vc_x = VC_MAX + 1;
			ball[ball_num].dir_x = 0;
			ball[ball_num].dx = 0;
		}
		if(ball[ball_num].dy >= zero)
		{
			ball[ball_num].vc_y = (int)(PRODUCT / ball[ball_num].dy);
			ball[ball_num].dir_y = 1;
		}
		else if (ball[ball_num].dy <= n_zero)
		{
			ball[ball_num].vc_y = - (int)(PRODUCT / ball[ball_num].dy);
			ball[ball_num].dir_y = -1;
		}
		else
		{
			ball[ball_num].vc_y = VC_MAX + 1;
			ball[ball_num].dir_y = 0;
			ball[ball_num].dy = 0;
		}
	}
	else
	{
		ball[ball_num].vc_x = VC_MAX + 1;
		ball[ball_num].dir_x = 0;
		ball[ball_num].dx = 0;
		ball[ball_num].vc_y = VC_MAX + 1;
		ball[ball_num].dir_y = 0;
		ball[ball_num].dy = 0;
	}

	if(ball[ball_num].vc_x < ball[ball_num].count_x)
	{
		ball[ball_num].count_x = ball[ball_num].vc_x;
	}

	if(ball[ball_num].vc_y < ball[ball_num].count_y)
	{
		ball[ball_num].count_y = ball[ball_num].vc_y;
	}

}
void dir_change(int i, char axle, int change_to)
{
	if(axle == 'x')
	{
		if((change_to == 1 && ball[i].dx < 0) || (change_to == -1 && ball[i].dx > 0))
		{
			ball[i].dx = -ball[i].dx;
		}
	}
	else if(axle == 'y')
	{
		if((change_to == 1 && ball[i].dy < 0) || (change_to == -1 && ball[i].dy > 0))
		{
			ball[i].dy = -ball[i].dy;
		}
	}
}

void detect_bound_edge(int i)
{
	int hit_flag = 0;
	float dis_v_sq;

	  if(ball[i].pos_x < 45 && ball[i].pos_y < 179)  //left_up pocket area
	  {
		  if(39 - ball[i].pos_x > 179 - ball[i].pos_y)
		  {
			  swtich_d = ball[i].dx;
			  ball[i].dx = ball[i].dy;
			  ball[i].dy = swtich_d;
			  dir_change(i, 'x', 1);
			  dir_change(i, 'y', -1);
			  ball[i].dx *= edge_acc;
			  ball[i].dy *= edge_acc;
			  decide_direction (i);
			  hit_flag = 1;
		  }
		  else if(173 - ball[i].pos_y > 45 - ball[i].pos_x)
		  {
			  swtich_d = ball[i].dx;
			  ball[i].dx = ball[i].dy;
			  ball[i].dy = swtich_d;
			  dir_change(i, 'x', -1);
			  dir_change(i, 'y', 1);
			  ball[i].dx *= edge_acc;
			  ball[i].dy *= edge_acc;
			  decide_direction (i);
			  hit_flag = 1;
		  }
	  }
	  else if(ball[i].pos_x > 594 && ball[i].pos_y < 179)  //right_up pocket area
	  {
		  if(ball[i].pos_x - 600 > 179 - ball[i].pos_y)
		  {
			  swtich_d = ball[i].dx;
			  ball[i].dx = ball[i].dy;
			  ball[i].dy = swtich_d;
			  dir_change(i, 'x', -1);
			  dir_change(i, 'y', -1);
			  ball[i].dx *= edge_acc;
			  ball[i].dy *= edge_acc;
			  decide_direction (i);
			  hit_flag = 1;
		  }
		  else if(173 - ball[i].pos_y > ball[i].pos_x - 594)
		  {
			  swtich_d = ball[i].dx;
			  ball[i].dx = ball[i].dy;
			  ball[i].dy = swtich_d;
			  dir_change(i, 'x', 1);
			  dir_change(i, 'y', 1);
			  ball[i].dx *= edge_acc;
			  ball[i].dy *= edge_acc;
			  decide_direction (i);
			  hit_flag = 1;
		  }

	  }
	  else if(ball[i].pos_x < 45 && ball[i].pos_y > 440)  //left_down pocket area
	  {
		  if(39 - ball[i].pos_x > ball[i].pos_y - 440)
		  {
			  swtich_d = ball[i].dx;
			  ball[i].dx = ball[i].dy;
			  ball[i].dy = swtich_d;
			  dir_change(i, 'x', 1);
			  dir_change(i, 'y', 1);
			  ball[i].dx *= edge_acc;
			  ball[i].dy *= edge_acc;
			  decide_direction (i);
			  hit_flag = 1;

		  }
		  else if(ball[i].pos_y - 446 > 45 - ball[i].pos_x)
		  {
			  swtich_d = ball[i].dx;
			  ball[i].dx = ball[i].dy;
			  ball[i].dy = swtich_d;
			  dir_change(i, 'x', -1);
			  dir_change(i, 'y', -1);
			  ball[i].dx *= edge_acc;
			  ball[i].dy *= edge_acc;
			  decide_direction (i);
			  hit_flag = 1;
		  }

	  }
	  else if(ball[i].pos_x > 594 && ball[i].pos_y > 440)  //right_down pocket area
	  {
		  if(ball[i].pos_x - 600 > ball[i].pos_y - 440)
		  {
			  swtich_d = ball[i].dx;
			  ball[i].dx = ball[i].dy;
			  ball[i].dy = swtich_d;
			  dir_change(i, 'x', -1);
			  dir_change(i, 'y', 1);
			  ball[i].dx *= edge_acc;
			  ball[i].dy *= edge_acc;
			  decide_direction (i);
			  hit_flag = 1;

		  }
		  else if(ball[i].pos_y - 446 > ball[i].pos_x - 594)
		  {
			  swtich_d = ball[i].dx;
			  ball[i].dx = ball[i].dy;
			  ball[i].dy = swtich_d;
			  dir_change(i, 'x', 1);
			  dir_change(i, 'y', -1);
			  ball[i].dx *= edge_acc;
			  ball[i].dy *= edge_acc;
			  decide_direction (i);
			  hit_flag = 1;
		  }
	  }
	  else
	  {
		  if(ball[i].pos_x <= 39)  //left edge
		  {
			  ball[i].pos_x = 39;
			  dir_change(i, 'x', 1);
			  ball[i].dx *= edge_acc;
			  //ball[i].dy *= edge_acc;
			  decide_direction (i);
			  hit_flag = 1;
		  }
		  if(ball[i].pos_x >= 600)  //right edge
		  {
			  ball[i].pos_x = 600;
			  dir_change(i, 'x', -1);
			  ball[i].dx *= edge_acc;
			  //ball[i].dy *= edge_acc;
			  decide_direction (i);
			  hit_flag = 1;
		  }

		  if(ball[i].pos_y <= 173)   //up edge
		  {
			  if(ball[i].pos_y > 168 ) //up_mid pocket area
			  {
				  if(ball[i].pos_x < 336 && ball[i].pos_x > 304)
				  {

					  if(173 - ball[i].pos_y > ball[i].pos_x - 304)
					  {
						  swtich_d = ball[i].dx;
						  ball[i].dx = ball[i].dy;
						  ball[i].dy = swtich_d;
						  dir_change(i, 'x', 1);
						  dir_change(i, 'y', 1);

						  ball[i].dx *= edge_acc;
						  ball[i].dy *= edge_acc;
						  decide_direction (i);

					  }
					  else if(173 - ball[i].pos_y > 336 - ball[i].pos_x)
					  {
						  swtich_d = ball[i].dx;
						  ball[i].dx = ball[i].dy;
						  ball[i].dy = swtich_d;
						  dir_change(i, 'x', -1);
						  dir_change(i, 'y', 1);

						  ball[i].dx *= edge_acc;
						  ball[i].dy *= edge_acc;
						  decide_direction (i);
					  }

				  }
				  else  //normal
				  {
					  ball[i].pos_y = 173;
					  dir_change(i, 'y', 1);
					  //ball[i].dx *= edge_acc;
					  ball[i].dy *= edge_acc;
					  decide_direction (i);
					  hit_flag = 1;

				   }
			  }
			  else
			  {
				  if(ball[i].pos_x >= 325)
				  {
					  //ball[i].pos_y = 173;
					  dir_change(i, 'x', -1);
					  ball[i].dx *= edge_acc;
					  //ball[i].dy *= edge_acc;
					  decide_direction (i);
					  hit_flag = 1;
				  }
				  else if(ball[i].pos_x <= 315)
				  {
					  //ball[i].pos_y = 173;
					  dir_change(i, 'x', 1);
					  ball[i].dx *= edge_acc;
					  //ball[i].dy *= edge_acc;
					  decide_direction (i);
					  hit_flag = 1;

				  }
			  }


		  }

		  if(ball[i].pos_y >= 446)   //down edge
		  {
			  if(ball[i].pos_y < 451) //up_mid pocket area
			  {
				  if(ball[i].pos_x < 336 && ball[i].pos_x > 304)
				  {
					  if(ball[i].pos_y - 446 > ball[i].pos_x - 304)
					  {
						  swtich_d = ball[i].dx;
						  ball[i].dx = ball[i].dy;
						  ball[i].dy = swtich_d;
						  dir_change(i, 'x', 1);
						  dir_change(i, 'y', -1);

						  ball[i].dx *= edge_acc;
						  ball[i].dy *= edge_acc;
						  decide_direction (i);
						  hit_flag = 1;

					  }
					  else if(ball[i].pos_y - 446 > 336 - ball[i].pos_x)
					  {
						  swtich_d = ball[i].dx;
						  ball[i].dx = ball[i].dy;
						  ball[i].dy = swtich_d;
						  dir_change(i, 'x', -1);
						  dir_change(i, 'y', -1);

						  ball[i].dx *= edge_acc;
						  ball[i].dy *= edge_acc;
						  decide_direction (i);
						  hit_flag = 1;
					  }

				  }
				  else  //normal
				  {
					  ball[i].pos_y = 446;
					  dir_change(i, 'y', -1);
					  //ball[i].dx *= edge_acc;
					  ball[i].dy *= edge_acc;
					  decide_direction (i);
					  hit_flag = 1;
				  }
			  }
			  else
			  {
				  if(ball[i].pos_x >= 325)
				  {
					  //ball[i].pos_y = 173;
					  dir_change(i, 'x', -1);
					  ball[i].dx *= edge_acc;
					  //ball[i].dy *= edge_acc;
					  decide_direction (i);
					  hit_flag = 1;
				  }
				  else if(ball[i].pos_x <= 315)
				  {
					  //ball[i].pos_y = 173;
					  dir_change(i, 'x', 1);
					  ball[i].dx *= edge_acc;
					  //ball[i].dy *= edge_acc;
					  decide_direction (i);
					  hit_flag = 1;
				  }
			  }


		  }

	  }

	  if(hit_flag == 1)
	  {
		  dis_v_sq = ball[i].dx * ball[i].dx + ball[i].dy * ball[i].dy;
		  if(dis_v_sq > 0.05)
		  {
			  IOWR_AUDIO_EN(4);
		  }
		  else if(dis_v_sq > 0)
		  {
			  IOWR_AUDIO_EN(8);
		  }

	  }
}

void bound_balls(int b1,int b2)
{
	float s1=100,s2=100,s,d1,d2,x,y,dx1,dx2,dy1,dy2;
	float dis_v_sq;
	int dis1_x, dis2_x;
	int dis1_y, dis2_y;

	x = ball[b2].pos_x - ball[b1].pos_x;
	y = ball[b2].pos_y - ball[b1].pos_y;

	//Audio
	/*
	dis_v_sq = (ball[b2].dx - ball[b1].dx)*(ball[b2].dx - ball[b1].dx) + (ball[b2].dy - ball[b1].dy)*(ball[b2].dy - ball[b1].dy);
	if(dis_v_sq > 0.05)
	{
		IOWR_AUDIO_EN(1);
	}
	else if(dis_v_sq > 0)
	{
		IOWR_AUDIO_EN(2);
	}
	*/


	if(!(fabs(ball[b1].dx) < zero && fabs(ball[b1].dy) < zero))
	{
		s1 = atan2(ball[b1].dy,ball[b1].dx);
	}

	if(!(fabs(ball[b2].dx) < zero && fabs(ball[b2].dy) < zero))
	{
		s2 = atan2(ball[b2].dy,ball[b2].dx);
	}
	s = atan2(y,x);

	if(s1!=100 && fabs(s-s1) < pi/2)
	{
		d1=sqrt(ball[b1].dx * ball[b1].dx + ball[b1].dy * ball[b1].dy)*cos(s-s1);
		dx1= d1*cos(s);
		dy1= d1*sin(s);
		ball[b1].dx -= dx1;
		ball[b1].dy -= dy1;
		ball[b2].dx += dx1;
		ball[b2].dy += dy1;

		dis_v_sq = dx1*dx1 + dy1*dy1;
		if(dis_v_sq > 0.02)
		{
			IOWR_AUDIO_EN(1);
		}
		else if(dis_v_sq > 0)
		{
			IOWR_AUDIO_EN(2);
		}
	}

	if(s2 != 100 && fabs(s-s2) > pi/2)
	{
		d2=sqrt(ball[b2].dx * ball[b2].dx + ball[b2].dy * ball[b2].dy)*cos(pi-(s-s2));
		dx2= d2*cos(pi-s);
		dy2= d2*sin(pi-s);
		ball[b1].dx += dx2;
		ball[b1].dy += dy2;
		ball[b2].dx -= dx2;
		ball[b2].dy -= dy2;

		dis_v_sq = dx1*dx1 + dy1*dy1;
		if(dis_v_sq > 0.05)
		{
			IOWR_AUDIO_EN(1);
		}
		else if(dis_v_sq > 0)
		{
			IOWR_AUDIO_EN(2);
		}
	}


	ball[b1].dx *= 0.90;
	ball[b1].dy *= 0.90;
	ball[b2].dx *= 0.90;
	ball[b2].dy *= 0.90;
	decide_direction (b1);
	decide_direction (b2);

	if(x*x + y*y < 196)
	{
		if(x > 0)
		{
			dis2_x = 1;
			dis1_x = -1;
		}
		else
		{
			dis2_x = -1;
			dis1_x = 1;
		}

		if(y > 0)
		{
			dis2_y = 1;
			dis1_y = -1;
		}
		else
		{
			dis2_y = -1;
			dis1_y = 1;
		}

		moveball(b1, &ball[b1].pos_x, &ball[b1].pos_y, dis1_x, dis1_y, &ball[b1].bias_x, &ball[b1].bias_y);
		moveball(b2, &ball[b2].pos_x, &ball[b2].pos_y, dis2_x, dis2_y, &ball[b2].bias_x, &ball[b2].bias_y);

		ball[b2].force_move = 1;

		IOWR_AUDIO_EN(2);
	}
}

void win(int b)
{
	int i,m=0;
	if(b==7)    // if the black ball pockets
	{
		ex = 0;
		//printf("Start again?\n");
		ball[b].pos_x = 120;
		ball[b].pos_y = 48;
		placeball(b, ball[b].pos_x, ball[b].pos_y, 0, 0, &ball[b].bias_x, &ball[b].bias_y);
		if(plball[player]==0)    // if player directly pocket the black ball without pocketing his balls first
		{
			//printf("win player: %d",!player);
			IOWR_VGA_WORD_EN(71);
			IOWR_VGA_WORD_POS_X(0, 52);
			IOWR_VGA_WORD_POS_Y(0, 60);
			IOWR_VGA_WORD_POS_X(1, 52);
			IOWR_VGA_WORD_POS_Y(1, 90);
			IOWR_VGA_WORD_POS_X(2, 550);
			IOWR_VGA_WORD_POS_Y(2, 40);
			if(player == 0)
			{
				IOWR_VGA_WORD_HL_EN(64);
				IOWR_VGA_WORD_POS_X(6, 10);
				IOWR_VGA_WORD_POS_Y(6, 90);
			}
			else
			{
				IOWR_VGA_WORD_HL_EN(64);
				IOWR_VGA_WORD_POS_X(6, 10);
				IOWR_VGA_WORD_POS_Y(6, 60);
			}
		}
		else
		{
			for(i = plball[player]-1; i < plball[player]+6; i++)
			{
				if(ball[i].flag==1)  // if player doesn't pocket all his balls before pocketing black ball
				{
					m=1;
					break;
				}
			}
			if(m)
			{
				printf("win player: %d",!player);
				IOWR_VGA_WORD_EN(71);
				IOWR_VGA_WORD_POS_X(0, 52);
				IOWR_VGA_WORD_POS_Y(0, 60);
				IOWR_VGA_WORD_POS_X(1, 52);
				IOWR_VGA_WORD_POS_Y(1, 90);
				IOWR_VGA_WORD_POS_X(2, 550);
				IOWR_VGA_WORD_POS_Y(2, 40);
				if(player == 0)
				{
					IOWR_VGA_WORD_HL_EN(64);
					IOWR_VGA_WORD_POS_X(6, 10);
					IOWR_VGA_WORD_POS_Y(6, 60);
				}
				else
				{
					IOWR_VGA_WORD_HL_EN(64);
					IOWR_VGA_WORD_POS_X(6, 10);
					IOWR_VGA_WORD_POS_Y(6, 90);
				}
			}
			else
			{
				printf("win player: %d",player);
				IOWR_VGA_WORD_EN(71);
				IOWR_VGA_WORD_POS_X(0, 52);
				IOWR_VGA_WORD_POS_Y(0, 60);
				IOWR_VGA_WORD_POS_X(1, 52);
				IOWR_VGA_WORD_POS_Y(1, 90);
				IOWR_VGA_WORD_POS_X(2, 550);
				IOWR_VGA_WORD_POS_Y(2, 40);
				if(player == 0)
				{
					IOWR_VGA_WORD_HL_EN(64);
					IOWR_VGA_WORD_POS_X(6, 10);
					IOWR_VGA_WORD_POS_Y(6, 90);
				}
				else
				{
					IOWR_VGA_WORD_HL_EN(64);
					IOWR_VGA_WORD_POS_X(6, 10);
					IOWR_VGA_WORD_POS_Y(6, 60);
				}
			}
		}
	}
	else if(b==15)		//if the cue ball pockets
	{
		oops = 1;
		ball[b].pos_x = 100;
		ball[b].pos_y = 48;
		placeball(b, ball[b].pos_x, ball[b].pos_y, 0, 0, &ball[b].bias_x, &ball[b].bias_y);
	}
	else if(plball[player]==0)	//if player first pockets a ball, then he has to pocket the same type balls afterwards
	{
		if(b >=0 && b < 7)
		{
			plball[player]=1;
			plball[!player]=9;
			if(player == 0)
			{
				ball[b].pos_x = 100 + 17 * i_0;
				ball[b].pos_y = 68;
				placeball(b, ball[b].pos_x, ball[b].pos_y, 0, 0, &ball[b].bias_x, &ball[b].bias_y);
				i_0 ++;
			}
			else
			{
				ball[b].pos_x = 100 + 17 * i_1;
				ball[b].pos_y = 98;
				placeball(b, ball[b].pos_x, ball[b].pos_y, 0, 0, &ball[b].bias_x, &ball[b].bias_y);
				i_1 ++;
			}
		}
		else if(b >= 8&&b<15)
		{
			plball[player]=9;
			plball[!player]=1;
			if(player == 0)
			{
				ball[b].pos_x = 100 + 17 * i_0;
				ball[b].pos_y = 68;
				placeball(b, ball[b].pos_x, ball[b].pos_y, 0, 0, &ball[b].bias_x, &ball[b].bias_y);
				i_0 ++;
			}
			else
			{
				ball[b].pos_x = 100 + 17 * i_1;
				ball[b].pos_y = 98;
				placeball(b, ball[b].pos_x, ball[b].pos_y, 0, 0, &ball[b].bias_x, &ball[b].bias_y);
				i_1 ++;
			}
		}
		change=0;
	}
}

void place_cue_ball()
{
	int i;
	int f;
	SERVELINE_EN(1);

	angle = 60;

	while(cue_ready == 0)
	{
		get_key(&strength, &angle, &release);
		ball[15].pos_x = 172;
		ball[15].pos_y = 453 + (int)(-2.3 * angle);
		placeball(15, ball[15].pos_x, ball[15].pos_y, 0, 0, &ball[15].bias_x, &ball[15].bias_y);
		if(release == 1)
		{
			f = 1;
			for(i = 0; i < 15; i++)
			{
				if(ball[i].pos_x >= 158 && ball[i].pos_x <= 186)
				{
					if(ball[i].pos_y >= (ball[15].pos_y - 14) && ball[i].pos_y <= (ball[15].pos_y + 14))
					{
						f = 0;
					}
				}
			}
			if(f)
			{
				cue_ready =1;
				begin_flag = 0;
				ball[15].flag = 1;
				SERVELINE_EN(0);
			}
			release = 0;
		}
	}

	angle = 60;
}

void ball_initial()
{
	int i;

	int ballxy_triangle[15][2]={{3,4},{1,-3},{-1,2},{-3,-1},
								{3,-4},{3,-2},{1,-1},{-1,0},
								{-5,0},{1,1},{3,0},{-3,1},
								{-1,-2},{1,3},{3,2},};

	// initialize the position of the balls
	for(i = 0; i < 15; i++)			// initialize the position of the 15 balls
	{
		ball[i].pos_x = 500 + ballxy_triangle[i][0]*8;
		ball[i].pos_y = 310 + ballxy_triangle[i][1]*8;
		placeball(i, ball[i].pos_x, ball[i].pos_y, 0, 0, &ball[i].bias_x, &ball[i].bias_y);
		ball[i].flag = 1;
		ball[i].force_move = 0;
	}
	ball[15].pos_x = 172;
	ball[15].pos_y = 315;
	placeball(15, ball[15].pos_x, ball[15].pos_y, 0, 0, &ball[15].bias_x, &ball[15].bias_y);
	ball[15].flag = 1;

	// initialize the speed and direction of the balls
	for(i = 0; i < 16; i++)
	{
		ball[i].vc_x = VC_MAX + 1;
		ball[i].vc_y = VC_MAX + 1;
		ball[i].count_x = 0;
		ball[i].count_y = 0;
		ball[i].dir_x = 1;
		ball[i].dir_y = 1;
		ball[i].dx = 0;
		ball[i].dy = 0;
	}
	// initialize the strength bar
	strength = 16;
	IOWR_VGA_STRENGTHBAR(16);

	//initialize pool cue
	print_poolcue(ball[15].pos_x, ball[15].pos_y, 60);
}

int main()
{
	printf("Hello from Nios II!\n");

	int i;
	int j;
	int ff;
	float temp_angle;
	int acc_count = 0;
	short int move_flag;
	short int bias_x;
	short int bias_y;
	int dis_x;
	int dis_y;
	int hole_dis_x;
	int hole_dis_y;


    while(1)
    {
	//start:
		angle = 60;
		strength = 0;
		release = 0;
		cue_ready = 0;
		i_0 = 0;
		i_1 = 0;
		begin_flag = 0;
		oops = 0;
		//display "NEW GAME"
		IOWR_VGA_WORD_EN(48);
		IOWR_VGA_WORD_HL_EN(48);
		IOWR_VGA_WORD_POS_X(4, 280);
		IOWR_VGA_WORD_POS_Y(4, 60);
		IOWR_VGA_WORD_POS_X(5, 320);
		IOWR_VGA_WORD_POS_Y(5, 60);

		ball_initial();

	//start2:
		while(release == 0)
		{
			get_key(&strength, &angle, &release);
			//if(release == 0)  //wait for player to press "return"
			//{
			//goto start2;
			//}
		}
		release = 0;

		//display main screen printouts
		IOWR_VGA_WORD_EN(15);
		IOWR_VGA_WORD_HL_EN(5);
		IOWR_VGA_WORD_POS_X(0, 52);
		IOWR_VGA_WORD_POS_Y(0, 60);
		IOWR_VGA_WORD_POS_X(1, 52);
		IOWR_VGA_WORD_POS_Y(1, 90);
		IOWR_VGA_WORD_POS_X(2, 550);
		IOWR_VGA_WORD_POS_Y(2, 40);
		IOWR_VGA_WORD_POS_X(3, 550);
		IOWR_VGA_WORD_POS_Y(3, 60);


		place_cue_ball();
		printf("cue_ready = %d",cue_ready);

		for(i = 1; i < 15; i ++)
		{
			if(i != 7)
			{ball[i].flag = 0;}
		}

		ball[7].flag = 1;
		ball[15].flag = 1;
		ball[15].pos_x = 305;
		ball[15].pos_y = 178;
		ball[7].pos_x = 34;		//left-up hole : 24,158
		ball[7].pos_y = 168;
		ball[0].pos_x = 34;		//left-up hole : 24,158
		ball[0].pos_y = 436;
		placeball(7, ball[7].pos_x, ball[7].pos_y, 0, 0, &ball[7].bias_x, &ball[7].bias_y);
		placeball(1, ball[1].pos_x, ball[1].pos_y, 0, 0, &ball[1].bias_x, &ball[1].bias_y);
		placeball(15, ball[15].pos_x, ball[15].pos_y, 0, 0, &ball[15].bias_x, &ball[15].bias_y);


		while(cue_ready)
		{

			while(ex)
			{
				while(begin_flag == 0)
				{
					cx = ball[15].pos_x;
					cy = ball[15].pos_y;
					get_key(&strength, &angle, &release);
					print_poolcue(cx, cy, angle);
					IOWR_VGA_STRENGTHBAR(strength);

					if (release == 1)
					{
						begin_flag = 1;
						temp_angle = angle_trans * angle;
						ball[15].dx= - (strength + 1) * sq_zero * cos(temp_angle);
						ball[15].dy= - (strength + 1) * sq_zero * sin(temp_angle);
						decide_direction (15);
						ball[15].count_x = ball[15].vc_x;
						ball[15].count_y = ball[15].vc_y;
					}
				}

				while(begin_flag == 1)
				{
					release = 0;
					for(i = 15; i >= 0; i--)
					{
						if(ball[i].flag != 0)
						{
							move_flag = 0;
							//Update (Position update) counter
									if(ball[i].count_x > 0)
									{
										ball[i].count_x --;
										bias_x = 0;
									}
									else if(ball[i].vc_x <= VC_MAX)
									{
										ball[i].count_x = ball[i].vc_x;
										move_flag = 1;
										if(ball[i].dir_x == 1)
										{
											bias_x = 1;
										}
										else if(ball[i].dir_x == -1)
										{
											bias_x = -1;
										}
										else
										{
											bias_x = 0;
										}
									}
									else
									{
										bias_x = 0;
									}

									if(ball[i].count_y > 0)
									{
										ball[i].count_y --;
										bias_y = 0;
									}
									else if(ball[i].vc_y <= VC_MAX)
									{
										ball[i].count_y = ball[i].vc_y;
										move_flag = 1;
										if(ball[i].dir_y == 1)
										{
											bias_y = 1;
										}
										else if(ball[i].dir_y == -1)
										{
											bias_y = -1;
										}
										else
										{
											bias_y = 0;
										}
									}
									else
									{
										bias_y = 0;
									}


									//Update positions
									if(move_flag || ball[i].force_move)
									{
										if(move_flag)
										{
											moveball(i, &ball[i].pos_x, &ball[i].pos_y, bias_x, bias_y, &ball[i].bias_x, &ball[i].bias_y);
										}

										ball[i].force_move = 0;
										//detect and handle the situation when a ball hits edge
										detect_bound_edge(i);


										for(j = 15; j >= 0; j--)
										{
											if(j != i)
											{
												dis_x = abs(ball[i].pos_x - ball[j].pos_x);
												dis_y = abs(ball[i].pos_y - ball[j].pos_y);
												if(dis_x < 14 || dis_y < 14)
												{
													if(dis_x * dis_x + dis_y * dis_y <= 196)
													{
														bound_balls(i, j);
													}
												}
											}
										}

										for(j = 0; j < 6; j++)
										{
											hole_dis_x = ball[i].pos_x - hole[j][0];
											hole_dis_y = ball[i].pos_y - hole[j][1];
											if(hole_dis_x * hole_dis_x + hole_dis_y * hole_dis_y <= 144)     //original:144
											{
												printf("pocketed!\n");
												ball[i].flag = 0;
												if(plball[player]!=0 && oops == 0) // if player pocket before and it's not the cue ball pocketed
												{
													if(i >= (plball[player]-1) && i <= plball[player]+5) // if player is pocketing his balls, then no need to switch turn
													{
														change=0;
														if(player == 0)
														{
															ball[i].pos_x = 100 + 17 * i_0;
															ball[i].pos_y = 68;
															placeball(i, ball[i].pos_x, ball[i].pos_y, 0, 0, &ball[i].bias_x, &ball[i].bias_y);
															i_0 ++;
														}
														else
														{
															ball[i].pos_x = 100 + 17 * i_1;
															ball[i].pos_y = 98;
															placeball(i, ball[i].pos_x, ball[i].pos_y, 0, 0, &ball[i].bias_x, &ball[i].bias_y);
															i_1 ++;
														}
													}
													else			// if player is pocketing other's balls, then need to switch turn
													{
														change=1;
														if(player == 0)
														{
															ball[i].pos_x = 100 + 17 * i_1;
															ball[i].pos_y = 98;
															placeball(i, ball[i].pos_x, ball[i].pos_y, 0, 0, &ball[i].bias_x, &ball[i].bias_y);
															i_1 ++;
														}
														else
														{
															ball[i].pos_x = 100 + 17 * i_0;
															ball[i].pos_y = 68;
															placeball(i, ball[i].pos_x, ball[i].pos_y, 0, 0, &ball[i].bias_x, &ball[i].bias_y);
															i_0 ++;
														}
													}
												}
												win(i);

											}
										}
									}
						}
						while(IORD_16DIRECT(IRTIMER_0_BASE, 0) != 0)
						{

						}

						IOWR_16DIRECT(IRTIMER_0_BASE, 0, 3000);
					} //16 ball

					//Update Speed (dx,dy)
					if(acc_count >= ACC)
					{
						acc_count = 0;
						for(i = 16; i >= 0; i--)
						{
							ball[i].dx = ball[i].dx * 0.95;
							ball[i].dy = ball[i].dy * 0.95;
							decide_direction(i);
						}
					}
					else
					{
						acc_count ++;
					}


					ff=1;

					for(j = 15; j >= 0; j--)
					{
						if(!(ball[j].dx == 0 && ball[j].dy ==0) && ball[j].flag == 1)	//if there're still balls moving
						{
							ff=0;
							break;
						}
					}
					if(ff)		//if all the balls have stopped
					{
						begin_flag = 0;
						release = 0;
						if(ex == 1)
						{
							if(change == 1)
							{
								player=!player;
								if(player == 0)
								{
									IOWR_VGA_WORD_HL_EN(5);
								}
								else
								{
									IOWR_VGA_WORD_HL_EN(6);
								}
							}
						}
						change=1;
						if(oops == 1)		//see if the cue ball is pocketed.
						{
							/*ball[15].pos_x = 104;
											ball[15].pos_y = 310;
											placeball(15, ball[15].pos_x, ball[15].pos_y, 0, 0, &ball[15].bias_x, &ball[15].bias_y);
											ball[15].flag = 1;*/
							cue_ready = 0;
							place_cue_ball();
							change=1;
							oops = 0;
						}
					}

				}

			} //End: while(ex)
			//if(ex == 0)
			//{
			get_key(&strength, &angle, &release);
			if(release == 1)
			{

				release = 0;
				ex = 1;
				break;
				//goto start;
			}
			//}
		}  //End: while(cue_ready)
    }
	return 0;
}
