import java.awt.*;
import java.applet.*;
import java.awt.event.*;
import java.lang.Math.*;
// "Pong" Program
// Programmer: Melissa Smith (BLADE)
public class MyPong extends Applet implements KeyListener, Runnable
{
	/*** Variable Declaraction ***/ 
	Thread main;
	int sleep = 20; //The number of microseconds in bewtween thread loops.
	boolean user_is_playing = false; //The user is in the middle of a game 
	boolean program_running = false; //The program is running or not.
	boolean display_miss=false;      //True displays the "Hit Start to Continue" message"
	/* Who has won. */
	boolean user_won = false;
	boolean comp_won = false;
	String who_missed="You missed!";
	/* Variables for the paddle's size */
	int paddle_w = 10;
	int paddle_h = 40;
	/*Variables for the ball position and movement*/
	int user = 1; //User lost.
	int comp = 0; //Computer lost.
	int loser;	  //Who the loser was, becomes either user or comp
	
	int ballx;
	int bally;
	int ball_hit; //Where on the paddle the ball hit
	
	int perfect_hit; //Where the comp's paddle needs to go to hit the ball perfectly.
	int speed = 0;   //Speed of the ball number of x positions it jumps each redraw.
	int diry = 1;	 //Direction the ball is going.
    int intent;	     
	
	boolean p; //True if the ball has a new direction to go in after hitting the paddle.
	
