import java.applet.*;
import java.awt.*;


public class move extends java.applet.Applet implements Runnable {
	boolean start = false; // Determines whether the game is to start or not
	byte speed = 3; // Speed of the ball
	short rally_count = 0; // Number of rallies
   byte width, height; // Width and height of the paddles
   short x, y; // Position of the user paddle
   short e_x, e_y; // Position of the enemy paddle
   short e_l_x, e_l_y; // Laser Position
   short u_l_x, u_l_y = - 10; // Laser Position
   short heading = 0; // Where the enemy paddle wants to go
   byte y_dir; // Direction of the user paddle(up/down)
   short ballx, bally; // x and y positions of the ball
   char ballxDir = 'l'; // Direction of the ball in the x direction
   char ballyDir = 'u'; // Direction of the ball in the y direction
   int uscore_val; // int value for user score
   int escore_val; // int value for enemy score
   boolean fire_laser; // Test variable to see if the user wants the laser fired
   Thread animator;
   AudioClip music; // Background music track
   AudioClip laserHit;
   AudioClip laser;
   String uscore; // String value for user score
   String escore; // String value for enemy score
   Image logo; // Logo for the game "Extreme Pong"
   int logo_y = 100;
   byte logo_dir = -1;
   Image backbuffer; // Back Buffer 
   Graphics backg; // Back Buffer
   Image backbuffer2; // Back Buffer 
   Graphics backg2; // Back Buffer

   
   long fps = 60;
   long frame_count = 0; // Counts the number of frames
   long frame_count_laser = 0;
   long frame_count_e_temp; // Used for when the enemy gets hit by the laser
   long frame_count_u_temp; // Used for when the user gets hit by the laser
   public void init() {
	   
	  fps = 1000/fps;
      setBackground( Color.black );
      width = 10;
      height = 50;
      x = 20;
      y = 235;
      e_x = 790;
      e_y = 235;
      ballx = 405;
      bally = 255;
      backbuffer = createImage( 820, 520 );
      backbuffer2 = createImage( 820, 520 );
      backg = backbuffer.getGraphics();
      laserHit = getAudioClip(getCodeBase(), "TESLA1.au");
      laser = getAudioClip(getCodeBase(), "zap6.au");
      music = getAudioClip(getCodeBase(), "Jenova.au");
      music.loop();

   }
   
   public void start() {
		animator = new Thread(this);
		animator.start();
	    }
   public void player_paddle(byte y_dir){
	   if (y > 11 && y_dir == -1 && frame_count > frame_count_u_temp + 15){ // Moving player paddle upwards
		   byte distance=5; // Distance that the paddle will go
		   if (y == 12){
			   distance = 1;
		   }
		   else if (y == 13){
			   distance = 2;
		   }
		   else if (y == 14){
			   distance = 3;
		   }
		   else if (y == 15){
			   distance = 4;
		   }
		   else{
			   distance = 5;
		   }
		   y += y_dir*distance;
	   }
	   if (y < (510 - height) && y_dir == 1 && frame_count > frame_count_u_temp + 15){ // Moving player paddle downwards
		   byte distance=5; // Distance that the paddle will go
		   if (y == (509 - height)){
			   distance = 1;
		   }
		   else if (y == (508 - height)){
			   distance = 2;
		   }
		   else if (y == (507 - height)){
			   distance = 3;
		   }
		   else if (y == (506 - height)){
			   distance = 4;
		   }
		   else{
			   distance = 5;
		   }
		   y += y_dir*distance;
	   }
   }
   
