//Waste'em is a java game applet written by Daniel Moscufo for Scufo
//http://www.esearch.com.au/scufo. It can be considered freeware
//and the code can be altered at will.

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


public class Wastem extends Applet implements ActionListener
{    
    Image bird, logo;
    AudioClip Shot_AC, Hit_AC, Empty_AC;
    
    public void init()
    {
	//Setup color and layout
	//null Layout isn't good but it is easier than fooling
	//round with the gridbaglayout for such a simple layout
	setBackground(Color.black);
	setLayout(null);
	
	//We load the audio first as there is no support
	//for AudioClips in the mediatracker class
	//therefore we hope they load before the images
	Shot_AC = getAudioClip(getCodeBase(),"shot.au");
	Hit_AC = getAudioClip(getCodeBase(),"crash.au");
	Empty_AC = getAudioClip(getCodeBase(),"empty.au");
	
	//We track the loading of images so that when the
	//game starts, the player can see all the images
	MediaTracker tracker = new MediaTracker(this);

	//Get theImages
	bird = getImage(getCodeBase(), "ball.gif");
	Image blast = getImage(getCodeBase(), "bang.gif");
	Image hit = getImage(getCodeBase(), "blast.gif");
	
	//Add Images to media tracker
	tracker.addImage(blast, 0);
	tracker.addImage(bird, 1);
	tracker.addImage(hit, 2);
	
	//Wait for images to load
	try
	    {
		tracker.waitForID(0);
		tracker.waitForID(1);
		tracker.waitForID(2);
	    }

	catch(Exception e)
	    {
		System.out.println("Error in waiting for images: " + e);
	    }
	
	//Load up a new ShootRange object, the main part of the game
	//Applet is setup this way as I have learnt if you run the game
	//straight from the applet instead of passing all the images
	//and sounds to a different class, the applet wants to keep
	//loading the images and sounds from the server. 
	//This way loads components once as well as making code easier 
	//to maintain and more portable to application or component of 
	//other applets.

	ShootRange shootrange = new ShootRange(bird,blast,hit,Shot_AC,Hit_AC,Empty_AC,350,100);
	shootrange.setBounds(0,0,350,100);	
	add(shootrange);
	
	//Now I had my logo on the right hand side. 
	//Clicking on the image is handled in this class
	logo = getImage(getCodeBase(),"ScufoLo.gif");
	ImageCanvas logocanvas = new ImageCanvas(logo,94,52,"http://www.esearch.com.au/scufo");
	logocanvas.addActionListener(this);
	logocanvas.setBounds(360,24,100,52);
	add(logocanvas);
    }
    
     public void actionPerformed(ActionEvent e)
    {
	
	String arg = e.getActionCommand();
	//redirect browser to my page.
	gotourl(new String(arg));
	
    }

    //This following code was written by me. It is usefull in
    //sending a browser to any given page. Use it at will
    void gotourl(String urlstring)
    {
	try
	    {
		URL url1 = new URL( urlstring );
		AppletContext appletcontext1 = getAppletContext();
		
		appletcontext1.showDocument(url1, "_top");
	    }
	catch( MalformedURLException malformedurlexception1 )
	    {
		malformedurlexception1.printStackTrace();
	    }
	//System.out.println(urlstring);
    }


}


//Ok now we code the game
class ShootRange extends Canvas implements MouseListener, Runnable
{
    int mousex,mousey,Xsize,Ysize; //standard mouse locations and game size
    int birdmax = 10;//number of "birds" in a level
    int score; //your score
    int level; //level
    int bullets; //number of bullets or shots left
    int waittime; //how long the thread sleeps
    
    double blast = 15.0;// radius allowed from center of shot to
    //center of target "bird"

    double birdx[] = new double[birdmax];//Birds x coord
    double birdy[] = new double[birdmax];//Birds y coord
    double birdvx[] = new double[birdmax];//Birds x velocity
    double birdvy[] = new double[birdmax];//Birds y velocity
    int birdstart[] = new int[birdmax];//starting location of birds
    int birddirn[] = new int[birdmax];//direction ie start from left=1, right=-1
    
    boolean wait = false;//displays change of level tag
    
    int fire = -1;//these two are counters for the blast shots. When
    int shot = -1;//a target is hot, fire goes on for 4 cycles, shot for 2

    boolean gameover = true; // see if game is over
    Cursor cursor;
    Image Bird, Blast, Hit; //images
    Thread thisthread;
    AudioClip Shot_AC, Hit_AC, Empty_AC; //audio clips