	boolean ball_right; //True if... the ball is going right.
	boolean ball_was_missed = false;
	/*Ball boundaries*/
	int ball_up_bound = 0;
	int ball_down_bound = 230;
	int ball_left_bound = 0;
	int ball_right_bound = 380;
	/* Variables for player poaition and movement*/
	boolean plr1_up = true;  //Player starts game moving up.
	/*player 1*/
	int plr1_x = 5;
	int plr1_y = 150;
	/*player 2 (The Computer)*/
	int plr2_x = 385;
	int plr2_y = 50;
	/* player  boundaries */
	int up_bound = 0;
	int down_bound = 210;
	/* Double buffering stuff */
	Image off_screen_image;
	Graphics offgc;
	/* Collision Detection */
	int help = 5;
	/* Scoreing */
	int user_score = 0;
	int comp_score = 0;
	/* Fonts */
	Font ComicSansLarge = new Font("Comic Sans MS", Font.BOLD,40);
	Font ComicSansSmall = new Font("Comic Sans MS", Font.BOLD,12);
	/* Labels */
	Label dirHit = new Label("                       ");
	/* Misc. */
	String[] Good_Messages = new String[20];
	String[] Bad_Messages = new String[20];
	int which_message;
	boolean comp_missed=false;
	boolean user_missed=false;
	boolean got_message=false;
	/* Text positions */
	int Bad_Message_X = 240;
	int Bad_Message_Y = 30;
	int Good_Message_Y = 30;
	int Good_Message_X = 30;
	int Press_Any_Key_X = 130;
	int Press_Any_Key_Y = 80;
	int Game_Over_X = 140;
	int Game_Over_Y = 100;
	int CompScore_X = 275;
	int CompScore_Y = 240;
	int UserScore_X = 10;
	int UserScore_Y = 240;
/***INIT***/
public void init()
	{
	/*Adds KeyListener*/
	
	addKeyListener(this);

	setBackground(Color.black);	
	/* Double Buffering */	off_screen_image = createImage(400,260);
	offgc = off_screen_image.getGraphics();

	/* Store Messages */
	/* Bad Messages */
	
	Bad_Messages[1]="Not a chance...";
	Bad_Messages[2]="Is it really that hard?";
	Bad_Messages[3]="Heh heh heh...";
	Bad_Messages[4]="Loosser...";
	Bad_Messages[5]="HaHaHa!";
	Bad_Messages[6]="HaHA!";
	Bad_Messages[7]="Shot down!";
	Bad_Messages[8]="Ooo.";
	Bad_Messages[9]="Ouch.";
	Bad_Messages[10]="Why don't you just give up?";
	Bad_Messages[11]="That was sad.";
	Bad_Messages[12]="Do you need a nap?";
	Bad_Messages[13]="You Missed!";
	Bad_Messages[14]="Ahh!";
	Bad_Messages[15]="You Missed!";
	Bad_Messages[16]="You Missed!";
	Bad_Messages[17]="Hee hee...";
	Bad_Messages[18]="Blown away!";

	/* Good Messages */
	
	Good_Messages[1]="You go!";
	Good_Messages[2]="Only a few more points...";
	Good_Messages[3]="Got 'em!";
	Good_Messages[4]="Waho!";
	Good_Messages[5]="Much better.";
	Good_Messages[6]="You've been practising!";
	Good_Messages[7]="'Bout time!";
	Good_Messages[8]="Phew.";
	Good_Messages[9]="You rock!";
	Good_Messages[10]="The computer missed!";
	Good_Messages[11]="The computer missed!";
	Good_Messages[12]="The computer missed!";
	Good_Messages[13]="Nice.";
	Good_Messages[14]="Sweet.";
	Good_Messages[15]="Keep it up!";

	ball_start(comp);

}
	
public void start() {
    if(main==null) {
      main = new Thread(this);
      main.start();
	 
	}
  }

public void run() {
    while(true) {		
		if (user_is_playing){
		adjust_speed();
		move_paddles();
		move_ball();
		
		repaint();}
	
		if(user_is_playing==false){repaint();}
		
		try {main.sleep(sleep);}
		catch(InterruptedException e){}
	
	}		
	
	}





public void ball_start(int lost) /* Waits for the user to be ready for the next round, then starts the ball */
{
	sleep = 20; //Amount of time between thread loops.
	
	bally = ball_down_bound /2; //Puts ball in the middle of the playfield.
	ballx = ball_right_bound /2;
	
	ball_was_missed = false;

	if (lost == 1){
		ball_right = false; //Ball's going left...
		do {
		diry =(int)(-4 + Math.random() * (4+4 + 1));//Picks a random angle for the ball to travel on.
		} while (diry == 0);}
	
	if (lost == 0){
		ball_right = true;//Ball's going right...
		do {
			diry=(int)(-4 + Math.random()*(4+4+1));//Picks a random angle for the ball to travel on.
		} while (diry == 0);}
		
	
	intent = (int)(1 + Math.random() * (35-1 + 1));
}

/***BALL HIT THE RIGHT BOUNDARY***/
public void right_bound()
{
	p=false;
	if ((bally+3 >= plr2_y && bally-3 <= plr2_y + 45)) //If the ball hit the paddle...
	{
		ball_hit = bally - plr2_y; //Place on the paddle the ball hit.
		diry = (ball_hit/5) -5; //where the ball hit the paddle determines the new y-angle of the ball.
		if (diry==-5){diry=-4;} //keeps the steepness from being too sharp.
		if (diry==5){diry=4;}
		p=true; //The ball hit the paddle and has a new angle.
		/* Intent--The place the computer wants the ball to hit next time */
		intent = (int)(1 + Math.random() * (34-1 + 1));
		ball_right = false;
		if (speed > 10){speed = speed -1;} //Makes the ball travel faster.
			
	}
	if (p==false){ball_was_missed = true;}
}	
/*** BALL HIT THE LEFT BOUNDARY ***/
public void left_bound()
{
		p=false;
	if ((bally+3 >= plr1_y && bally-3 <= plr1_y + 45))//If the ball hit the paddle...
	{
		ball_hit = bally - plr1_y;//Get where on the paddle the ball hit.
		
		/* Calculates the new direction */
		diry = (ball_hit/5) -5; //Get the new angle of the ball depending on where the ball hit the paddle.
		/*Keeps the angle from becoming too sharp*/
		if (diry==-5){diry=-4;}
		if (diry==5){diry=4;}
		p=true; //The ball hit the paddle and has a new angle.
		ball_right = true;
		if (speed > 10){speed = speed -1;}//Makes the ball travel faster.
	}
	if (p==false){ball_was_missed = true;}
}
public void adjust_speed()
{
	/* This function keeps the game running at a steady pace regardless of what angle the ball is traveling on.*/	
	if ((diry == 4) || (diry ==-4)){speed = 2;}
	if ((diry == 3) || (diry ==-3)){speed = 3;}
	if ((diry == 2) || (diry ==-2)){speed = 4;}
	if ((diry == 1) || (diry ==-1)){speed = 5;}
	if ((diry == 0)){speed =5;}
}

public void move_paddles()
{
	//The computer's paddle will only start moving once the ball is past the middle of the screen.
	if (ballx >ball_right_bound/2-100){
	//Move up if too low, move down if too high...
		if (plr2_y-3 >=up_bound){
		if (bally < plr2_y+intent) {plr2_y = plr2_y -3;}}
	if (plr2_y+3 <=down_bound){ 
		if (bally > plr2_y+intent) {plr2_y = plr2_y +3;}}
	}
		
		/*If the paddle won't run over the bound if it moves in the chosen direction,move.*/
		if (plr1_up==true && plr1_y - 3 >= up_bound){plr1_y = plr1_y -3;} 
		if (plr1_up==false && plr1_y + 3 <= down_bound){plr1_y = plr1_y +3;}
}
public void move_ball()
{
	if(user_is_playing)
	{
	/* The ball will only move in a random direction if it hits a horizontal boundary, like the paddle.*/
		if (bally < ball_up_bound) {diry = (diry-diry-diry);}
		if (bally > ball_down_bound) {diry = (diry-diry-diry);}
				
		/* Changes ball position.*/
		bally = bally + diry;
		if (ball_right == true){ballx = ballx + speed;}
		if (ball_right == false){ballx = ballx - speed;}
		
		//If the ball was missed, this adds one to a score and resets the ball.*/
		if(ball_was_missed)
		{
			if ((ballx < ball_left_bound)||(ballx>ball_right_bound))
			{
				if (ballx < ball_left_bound){++comp_score;if(comp_score==10){comp_won=true;}user_missed=true;display_miss=true;user_is_playing=false;ball_start(user);}
				if (ballx >ball_right_bound){++user_score;if(user_score==10){user_won=true;}comp_missed=true;display_miss=true;user_is_playing=false;ball_start(comp);}
				
			}
		}
		if(user_is_playing)
		{
		/* Collision detection */
		/* If the ball is at the left boundary */
		if ((ball_right==false)&&(ballx <= plr1_x + paddle_w)&&ballx>ball_left_bound){left_bound();}
		/* If the ball is at the right boundary */
		if ((ball_right==true)&&(ballx >= plr2_x - paddle_w)&&ballx<ball_right_bound){right_bound();}
		}
	}
}

public void paint(){}
  

public void update(Graphics g) {
	/* The double buffering prevents flickering. */	// clear the exposed area
	offgc.setColor(getBackground());
	offgc.fillRect(0, 0, 400, 260);
	offgc.setColor(getForeground());
		// do normal redraw of where things are now.
	offgc.setColor(Color.green);	offgc.setFont(ComicSansSmall);
		if (program_running == false) 	{		offgc.drawString("Hit Any Key to Play!",Press_Any_Key_X,Press_Any_Key_Y);		offgc.drawString("This Game was Programmed by Melissa Smith",80,150);	}
	if (display_miss==true)
	{
		offgc.drawString("Hit Any Key to Continue!",Press_Any_Key_X,Press_Any_Key_Y);
				if(user_missed)		{			if(!(got_message)){which_message =(int)(1 + Math.random() * (18-0 + 0));got_message=true;}			got_message=true;
			offgc.drawString(Bad_Messages[which_message],Bad_Message_X,Bad_Message_Y);
					}		if(comp_missed)		{			if(!(got_message)){which_message=(int)(1 + Math.random() * (15-0+0));got_message=true;}
			offgc.drawString(Good_Messages[which_message],Good_Message_X,Good_Message_Y);		}	}
	/* If someone wins, this changes the color of the lines and text on the playfield and tells the user who won.*/	if ((comp_won==true)||(user_won==true)){
			if (comp_won==true){				offgc.setColor(Color.red);
				offgc.drawString("Game Over, You Lost!",Game_Over_X,Game_Over_Y);}			if (user_won==true){				offgc.setColor(Color.red);
				offgc.drawString("Game Over, You Won!",Game_Over_X,Game_Over_Y);}		user_is_playing = false;	}	
		/*Display the score.*/	offgc.setFont(ComicSansSmall);
	offgc.drawString("Computer's Score: "+comp_score,CompScore_X,CompScore_Y);	offgc.drawString("Your Score: "+user_score,UserScore_X,UserScore_Y);
	/*Draw the ball.*/
	offgc.fillOval(ballx,bally,10,10);	/*Draw the lines*/
	offgc.fillRect(0,0,400,3);	offgc.fillRect(0,247,500,3);	offgc.fillRect(397,0,3,250);
	offgc.fillRect(0,0,3,250);
	/*Draw the starting circle for the ball*/
	offgc.setColor(Color.blue);	offgc.drawOval(185,110,20,20);	/*Draw the paddles*/
	offgc.setColor(Color.green);	offgc.fillOval(ballx,bally,10,10);
	offgc.fillRoundRect(plr1_x,plr1_y,paddle_w,paddle_h,10,10);	offgc.fillRoundRect(plr2_x,plr2_y,paddle_w,paddle_h,10,10);
	paint(offgc);
	// transfer offscreen to window	g.drawImage(off_screen_image, 0, 0, this);	
}


public void stop() {
    if(main!=null) {
      main.stop();
      main = null;
    }
  }

public void keyTyped(KeyEvent e){
	if(e.getKeyChar()=='w'){plr1_up=true;} //Go Up
	if(e.getKeyChar()=='s'){plr1_up=false;} //Go Down
	program_running = true;
	user_is_playing=true;
	display_miss=false;
	comp_missed=false;
	user_missed=false;
	got_message=false;
	/* Resets the game once it's over*/
	if ((user_won)||(comp_won))
	{
		user_is_playing=true; 
		user_won=false;
		comp_won=false;
		user_score=0;
		comp_score=0;
	}
	
}
public void keyPressed(KeyEvent e){}

public void keyReleased(KeyEvent e){}

public void Pick_Message(int loser)
{

}
}