   public void enemy_paddle(){
	   
	   if(ballx <= (20 + width) && ballyDir == 'u'){ // Executes when the ball hits the user paddle when going up
		   heading = (short)(760 - bally) ;
		   if (heading >= 500){ // Hits the wall more than once
			   heading -= 500;
			   heading = (short)(500 - heading);
			   heading -= (height/2);
		   } 
		   else{ // Hits the wall only once
			   heading -= (height/2);
		   }
	   }
	   else if(ballx <= (20 + width) && ballyDir =='d'){ // Executes when the ball hits the user paddle when going down
		   heading = (short)(760 - bally);
		   if (heading >= 500){ // Hits the wall only once
			   heading -= 500;
			   heading -= (height/2);
		   }
		   else{ // Hits the wall more than once
			   heading = (short)(500 - heading); 
			   heading += (height/2);
		   }
	   }
	   if (ballx < 405 && speed < 6){
		   if (ballxDir == 'r' && ballyDir =='u'){
			   heading -= speed;
		   }
		   else if (ballxDir == 'r' && ballyDir == 'd'){
			   heading += speed;
		   }

	   }
	   else if(ballx >= 405 && speed < 6){
		   heading = bally;
	   }
	   else if (ballx >= 405 && speed >= 6 && ballyDir == 'u'){
		   heading = (short)(bally - speed*(speed - 2) - (speed -2));
	   }
	   else if (ballx >= 405 && speed >= 6 && ballyDir == 'd'){
		   heading = (short)(bally + speed*(speed - 2) + (speed -2));
	   }
	   
	   
	   if (ballxDir == 'l')
	   {
		   if (y_dir == -1){
			   heading = (short)((y/2)-(ballx/2));
		   }
		   else if (y_dir == 1){
			   heading = (short)((y/2)+(ballx/2));
		   }
		   else if (y_dir == 0){
			   heading = (short)((y/2)+(bally/2));
		   }
	   }
	   if (heading > e_y && e_y < (509 - height) && frame_count > frame_count_e_temp + 15){
		   int distance=5; // Distance that the enemy paddle will go
		   if (e_y == (508 - height)){
			   distance = 1;
		   }
		   else if (e_y == (507 - height)){
			   distance = 2;
		   }
		   else if (e_y == (506 - height)){
			   distance = 3;
		   }
		   else if (e_y == (505 - height)){
			   distance = 4;
		   }
		   else{
			   distance = 5;
		   }
		   e_y += distance;
	   }
	   if (heading < e_y && e_y > 11 && frame_count > frame_count_e_temp + 15){
		   int distance=5; // Distance that the enemy paddle will go
		   if (e_y == 12){
			   distance = 1;
		   }
		   else if (e_y == 13){
			   distance = 2;
		   }
		   else if (e_y == 14){
			   distance = 3;
		   }
		   else if (e_y == 15){
			   distance = 4;
		   }
		   else{
			   distance = 5;
		   }
		   e_y += -distance;
	   }
   }
   public void enemy_laser(){
	   if (frame_count % 120 == 0){
		   e_l_y = (short)(e_y + (height/2));
		   e_l_x = (short)(e_x-width);
		   laser.play();
	   }
		   e_l_x -= 9;
	   
	   if (e_l_x <= 30 && e_l_x >= 20 && e_l_y >= y && e_l_y <= (y+height)){
		   escore_val += 15;
		   frame_count_u_temp = frame_count;
		      laserHit.play();
	   }
   }
   public void user_laser(){
	   if (frame_count_laser % 121 == 120 && fire_laser == true){
		   frame_count_laser = 0;
		   fire_laser = false;
		   u_l_y = (short)(y + (height/2));
		   u_l_x = (short)(x-width);
		   laser.play();
	   }
		   u_l_x += 9;
	   
	   if (u_l_x <= 800 && u_l_x >= 790 && u_l_y >= e_y && u_l_y <= (e_y+height)){
		   uscore_val += 15;
		   frame_count_e_temp = frame_count;
		      laserHit.play();
	   }
   }
   public void paddle_limits(int padx, int pady){
	   if (ballxDir == 'l' && ballx <= (padx + width) && ballx >= padx && bally >= (pady -5) && bally <= (pady + height -5)){ // Hits paddle from the right
		   ballxDir = 'r';
		   rally_count += 1;
		   uscore_val += speed;
	   }
	   else if (ballxDir == 'r' && ballx >= (padx - 10) && ballx <= (padx + width - 10) && bally >= (pady -5) && bally <= (pady + height -5)){ // Hits paddle from the left
		   ballxDir = 'l';
		   rally_count += 1;
		   escore_val += speed;
	   }
	   else if (ballyDir == 'd' && ballx >= (padx - 5) && ballx <= (padx + width - 5) && bally >= (pady - 10) && bally <= (pady + height)){ // Hits paddle from the top
		   ballyDir = 'u';
	   }
	   else if (ballyDir == 'u' && ballx >= (padx - 5) && ballx <= (padx + width - 5) && bally >= pady && bally <= (pady + height)){ // Hits paddle from the bottom
		   ballyDir = 'd';
	   }
	}
   