    ShootRange(Image bird, Image blast, Image hit, AudioClip shot_ac, AudioClip hit_ac, AudioClip empty_ac,int xsize, int ysize)
    {
	int n;  //standard counter
	Xsize = xsize;
	Ysize = ysize;

	addMouseListener(this);
	
	//basic setup
	setSize(Xsize,Ysize);
	setBackground(Color.cyan);
	setCursor(cursor.getPredefinedCursor(cursor.CROSSHAIR_CURSOR));
	mousex = 0;
	mousey = 0;
	Bird = bird;
	Blast = blast;
	Hit = hit;
	Shot_AC=shot_ac;
	Hit_AC=hit_ac;
	Empty_AC=empty_ac;
	
	//call startpositions for new game
	startpositions();
	
	//start the thread
	thisthread = new Thread(this);
	thisthread.start();
    }

    void startpositions()
    {
	//This code just resets all the variables to a new game status
	waittime=40;
	score=0;
	bullets=12;
	level=0;
    }


    //Ok this code just checks that the distance from a click to a birds
    //centre coords is less than blast distance
    boolean checkhit(int x1, int y1 , int x2, int y2, int n)
    {
	if(Math.sqrt(Math.pow(x1-x2,2) + Math.pow(y1-y2,2))<=blast)
	    {
		//If the bird is hit move it off the screen and stop displaying
		//it NB 500 is greater than maximum time of 350 so never is
		//shown
		birdx[n] = -1;
		birdy[n] = -1;
		birdvx[n]= -1;
		birdvy[n]= -1;
		birdstart[n] = 500;
		return true;
	    }
	
	else
	    {
		//System.out.println("Miss");		
		return false;
	    }
    }
    
    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)
    {
	int n;
	
	//this draw all the birds who should be on screen
	for(n=0;n<birdmax;n++)
	    if(birdx[n]!=-1)
		{
		    g.drawImage(Bird,(int)birdx[n]-5,(int)birdy[n]-5,this);
		}
	
	//Check to see if level display is on
	if(wait)
	    g.drawString("Level " + level,90,40);
	
	//check to see if gameover is on
	if(gameover)
	     g.drawString("Game Over. Click to play",90,40);
	
	//if fire is on draw shotgun blast
	if(fire>=0)
	    g.drawImage(Blast,mousex-15,mousey-15,this);
	
	//if a target is hit display explosion
	if(shot>=0)
	    g.drawImage(Hit,mousex-15,mousey-15,this);
	
	//Now we draw the scorecard
	g.setColor(Color.black);
	g.fillRect(0,0,60,Ysize);

	//draw the score values
	g.setColor(new Color(189,198,0));
	g.drawString("" + score,10,20);
	g.drawString("" + level,10,40);
	g.drawString("" + bullets,10,60);
	g.drawString("" + 8*level,10,80);

	//draw the score labels
	g.setColor(Color.red);
	g.drawString("Score",10,10);
	g.drawString("Level",10,30);
	g.drawString("Shells",10,50);
	g.drawString("Target",10,70);
    }
    
    //Ok now we setup the thread
    public void run()
    {
	int n;
	double velocityx=4.5; //these are the nominal velocities in x
	double velocityy=1.70;//and y dirn
	
	int i;//another counter
	
	while(true)//always cycle
	    if(!gameover)//game is on
		for(n=0;n<350;n++)//level goes for 350 cycles
		    {
			if(fire>=0)//If we are drawing the fire image reduce
			    fire--;//count by 1

			if(shot>=0)//if we are drawing shot image reduce
			    shot--;//count by 1
			
			if(n==1)//Start of level
			    {
				//now we setup this level
				for(i=0;i<birdmax;i++)
				    {
					//first split the bords up as to which
					//side of screen they enter from
					if(Math.random()>0.5)
					    birddirn[i]=1;
					
					else
					    birddirn[i]=-1;
					
					//now vary starting velocities by a 
					//random number as well as set the
					//correct direction
					birdvx[i] = birddirn[i] * (velocityx + 2 * Math.random());
					birdvy[i] = velocityy + 2 * Math.random();
					//Ok now we setup starting coords
					//the number below are just to make it
					//easier for me to understand the
					//effect of the scoreboard (size 60)
					//the 10 is to start the birds 10 
					//pixels offscreen either side.
					birdx[i] = (Xsize-60)/2 - birddirn[i]*((Xsize-60)/2+10)+60;
					birdy[i] = 70;
					//now we vary the start time of each bird
					birdstart[i] = (int)(300.00*Math.random());
				    }
				
				//set bullets to 12
				bullets = 12;
				//increase level number
				level++;
				//turn level display on
				wait = true;
			    }
			
			//check if a bird is in flight
			for(i=0;i<birdmax;i++)
			    if(n>=birdstart[i])//started yet
				{
				    //check if bird has made it passed without
				    //being shot
				    if(birdy[i]>=Ysize)
				      {
				          //set it so it doesn't appear in calcs
					  //any more
					  birdstart[i]=500;
					  birdy[i]=Ysize+20;
					}
				    
				    //ok effect of gravity is -g, g=9.8m/s^2
				    //but we are far away therefore distance
				    //is less so by this calc we are 98 m from
				    //targets in earth gravity.
				    birdvy[i] = birdvy[i] - 0.1;
	
				    //move bird along by vx and vy
				    birdx[i] = birdx[i] + birdvx[i];
				    birdy[i] = birdy[i] - birdvy[i];
	
				    
				}
		
		       
			//turn level display off
			if(n==10)
			    wait=false;
			
			//check if we passed the level
			if(n>=348 && score>=8*level)
			    {
				//restart counter
				n=0;
				
				//Ok this is how we make the game harder
				//we run thru exactly the same program, only
				//we reduce the sleep time. Therefore
				//game goes quicker. Simple yes, but
				//effective.
				waittime=(int)(waittime * 0.92);
			    }
			
			//If it makes it this far the game is over
			if(n>=349)
			    {
				System.out.println("Game Over");
				gameover=true;
			    }
			
			//Ok now we sleep the thread for waittime milliseconds
			try
			    {
				thisthread.sleep(waittime);
			    }
			
			catch(Exception e)
			    {
				System.out.println("Error on sleep");
			    }
			repaint();
		    }

	//If the game is over we will sleep for longer so as not to tie up
	//much cpu resources
	    else
		{
		    try
			{
			    thisthread.sleep(500);
			}
		    
		    catch(Exception e)
			{
			    System.out.println("Error on sleep");
			}
		    repaint();
		}
    }
    
   
    public void mouseClicked(MouseEvent e)
    {
    }

    public void mouseReleased(MouseEvent e)
    {
    }


    //Ok this checks if the mouse has been pressed and
    //sends the coords for processing
    public void mousePressed(MouseEvent e)
    {
	//If pressed and gameover, must be new game.
	if(gameover)
	    {
		gameover=false;
		startpositions();
	    }
	
	//otherwise shot at bird
	else
	    {
		//get coords
		int x = e.getX();
		int y = e.getY();
		
		//set them for image display
		mousex=x;
		mousey=y;
		
		//if we have bullets left
		if(bullets>0)
		    {
			//display fire image
			fire = 2;
			//play shotgun fire sound
			Shot_AC.play();
			
			//decrease bullet count
			bullets --;
			int n;
			
			//now we check if the shot was near any of the birds
			for(n=0;n<birdmax;n++)
			    {
				if(checkhit(x,y,(int)birdx[n],(int)birdy[n],n))
				    {
					//If we get one play hit sound
					Hit_AC.play();
					shot = 4;//start shot graphic
					score++;//increase score by 1
				    }
			    }
		    }

		else//if we have no bullets play empty cartridge sound
		    Empty_AC.play();
	    }
	repaint();
		
    }

     public void mouseEntered(MouseEvent e)
    {	
    }

     public void mouseExited(MouseEvent e)
    {
    }
}


