
/**
 * Write a description of class newGame here.
 * 
 * @author Xander Friedlander
 * @version 0.1  Sat, Aug 15, 2009
 */

import java.applet.*;  /* Required to run as applet */
import java.awt.*;     /* Required for java swing utilities */
import java.awt.geom.*;  /* Required for AffineTransform for rotations */
import java.lang.*;    /* Required for various utilities such as Runnable */
import javax.swing.*;
import java.util.ArrayList;


public class SmallGame extends Applet implements Runnable
{
    // instance variables
    Thread t;
    int i, keyRelease, keyDepress, width, height, rotation, gameState;
    String message;  // for debugging
    Image offscreenImage, shieldimg, mook1img, axeimg, shieldimgdead,
             axeimgdead, mook1imgdead, charImage;  // preloaded images, offscreenImage is buffer
    Graphics offscr, chIm; // buffer for double buffering
    NPC[] opponents;
    Player user; // player class forms a thread for the user's character
    ArrayList actors;

    /**
     * Constructor for objects of class newGame
     */
    
    // no constructors atm

    /**
     * Method init - initializes thread with starting data
     */
    
  public void init()
  {
     // start the thread for the applet
      t = new Thread(this);
      t.start();
      // initialize framerate monitor to 0
      i = 0;
      gameState = 0;  // title page is gamestate 0, initialize to this
      shieldimg = getImage(getCodeBase(), "shieldimg.PNG");  //preload graphics
      axeimg = getImage(getCodeBase(), "axeimg.PNG"); 
      mook1img = getImage(getCodeBase(), "mook1img.PNG");
      mook1imgdead = getImage(getCodeBase(), "mook1imgdead.PNG");
      shieldimgdead = getImage(getCodeBase(), "shieldimgdead.PNG");
      axeimgdead = getImage(getCodeBase(), "axeimgdead.PNG");
      width = getSize().width;  // width of applet; used for buffering
      height = getSize().height;  // height of applet; used for buffering
      offscreenImage = createImage(width, height);  // create offscreen buffer
      offscr = offscreenImage.getGraphics();   // save offscreen buffer as a graphics interface
      charImage = createImage(150, 170); // create a unique image and graphics interface for character
      chIm = charImage.getGraphics();    //        so that it can be rotated
      actors = new ArrayList();  // store all actors in arraylist for collision detection
  }
  

  public void update(Graphics g)
  {
      Graphics2D g2d = (Graphics2D)g;
      paint(g2d);  // override update method for buffering
  }
  
  public boolean mouseDown(Event e, int x, int y)
  {  // this event takes place when the mouse is clicked at coordinates (x,y)
      if (gameState == 0)
      {
        if ( x < 150 )
        {
            if (y > 60 && y < 230)
            {  // player has selected ShieldMan, go to game view
              user = new ShieldMan(shieldimg, shieldimgdead);  
              gameState = 1;
              // in the stage represented by gameState 1, there are 3 enemies, so make NPC array = 3
              opponents = new NPC[3];
              actors.add(user);
              for (int i = 0; i < 3; i++)
              {
                  opponents[i] = new Mook1(mook1img, mook1imgdead, 300, i*170+40, 170);
                  actors.add(opponents[i]);
              }
            }
        }
        if ( x > 170 && x < 320 )
        {
            if (y > 140 && y < 310)
            {  // player has selected AxeMan, go to game view
              user = new AxeMan(axeimg, axeimgdead);
              gameState = 1;
              // in the stage represented by gameState 1, there are 3 enemies, so make NPC array = 3
              opponents = new NPC[3];
              for (int i = 0; i < 3; i++)
              {
                  opponents[i] = new Mook1(mook1img, mook1imgdead, 300, i*170+40, 170);
                  actors.add(opponents[i]);
              }
            }
        }
      }
      
      return true;
  }
  
  public boolean keyDown(Event e, int key)
  {
      /** controls for gamestate 1 (the game) - w (119) is forward, s (115) is back
       *                                       e (101) is right strafe, q (113) is left
       *                                       a (97) is turn left, d (100) is turn right
       **/
      
      if (gameState == 1 && user.isAlive())
      {  // if user pushes q, strafe left
        if (key == 101)
        {
          user.strfL();
        }
        else if (key == 113)
        { // if user pushes e, strafe right
          user.strfR();
        }  
        else if (key == 119) 
        {  // if user pushes w, move forward
          user.forward();
        }
        else if (key == 115)
        {  // if user pushes d, move backward
          user.backward();
        }
        else if (key == 49)
        {  // if user pushes 1, use ability1
          user.useAbility1();
        }
        else if (key == 50)
        {  // if user pushes 2, use ability2
          user.useAbility2();
        }
        else if (key == 51)
        {  // if user pushes 3, use ability3
          user.useAbility3();
        }
        else if (key == 97)
        {  // if user pushes a, rotate left
          rotation -= 5;
        }
        else if (key == 100)
        {  // if user pushes d, rotate right
          rotation += 5;
        }
        else ;
    }
    if (key == 27)
    {  // if user pushes escape, return to main menu
      gameState = 0;
    }
      
      
      return true;
  }
  
