//SimplePong is a java applet written by Daniel Moscufo
//of scufo http://www.esearch.com.au/scufo. It can be 
//considered freeware.

import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.lang.Math;
import java.net.*;
import java.awt.image.*;

public class SimplePong extends Applet
{    
    public void init()
    {
	//Set default colour=black, width=300, height=80
	//Difficulty =5, image = backing.gif
	int bcRed = 0;
	int bcBlue = 0;
	int bcGreen = 0;
	int Width = 300;
	int Height = 80;
	int Difficulty = 5;
	String backimage = "backing.gif";
	
	//Check for user parameters
	if(getParameter("Red")!=null)
	    bcRed = new Integer(getParameter("Red").trim()).intValue();
	if(getParameter("Blue")!=null)
	    bcBlue = new Integer(getParameter("Blue").trim()).intValue();
	if(getParameter("Green")!=null)
	    bcGreen = new Integer(getParameter("Green").trim()).intValue();
	if(getParameter("Width")!=null)
	    Width = new Integer(getParameter("Width").trim()).intValue() -20;
	if(getParameter("Height")!=null)
	    Height = new Integer(getParameter("Height").trim()).intValue()-20;
	if(getParameter("Difficulty")!=null)
	    Difficulty = new Integer(getParameter("Difficulty").trim()).intValue();
	if(getParameter("BackImage")!=null)
	    backimage= getParameter("BackImage");
	
	//Set these above values
	setBackground(new Color(bcRed,bcGreen,bcBlue));
	Image ball = getImage(getCodeBase(), "ball.gif");
	Image paddle1 = getImage(getCodeBase(),"panel1.gif");
	Image paddle2 = getImage(getCodeBase(),"panel2.gif");
	Image back = getImage(getCodeBase(),backimage);
	Image toplay = getImage(getCodeBase(),"Toplay.gif");
	        
	//Create new Pongtable with correct values
	PongTable pongtable = new PongTable(Width,Height,ball,paddle1,paddle2,back,toplay, Difficulty);

	//this below code is just to add a centered pong game
	setLayout(new BorderLayout());
	Panel centredpanel = new Panel();
	centredpanel.add(pongtable);
	add(centredpanel, "Center");
    }

}

class PongTable extends Canvas implements Runnable, MouseMotionListener, MouseListener
{
    int Xsize, Ysize, Xball, Yball, Xbat, Ybat, XbatC, YbatC, difficulty;
    double direction[] = new double[2];
    Thread thisthread;
    int Xbatdir[] = new int[2];
    int Ybatdir[] = new int[2];
    boolean Centred = true;
    Image ball, paddle1, paddle2, back, toplay;
    //AudioClip pong;

    PongTable(int xsize, int ysize, Image Ball, Image Paddle1, Image Paddle2, Image Back, Image Toplay, int Difficulty)
    {
	
	//This method just setups all the variables
	Toolkit toolkit = Toolkit.getDefaultToolkit();
	addMouseMotionListener(this);
	addMouseListener(this);
	setSize(xsize,ysize);
	Xsize = xsize;
	Ysize = ysize;
	startpositions();

	Xball = (int)Xsize/2;
	Yball = (int)Ysize/2;
	direction[0] = 0;
	direction[1] = 0;
	
	ball = Ball;
	paddle1 = Paddle1;
	paddle2 = Paddle2;
	back = Back;
	toplay = Toplay;
	difficulty = Difficulty;
	
	//Start the thread.
	thisthread = new Thread(this);
	thisthread.start();
	
    }
    
    void startpositions()
    {
	//Specify the start positions
	Xball = 20;
	Yball = 20;
	Xbat = 20;
	Ybat = 40;
	XbatC = Xsize -20;
	YbatC = 40;
	direction[0] = 4.0; //X velocity vector
	direction[1] = 4.0; //Y velocity vector
    }

    public void update(Graphics g) 
    {
	//This is just your standard double buffering update method
	Graphics offgraph;
	Image offscreen = null;
	Dimension d = getSize();
       	offscreen = createImage(d.width, d.height);
	offgraph = offscreen.getGraphics();
	offgraph.setColor(getBackground());
	offgraph.fillRect(0, 0, d.width, d.height);
	offgraph.setColor(getForeground());
	paint(offgraph);
	g.drawImage(offscreen, 0, 0, this);
	offscreen.flush();
    }
    
