/*
 * @(#)Stk.java 1.0 03/04/24
 *
 * Copyright (C) 2004 Craig Nicholas
 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU 
 *
 * General Public License as published by the Free Software Foundation; either version 2 of the 
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
 * See the GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License along with this program; 
 * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307 USA
 *
 * Craig Nicholas
 * Website: www.britishplate.org.uk
 *
 */

 import java.awt.*;
 import java.awt.event.*;
 import java.applet.*;
 import java.lang.Math;
 import javax.swing.*;
 import javax.swing.border.*;
        
 public class Stk2 extends Applet {

     private Image knight, deadKnight, displayKnight, displayArcher, deadArcher, archer;
     private AudioClip hitSound, startSound,knightHitSound;
     Thread thread=null;
     private boolean threadStop=true;
     private Color backGround = null;
     JPanel controlArea = null;
     Game game = null;
     Score scoreArea = null;
     Difficulty difficultyArea = null;
     private boolean bSound = true;
     private JCheckBox soundCheck = null;
     
     // default constents for the class
     
     private int xInc = 1;
     private int yInc = 1;
     private int sleepTime = 5;
     private int maxSleeptime = 10;
            
     public void init() {
     	 MediaTracker tracker = new MediaTracker(this);
         hitSound = getAudioClip(getDocumentBase(),"ni.wav");
         knightHitSound = getAudioClip(getDocumentBase(),"ni.wav");
         startSound = getAudioClip(getDocumentBase(),"sword.wav");
         knight = getImage(getDocumentBase(), "knight.jpg");
         deadKnight = getImage(getDocumentBase(), "deadknight.jpg");
         archer = getImage(getDocumentBase(), "xbow.jpg");
         deadArcher = getImage(getDocumentBase(), "deadxbow.jpg");
         tracker.addImage(knight,0);
         tracker.addImage(deadKnight,0);
         tracker.addImage(archer,0);
         tracker.addImage(deadArcher,0);
         try {
             tracker.waitForID(0);
         } catch (Exception e) {}
		 
         
     	 Color backGround = Color.green.darker().darker();    
     	 Color foreGround = Color.yellow;
         this.setBackground(backGround);
         
         // get parameters if set.
         String xIncParam = getParameter ("xInc");
         String yIncParam = getParameter ("yInc");
         String diffParam = getParameter ("difficulty");
         
         if (xIncParam != null) {xInc = Integer.parseInt(xIncParam);}
         if (yIncParam != null) {yInc = Integer.parseInt(yIncParam);}
         if (diffParam != null) {sleepTime = Integer.parseInt(diffParam);}
         if (sleepTime > maxSleeptime) {sleepTime = maxSleeptime;}
         if (sleepTime < 1 ) {sleepTime = 1;}
         
         // set up window components

         // Button Panel
         JButton goButton = new JButton ("Start run..");
         goButton.addActionListener (new ActionListener() {
         	public void actionPerformed(ActionEvent ae) {
         		game.start();
         		}	
            }
      	 );

         soundCheck = new JCheckBox("Sound", true);
         soundCheck.setBackground(backGround);
         soundCheck.setForeground(foreGround);
         soundCheck.addActionListener (new ActionListener() {
         	public void actionPerformed(ActionEvent ae) {
         		if (soundCheck.isSelected())
         		{
         			bSound = true;
         		}
         		else
         		{
         			bSound = false;
         		}
         	
         		}	
            }
      	 );
         
         JPanel ButtonArea = new JPanel( new GridLayout(2,1));
         ButtonArea.setBackground(backGround);
         ButtonArea.add(soundCheck);
         ButtonArea.add(goButton);
       
       	 Border etch = BorderFactory.createEtchedBorder();
	     ButtonArea.setBorder (BorderFactory.createTitledBorder(etch,"Controls",
	         					TitledBorder.DEFAULT_JUSTIFICATION ,
	         					TitledBorder.DEFAULT_POSITION,
	         					getFont(),
	         					foreGround));

       
         // Difficulty panel
         difficultyArea = new Difficulty(sleepTime,maxSleeptime,foreGround,backGround);
         difficultyArea.setVisible(true);
                  
         // Score Panel
         scoreArea = new Score (foreGround,backGround);
         scoreArea.setVisible(true);
         
         // Control Area
         controlArea = new JPanel(new GridBagLayout());
         GridBagConstraints Con = new GridBagConstraints();
         controlArea.setBackground(backGround);
      
         Con.gridx=0;
         Con.gridy=1;
         Con.fill = GridBagConstraints.NONE;
         Con.anchor = GridBagConstraints.WEST;
         controlArea.add (ButtonArea, Con);
         
         Con.gridx=0;
         Con.gridy=2;
         //Con.fill = GridBagConstraints.HORIZONTAL;
         Con.anchor = GridBagConstraints.NORTHWEST;
         controlArea.add (difficultyArea, Con);
         
         Con.gridx=0;
         Con.gridy=3;
         Con.fill = GridBagConstraints.NONE;
         controlArea.add (scoreArea, Con);
      
         
         // Game area
         game = new Game(); 
         
         // Complete Applet
         setLayout(new FlowLayout(FlowLayout.LEFT));
         this.add (controlArea);
         this.add (game);
      
        
     }
	 
     public void start() {
          game.initGame();
          scoreArea.clear();
     }


     public void stop() {
      	 threadStop = true;
      	 if (thread != null) {
      	 	thread.interrupt(); 
      	 }    	
     
   	 } // class.Stk2
   	 
   		
	/************************************/
	/* Inner class to handle game panel	*/
	/************************************/
	class Game extends JComponent implements MouseListener, Runnable {
        
	    private int archerHeight, archerWidth, deadArcherHeight, deadArcherWidth, deadKnightWidth, deadKnightHeight;
     	private int imageWidth,imageHeight;
        private int knightX,knightY, archerX, archerY;
     	private int winXSize = 0;
     	private int winYSize = 0;
     	private int maxKnightX ;
     	private int maxKnightY ;
 	    private boolean goingRight=false;
     	private int zagCount=0, maxZag=0;

		public Game()
		{

				addMouseListener(this);
				initGame();
				//setVisible(true);
				
	         	imageWidth = knight.getWidth(this);
         		imageHeight = knight.getHeight(this);
         		archerWidth = archer.getWidth(this);
         		archerHeight = archer.getHeight(this);
         		deadArcherWidth = deadArcher.getWidth(this);
         		deadArcherHeight = deadArcher.getHeight(this);
         		deadKnightWidth = deadKnight.getWidth(this);
         		deadKnightHeight = deadKnight.getHeight(this);

		}
		
		public Dimension getPreferredSize() {
			return new Dimension(Stk2.this.getSize().width-controlArea.getSize().width-10, 
								 Stk2.this.getSize().height);
		}
		
		public void paint(Graphics g) {
     	 
     	 g.setColor (Color.black);
     	 g.drawRect (5,5,winXSize-10, winYSize-10);
     	 g.drawRect (6,6,winXSize-12, winYSize-12);
         g.drawImage(displayKnight,knightX, knightY,this);
         g.drawImage(displayArcher,archerX, archerY,this);
     	}
     	
     	// Mouse click handler - Starts game if on Archer
     	public void mouseClicked(MouseEvent e) { 
     	int mouseX = e.getX();
        int mouseY = e.getY();
     	     	
     	// game starts with click on archer
     	if (threadStop == true &&
            (mouseX >= archerX && mouseX <= archerX+archerWidth) &&
            (mouseY >= archerY && mouseY <= archerY+archerHeight)) {
			start();    		
     	}
  	 }
  	 
  	 // start a run
  	 public void start() {
  	 	
    		initGame();
   		        	
         	// create thread for animation
         	thread = new Thread(this);
         	
      	 	thread.setPriority(Thread.NORM_PRIORITY-2);
         	thread.start();	
  	 	
  	 }
     
     public void mouseReleased(MouseEvent e) { }
     public void mouseExited(MouseEvent e) { }
     public void mouseEntered(MouseEvent e) { }

	// Mouse pressed handler - Provides archer hit detection
     public void mousePressed(MouseEvent e) {
         int mouseX = e.getX();
         int mouseY = e.getY();
	   		 
         if (threadStop == false &&
             (mouseX >= knightX && mouseX <= knightX+imageWidth) &&
             (mouseY >= knightY && mouseY <= knightY+imageHeight)) {
                 if (bSound) knightHitSound.play();
                 // A hit 
                 threadStop=true;
                 thread.interrupt();
                 displayKnight = deadKnight; // switch image to dead knight
                 // shift dead knight left to fit window
                 if (knightX > winXSize - deadKnightWidth)
                 {
                 	knightX -= deadKnightWidth;
                 }
                 scoreArea.incArcherScore();
                 repaint();
          }

      }
     
    // Thread run method - performs animation and knight win detection    
	public void run () {
		
     	// Move the knight in zig zag style
     	showStatus("Shoot The Knight");
        repaint();
		
		// brief pause to get ready, and show repainted positions to user	
		try {
        	Thread.sleep(1000);
        } catch (Exception ex) {} 	         	
		threadStop = false;
		
     	if (bSound) startSound.play();
    	while (threadStop == false) {
    		int oldX = knightX;
    		int oldY = knightY;
    		
        	knightY = (knightY+yInc) % maxKnightY;
            if ( knightY >= maxKnightY-yInc )
        	{
        		// Knight has reached archer, so archer dies
        		displayArcher = deadArcher; // switch image to dead archer
        		archerY = winYSize-deadArcherHeight - 7 ;
        		threadStop = true;
        		// move knight next to archer
        		knightX = archerX + deadArcherWidth/2 - imageWidth/2;
        		knightY = archerY-imageHeight-10;
        		
        		repaint();
        		if (bSound) hitSound.play();
				scoreArea.incKnightScore();
        	} 
        	else
        	{
        		// Reverse direction of knight if its time, or have hit the edge
        		if (zagCount-- <= 0 ||
        		    (goingRight && knightX >= maxKnightX - xInc) ||
        		    (!goingRight && knightX <= xInc ))
        		{
        			
        			// its time to switch dir
        			if (goingRight == true) 
        				goingRight = false;
        			else
        				goingRight = true;
        			
        			// work out how long to go this way
        			zagCount = getZagCount();
        		}
        	
				// move the knight left or right by the increment        			
        		if (goingRight ) {
        		    knightX += xInc;
        		} else
        			knightX -= xInc;
        		}
        
        		// just repaint the knight, nothing else has changed  
        		this.repaint(oldX - xInc, oldY, imageWidth+xInc, imageHeight+yInc);	
        		try {
        			Thread.sleep(sleepTime);
        		} catch (Exception e) {}
        	}
       	} 
       	
   	// method to initialise for new game   
	public void initGame() {
	 	
	 	winXSize = getSize().width;
		winYSize = getSize().height;
        maxKnightX = winXSize - imageWidth ;
        maxKnightY = winYSize - imageHeight - archerHeight;
  		sleepTime = difficultyArea.getDifficulty();
  				
   		// start knight at the top 
       	knightX = (int)(Math.random() * maxKnightX);
       	knightY = 30;  
       	
        archerX = winXSize/2;
       	archerY = winYSize-archerHeight - 7;
     	maxZag = winXSize/xInc;    
     	
   	    // set intial images
	    displayKnight = knight;
    	displayArcher = archer;
    	
       	// set initial direction
       	if (Math.random() < 0.5 ) { 
	       	goingRight = true; 
        } else	{ 
	       	goingRight = false;
        }
        zagCount = getZagCount(); // work out how long to go this way
	}
	
    // Method to get time for knight to keep going in the current direction
    private int getZagCount ()
    {
    	return (int)(Math.random()*maxZag); 
    }

	} // class Game
	
	/*****************************************/
	/* Inner Class to handle difficulty area */
	/*****************************************/
	class Difficulty extends JPanel {
		
		private int diff;
        private JTextField difText = null;
        private int max;
        
		public Difficulty (int start, int maxDiff, Color foreGround, Color backGround ) {
			
			 diff = start;
			 max = maxDiff;
			 JButton upButton = new JButton ("+");
	         JButton downButton = new JButton ("-");
	         difText = new JTextField(Integer.toString(diff),2); 
	         difText.setEditable(false);
	         
	         setLayout( new GridLayout(1,3));
	         setBackground(backGround);
	         setForeground(foreGround);
	         
	         Border etch = BorderFactory.createEtchedBorder();
	         setBorder (BorderFactory.createTitledBorder(etch,"Difficulty (1-"+ max + ")",
	         											 TitledBorder.DEFAULT_JUSTIFICATION ,
	         											 TitledBorder.DEFAULT_POSITION,
	         											 getFont(),
	         											 foreGround));
	                          
	         add (upButton);
	         add (downButton);
	         add (difText);
	         
   	         upButton.setActionCommand("Up");
    	     upButton.addActionListener (new ActionListener() {
        	 	public void actionPerformed(ActionEvent ae) {
         			if ( diff < max ) {diff++;}
	         	    difText.setText(Integer.toString(diff)); 
	         	    }
         		}
       		);
       		
       		 downButton.setActionCommand("Down");
    	     downButton.addActionListener (new ActionListener() {
        	 	public void actionPerformed(ActionEvent ae) {
         			if (diff > 1) { diff--; }
	         	    difText.setText(Integer.toString(diff)); 
         			}
         		}
       		);
       		
       		setVisible(true);
		}
		
		public int getDifficulty()
		{
			return diff;
		}
	}
	
	
	/************************************/
	/* inner class to handle score area */
	/************************************/
	class Score extends JPanel {
		private int archerScore;
		private int knightScore;
		private JTextField archerScoreT = null, knightScoreT = null;
		private JPanel scorePanel = null;
		
		public Score (Color foreGround, Color backGround) {
			
			archerScore = 0;
			knightScore = 0;
			 
			 JLabel knightScoreL = new JLabel("KNIGHT:");
	         knightScoreL.setForeground(foreGround);
	         JLabel archerScoreL = new JLabel("ARCHER:");
	         archerScoreL.setForeground(foreGround);
	         
	         knightScoreT = new JTextField("0",3);
	         knightScoreT.setEditable(false);
	         archerScoreT = new JTextField("0",3);
			 archerScoreT.setEditable(false);
			 
			 JButton clearButton = new JButton ("clear");
			 
	         setLayout( new GridLayout(3,2));
			 setBackground(backGround);
	         setForeground(foreGround);
	         	
	         Border etch = BorderFactory.createEtchedBorder();
	         setBorder (BorderFactory.createTitledBorder(etch,"Score",
	         											 TitledBorder.DEFAULT_JUSTIFICATION ,
	         											 TitledBorder.DEFAULT_POSITION,
	         											 getFont(),
	         											 foreGround));
	         
	         add (knightScoreL);
	         add (knightScoreT);
	         add (archerScoreL);
	         add (archerScoreT);
	         add (clearButton);
	         	         
	         //Button handler
	         clearButton.setActionCommand("Clear");
    	     clearButton.addActionListener (new ActionListener() {
        	 	public void actionPerformed(ActionEvent ae) {
         			clear();
         			}
         		}
       		);
       		setVisible(true);
       		
		}
		
		private void displayScore()
		{
			  archerScoreT.setText(Integer.toString(archerScore)) ;
			  knightScoreT.setText(Integer.toString(knightScore)) ;
		}
		
		public void incArcherScore()
		{
			archerScore++;
			displayScore();
		}

		public void incKnightScore()
		{
			knightScore++;
			displayScore();
		}
		
		public void clear()
		{
			knightScore = 0;
			archerScore = 0;
			displayScore();
		}
			
	}
}

 