  public boolean keyUp(Event e, int key)
  {
      /** controls for gamestate 1 (the game) - release a directional button to stop moving **/
      
      if (gameState == 1)
      {
        if (key == 119 || key == 115 || key == 101 || key == 113)
        {
          user.stop();
        }
        
        if (key == 97 || key == 100)
        {
          user.stop();
        }

        else ;
      }
      return true;
  }
  
  
  
  /**
  * Methods paint(), displayTitleScreen(), displayHealthBar(), drawCharacter(), drawOpponents()
  *    These methods are the front-end, and display the graphics on the screen.
  *    Everything except the character image are printed first to an offscreen buffer, then copied to screen.
  */
 
  public void paint (Graphics g)
  {
      
    // Print background, and display frames
    Graphics2D g2d = (Graphics2D)g;
    offscr.setColor(Color.white);
    offscr.fillRect(0, 0, width, height);

    offscr.setColor(Color.blue);
    offscr.fillRect(0, 0, 80, 20);
    
    offscr.setColor(Color.white);
    offscr.drawString("Frames...." + i%60, 0, 15); 
    offscr.setColor(Color.black);
    
    if (gameState == 0)
    {
      displayTitleScreen();
    }

    if (gameState == 1)
    {        
      displayHealthBar();
      drawCharacter();
      drawOpponents();
    }
    
    AffineTransform originalLoc = g2d.getTransform();  // save original location of graphics for reversion
    g2d.drawImage(offscreenImage, 0, 0, this);  // draw buffer to screen
    g2d.rotate(Math.toRadians(rotation), user.getPosX()+150/2, user.getPosY()+170/2);  // rotate graphics interface
    g2d.drawImage(charImage, user.getPosX(), user.getPosY(), this);  // draw the character image to screen
    g2d.setTransform(originalLoc);  // revert graphics to non-rotated position

    //TODO: double buffering on rotated character


  }
  
  
  public void displayTitleScreen()
  {
    offscr.drawString("Select a character!", 200, 30);
    offscr.drawImage(shieldimg, 0, 60, this);
    offscr.drawImage(axeimg, 170, 140, this);
    offscr.drawRect(0, 60, 150, 170);
    offscr.drawRect(170, 140, 150, 170);
  }
  
  public void displayHealthBar()
  {
    offscr.setColor(Color.green);
    offscr.fillRect(141, 21, 199*(user.getHealth())/(user.getMaxHealth()), 14);
    offscr.setColor(Color.black);
    offscr.drawString("HEALTH: " + user.getHealth() + " / " + user.getMaxHealth(), 200, 30);
    offscr.drawRect(140, 20, 200, 15);
//    offscr.drawString("Rotation: " + (-rotation), 200, 45);
  }
  
  public void drawCharacter()
  {
      chIm.drawImage(user.playerImage(), 0, 0, this);
  }
  
  public void drawOpponents()
  {
      for (int i = 0; i < 3 ; i++)
      {
        offscr.drawImage(opponents[i].characterImage(), opponents[i].getPosX(), opponents[i].getPosY(), this);
      }
  }
  
  
  /** Method checkCollisions() checks to see if the player is sharing a space with any NPCs 
   *   Also check to see if any abilities are intersecting with anyone.
   *   When a collision is determined, call collision on both objects with the opposite object
   *   as the parameter, and let them determine how to react.
   */
  
  public void checkCollisions()
  {
      
  }
  
  /**
   * Method run - required for threading, this is executed when the applet is run
   * This also serves as the "tick," so all methods that need to be reapplied every 
   * moment are called in here.  
   */
  
  public void run()
  {
      while(true)
      {
          i++;
          rotation = rotation%360;
          if (gameState == 1)
          {
              checkCollisions();
              user.setRotation(rotation);
          }
          repaint();
          
          try {
              t.sleep(16);
            } catch (InterruptedException e)
              { ;  }
      }
  }
}