    public void paint(Graphics g)
    {
	//Draw Background Image
	g.drawImage(back,5,5,Xsize-10,Ysize-10,this);
	//Draw users bat
	g.drawImage(paddle1,XbatC-2,YbatC-10,this);
	//Draw computer bat
	g.drawImage(paddle2,Xbat-2,Ybat-10,this);
	//draw ball
	g.drawImage(ball,Xball-5, Yball-5,this);
	
	//check if no one is playing and display "click to play"
	if(Centred)
	    g.drawImage(toplay,10, 10,this);
    }

    public void run()
    {
	double Xballdb, Yballdb;
	Xballdb = Xball;
	Yballdb = Yball;
	int n;

	while(true)
	    {
		//We check for ball hitting surface 4 times for every repaint()
		for(n=0;n<4;n++)
		    {
			//increase X & Y by velocity/4
			Xballdb = Xballdb + direction[0]/4;
			Yballdb = Yballdb + direction[1]/4;
			
			//check if ball hit either "goal"
			//centred tells that game is over
			if(Xballdb<10 || Xballdb>Xsize-10)
			    {
				Xballdb = Xsize/2;
				Yballdb = Ysize/2;
				direction[0] = 0;
				direction[1] = 0;
				Centred = true;
			    }
		
			//Check if ball hits either top or bottom wall
			// if so change y to = -y
			if(Yballdb<10 || Yballdb>Ysize-10)
			    {
				direction[1]=-1*direction[1];
			    }

			//Now we see if bat hits players bat
			if(Xballdb>18 && Xballdb<27)//X thickness of bat
			    //check if ball is within 10 pixels Y dirn
			    //of bat
			    if(Math.abs(Yballdb-Ybat)<=10)
				{
				    //if so x = -x + x bat movement dirn, 
				    //y = -y + y bat movement dirn
				    direction[0] = -1*direction[0]+(int)((Xbatdir[0]-Xbatdir[1])/8);
				    direction[1] = direction[1]+(int)((Ybatdir[0]-Ybatdir[1])/8);
				    //place ball at front of bat
				    Xballdb=28;				    
				}
		
			//Now we do the same for computer bat
			if(Xballdb<(Xsize-15) && Xballdb>(Xsize-22))
			    if(Math.abs(Yballdb-YbatC)<=10)
				{
				    //x = -x - random no.
				    direction[0] = -1*direction[0] + -1*Math.random();
				    //y = -y + random no proportional to x speed
				    //This helps in stopping the ball going
				    //back and further on same y value
				    direction[1] = direction[1] + (direction[0]/4)*Math.sin(Math.random()*2*Math.PI);
				    //place ball on front of bat
				    Xballdb=Xsize-23;
				}
		    }
		
		//send paint correct coords
		Xball = (int)Xballdb;
		Yball = (int)Yballdb;

		//ok now do Computer AI
		//check ball in our half
		if(Xball>Xsize/2)
		    {
			//ok this algorithym is simple but effective
			//firstly check the bat and ball aren't the same height
			//then find if bat is above or below the bat
			//then move bat up/down by difficulty pixels
			if((Yball-YbatC)!=0)
			    YbatC = (Yball-YbatC)/(Math.abs(Yball-YbatC))*difficulty + YbatC;
		    }
		
		//recall the paint method
		repaint();
		
		//Ok sleep the thread fo 50 ms
		try
		    {
			thisthread.sleep(50);
		    }
	
		catch(Exception e)
		    {
			System.out.println("Error on sleep");
		    }

	    }
    }

    public void mouseMoved(MouseEvent e)
    {
	int x = e.getX();
	int y = e.getY();
	
	//Ok here we move the bat by setting it equal to mouse height
	if(y>15 && y<Ysize-10)
	    {
		Ybat = y;
		//below we set up the bat movement dir'n. so the player
		//can influence the ball dir'n.
		Xbatdir[1] = Xbatdir[0];
		Ybatdir[1] = Ybatdir[0];
		Xbatdir[0] = x;
		Ybatdir[0] = y;
	    }
	
	repaint();
    }
    
    public void mouseDragged(MouseEvent e)
    {
    }

    public void mousePressed(MouseEvent e)
    {
    }

    public void mouseReleased(MouseEvent e)
    {
    }

    public void mouseClicked(MouseEvent e)
    {
	//Check if "start new game"
	if(Centred)
	    {
		startpositions();
		Centred = false;
	    }
	    
    }

     public void mouseEntered(MouseEvent e)
    {	
    }

     public void mouseExited(MouseEvent e)
    {
    }
}