//Ok this is a class written by me to display images and when
//clicked it returns the string it was given when initiated
class ImageCanvas extends Canvas implements  MouseListener
{
    
    private Vector listeners = new Vector(); 
    Image canvasImage;
    int Xsize;
    int Ysize;
    String Name;
    Cursor cursor;
    public ImageCanvas(Image image, int X, int Y, String name)
    {
	addMouseListener(this);
	canvasImage = image;
	Xsize = X;
	Ysize = Y;
	setSize(Xsize+5,Ysize);
	Name = name;
    }
   
     public void mousePressed(MouseEvent e)
    {
    }

    public void mouseDragged(MouseEvent e)
    {
    }

    public void mouseReleased(MouseEvent e)
    {
    }

    public void mouseClicked(MouseEvent e)
    {
	//System.out.println("Hello");
	notifyListeners();
    }

     public void mouseEntered(MouseEvent e)
    {
	setCursor(cursor.getPredefinedCursor(cursor.HAND_CURSOR));

    }

     public void mouseExited(MouseEvent e)
    {
	cursor.getDefaultCursor();
    }

    public void addActionListener(ActionListener listener)
    {
	if(!listeners.contains(listener))
	    listeners.addElement(listener);
    }

    public void removeActionListener(ActionListener listener)
    {
	listeners.removeElement(listener);
    }

    private void notifyListeners()
    {
	ActionListener listener;
	ActionEvent event = new ActionEvent(this, AWTEvent.RESERVED_ID_MAX+1, Name);
	
	Vector copyOfListeners = (Vector)(listeners.clone());
	Enumeration enum = copyOfListeners.elements();
	while (enum.hasMoreElements())
	    {
		listener = (ActionListener)enum.nextElement();
		listener.actionPerformed(event);
	    }
    }

	    public void paint(Graphics g)
    {
	g.drawImage(canvasImage, 5, 0, Xsize, Ysize, this);

    }
}