   public void ball(){
	   if (rally_count < 3){ // Changes speed of ball over time
		   speed = 3;
	   }
	   else if(rally_count < 6){
		   speed = 4;
	   }
	   else if(rally_count < 12){
		   speed = 5;
	   }
	   else if (rally_count < 24){
		   speed = 6;
	   }
	   else if (rally_count < 48){
		   speed = 7;
	   }
	   else if (rally_count < 96){
		   speed = 8;
	   }
	   else{
		   speed = 9;
	   }
		   player_paddle(y_dir); // Calls the method to move the paddle up or down
		   enemy_paddle(); // Calls the method to move the enemy paddle
	
		   if (ballxDir == 'l' && ballyDir == 'u'){ // Ball is moving Left & Up
			   ballx-= speed;
			   bally-= speed;
		   }
		   else if (ballxDir == 'l' && ballyDir == 'd'){ // Ball is moving Left & Down
			   ballx-= speed;
			   bally+= speed;
		   }
		   else if (ballxDir == 'r' && ballyDir == 'u'){ // Ball is moving Right and Up
			   ballx+= speed;
			   bally-= speed;
		   }
		   else if (ballxDir == 'r' && ballyDir == 'd'){ // Ball is moving Right and Down
			   ballx+= speed;
			   bally+= speed;
		   }
		   
		   paddle_limits(x,y);
		   paddle_limits(e_x,e_y);
		   
		   if (bally < 10){ // Changes ball direction from up to down
			   ballyDir = 'd';
		   }
		   else if (bally > 500){ // Changes ball direction from down to up
			   ballyDir = 'u';
		   }
		   if (ballx > 800){ // Game over for computer
			   ballx = 405;
			   ballxDir='l';
			   speed = 3;
			   rally_count = 0;
			   uscore_val += 50;
			   
		   }
		   else if(ballx < 10){ // Game over for user
			   ballx = 405;
			   ballxDir='r';
			   speed = 3;
			   rally_count = 0;
			   escore_val += 50;
		   }
   }
   public void run() {
	   while (Thread.currentThread() == animator){
		   repaint();
		   try {
				Thread.sleep(fps);
			    } catch (InterruptedException e) {
				break;
			    };
	   }
   }
   public void intro() {
	   logo = getImage(getDocumentBase(), "logo.png");
	   if (logo_y > 50 && logo_dir == -1){
		   logo_y--;
	   }
	   else if(logo_y < 150 && logo_dir == 1){
		   logo_y++;
	   }
	   if (logo_y <= 50){
		   logo_dir = 1;
	   }
	   else if (logo_y >= 150){
		   logo_dir = -1;
	   }
	   backg.setColor(Color.black);
	   backg.fillRect(0,0, 820, 520);
       backg.setColor( Color.red );
	   backg.drawRect(10, 10, 800, 500);
	   backg.drawString("To Start Click the game then press the Enter button.", 300, 400);
	   backg.setColor(Color.gray);
	   backg.drawString("Controls:", 300, 300);
	   backg.drawString("Move Up = Up Key", 360, 300);
	   backg.drawString("Move Down = Down Key", 360, 315);
	   backg.drawString("Fire Laser = Right Key", 360, 330);
	   backg.drawLine(20, 11, 20, 509);
	   backg.drawLine(800, 11, 800, 509);
	   backg.drawImage(logo, 210, logo_y, this);
   }
   public void primary() {
	   frame_count++;
	   if (frame_count_laser % 121 != 120){
		   frame_count_laser++;
	   }
	   uscore = uscore.valueOf(uscore_val);
	   escore = escore.valueOf(escore_val);
	   ball();
	   enemy_laser();
	   user_laser();
	   backg.setColor(Color.black);
	      backg.fillRect(0,0, 820, 520);
	      backg.setColor(Color.red);
	      backg.drawRect(35, 495, 60, 5); // Weapon reloader
	      backg.fillRect(35, 495, (int)(frame_count_laser % 121)/2, 5); // Weapon reloader
		  backg.drawRect(10, 10, 800, 500);
		  backg.drawLine(410, 10, 410, 510);
		  backg.drawRect(e_l_x, e_l_y-1, 30, 2); // Enemy Laser
		  backg.drawRect(u_l_x, u_l_y-1, 30, 2); // User Laser
		  backg.setColor(Color.orange);
		  backg.drawLine(e_l_x, e_l_y, e_l_x + 30, e_l_y); // Enemy Laser
		  backg.drawLine(u_l_x + 30, u_l_y, u_l_x, u_l_y); // User Laser
		  backg.setColor(Color.black);
		  backg.fillRect(0, 0, 9, 520);
		  backg.fillRect(811, 0, 9, 520);
		  backg.setColor(Color.gray);
		  backg.drawLine(20, 11, 20, 509);
		  backg.drawLine(800, 11, 800, 509);
	   backg.setColor( Color.white );
	   backg.fillRect( x, y, width, height );  // User Paddle
	   backg.fillRect( e_x, e_y, width, height );  // Enemy Paddle
	   backg.fillOval(ballx, bally, 10, 10);  // Ball
	   backg.setColor(Color.red);
	   backg.drawString(uscore, 350, 500);
	   backg.drawString(escore, 463, 500);
   }
   public void stop() {
	        music.stop();    //Stop the sound loop.
	}

   public boolean keyDown( Event e, int key ) {
	   if (key == Event.UP) // Moves Paddle Up
	   {
		   y_dir = -1;
	   }
	   if (key == Event.DOWN) // Moves Paddle Down
	   {
		   y_dir = 1;
	   }
	   if (key == Event.RIGHT) // Fires Laser
	   {
		   fire_laser = true;
	   }
	   if (key == Event.ENTER) // Starts Game
	   {
		   start = true;
	   }
	   return true;}
   public boolean keyUp( Event e, int key ) {
	   if (key == Event.UP || key == Event.DOWN)
	     {
	      y_dir = 0;
	     }
	    return true;
}
   public void update( Graphics g ) {
	   		run();
	   		if (start == false){
	   			intro();
	   		}
	   		else if(start == true){
	   			primary();
	   		}
	   		g.drawImage( backbuffer, 0, 0, this );
	   }

	   public void paint( Graphics g ) {
	      update( g );
	   }
}
