package cannon;

/*########################################################################
 *
 * Auth: Sean E. Russell
 *       University of Oregon, CIS
 * Date: Thu Aug 10 10:34:06 PDT 1995
 *
 * Synopsis:
 *
 * - Mon Aug 14 15:23:46 PDT 1995
 *   It's not my fault.  I started this when Java was in it's Alpha-3
 * release, when the documentation was non-existant, examples were
 * scarce, and the AWT package was primative.  I refuse to take any
 * blame for injuries incurred while reading this code.
 *   That said, cannon is a Java class for HotJava which is supposed
 * to provide an example of a simple gravity/velocity environment.  The
 * user has a cannon which he may shoot.  He is able to vary the angle
 * of the cannon and the velocity of the projectile, and view the
 * results of his input.  That's all it does so far, and it doesn't
 * do it well.  AWT is a nightmare.
 *
 * - Thu Aug 17 17:41:59 PDT 1995
 *   Well, considering what I had to go through to figure out how the
 * layout engine behaves, the code doesn't look *too* bad.  Sound and
 * rudimentry animation has been added.  As it is, I would consider
 * this a usable app.
 *   Needing to be done: explosion for target and sounds for a miss.
 * There are numerous cosmetic features that can be worked on, but
 * I'll leave those until someone requests them.
 *
 * - Sun Aug 20 00:34:18 PDT 1995
 *   Ha!  Perfection!  The animation, the smoke trail; the sound...
 * it even refreshes correctly.  I don't like the way the code looks;
 * it's very messy, and a lot of things are hardcode that shouldn't be.
 * Due to the need for my services on a number of other projects, I'm
 * not going to fix things like the dependancy on a small font size in
 * the UI.  Maybe later.
 *   I was harsh on AWT.  Its not poorly designed; its just poorly
 * documented.  All in all, not bad for an Alpha release, even if the
 * layout engine is unpredictable at times.
 *
 ######################################################################*/

import java.awt.*;
import java.net.*;
import java.lang.Math;
import java.lang.Integer;

public class cannon extends java.applet.Applet
{
  double dx, dy, theta, velocity, gravity, windage;
  int xmax, ymax, numshots;
  Color black, erase;
  double x, y;
  double xo[] = new double[4];
  double yo[] = new double[4];
  double rads;
  boolean dosound;
  CannonFrame frame;

  Graphics drawarea;

  Image can, shot, targ, targ2,
    bang1, puff1, puff2, puff3, puff4;

  public void more()
     {
     numshots = 4;
     repaint();
     }

  public void shootShot()
    {
      if (numshots > 0)
    {
      numshots--;
      play(getCodeBase(), "sounds/cannon.au");
      dosound = true;
      repaint();
    }
    }

  public void loadImages()
    {
      can = getImage(getCodeBase(), "images/cannon.gif");
      shot = getImage(getCodeBase(), "images/ammo.gif");
      targ = getImage(getCodeBase(), "images/target.gif");
      targ2 = getImage(getCodeBase(), "images/target2.gif");
      bang1 = getImage(getCodeBase(), "images/bang1.gif");
      puff1 = getImage(getCodeBase(), "images/puff1.gif");
      puff2 = getImage(getCodeBase(), "images/puff2.gif");
      puff3 = getImage(getCodeBase(), "images/puff3.gif");
      puff4 = getImage(getCodeBase(), "images/puff4.gif");
    }

  public void init()
    {
      loadImages();
      numshots = 4;
      rads = 57.29577866f;
      xmax = 600;
      ymax = 300;
      resize(xmax,ymax+20);
      theta = 60;        // degrees
      theta /= rads;        // -> radians
      velocity = 3;        // m/s x 10^-1
      gravity = .098f;        // m/s^2 x 10^-2
      windage = 0;
      black = Color.black;
      erase = Color.blue;
      frame = new CannonFrame(this);
    }
  
  public void changeAngle(int val)
    {
      Integer temp = new Integer(val);
      theta = (double)val;        // degrees
      theta /= rads;        // -> radians
      frame.ang.setText(temp.toString());
    }

  public void changeVelocity(int val)
    {
      Integer temp = new Integer(val);
      velocity = (double)val / 5;
      frame.vel.setText(temp.toString());
    }

  public void changeGravity(int val)
    {
      Float temp = new Float((float)val / 10);
      gravity = (double)val / 1000;
      frame.grav.setText(temp.toString());
    }

  public void changeWindage(int val)
    {
      Integer temp = new Integer(val);
      windage = (double)val / 200;
      frame.wind.setText(temp.toString());
    }

  public void paint(Graphics g)
    {
      if (can == null) {
      return;
      }

      drawarea = g;
      //##### Cannon part

      //##### Draw images
      g.drawImage(can, 20, ymax - can.getHeight(this), this);
      g.drawImage(targ, xmax - (targ.getWidth(this) + 10), ymax - targ.getHeight(this), this);
      if (numshots > 3) g.drawImage(shot, 0, ymax - ((2*shot.getHeight(this))+2), this);
      if (numshots > 2) g.drawImage(shot, 2 + shot.getWidth(this), 
                    ymax - ((2*shot.getHeight(this))+2), this);
      if (numshots > 1) g.drawImage(shot, 0, ymax - shot.getHeight(this), this);
      if (numshots  >0) g.drawImage(shot, 2 + shot.getWidth(this), ymax - shot.getHeight(this), this);

      if (numshots < 4)
    {
      //##### Shoot da shot
      x = 65;
      y = ymax-55;
      dx = velocity * Math.cos(theta);
      dy = velocity * Math.sin(theta);
      g.setColor(Color.gray);
      
      while ((x > 0) && (x < xmax) && (y < ymax))
        {
          if (xo[3] != 0)
        g.clearRect((int)xo[3] - 4, (int)yo[3] - 4, 8, 7);
          if (xo[0] != 0)
          g.drawRect((int)xo[0]-1, (int)yo[0]-1, 2, 2);
          g.drawImage(shot, (int)x - 4, (int)y - 4, this);
          if (x < 75) g.drawImage(can, 20, ymax - can.getHeight(this), this);
          if ((x>xmax-(targ.getWidth(this)+10)) && (y>ymax-targ.getHeight(this)))
        g.drawImage(targ, xmax - (targ.getWidth(this)+10), 
                ymax - targ.getHeight(this), this);
          if (dosound)try {Thread.sleep(5);} catch (InterruptedException e){}
          xo[0] = xo[1]; xo[1] = xo[2]; xo[2] = xo[3];
          yo[0] = yo[1]; yo[1] = yo[2]; yo[2] = yo[3];
          xo[3] = x; yo[3] = y;
          x += dx;
          dx -= windage/2;
          y -= dy;
          dy -= gravity/2;
          
          //##### Check for hit
          if ((x>(xmax-43)) && (x<(xmax-27)) && 
          (y>(ymax-40)) && (y<(ymax-25)))
        {
          if (dosound)
            {
              play(getCodeBase(), "sounds/explosion.au");
              //##### Draw FX
              // Bang over full target
              g.drawImage(bang1, xmax - (targ.getWidth(this)+10), 
                  ymax - targ.getHeight(this), this);
              
              // puff1 over targ2
        try {Thread.sleep(75);} catch (InterruptedException e){}
              g.clearRect(xmax-(targ.getWidth(this)+10), ymax-targ2.getHeight(this),
                  (targ.getWidth(this)+10), targ2.getHeight(this));
              g.drawImage(targ2, xmax - (targ.getWidth(this)+10), 
                  ymax - targ2.getHeight(this), this);
              play(getCodeBase(), "sounds/applause.au");
              g.drawImage(puff1, xmax - (targ.getWidth(this)+15), 
                  ymax - (targ.getHeight(this)+40), this);
              
              // Puff2 over targ2
        try {Thread.sleep(75);} catch (InterruptedException e){}
              g.clearRect(xmax-(targ.getWidth(this)+15), 
                  ymax-(targ.getHeight(this)+40),
                  (targ.getWidth(this)+15), (targ.getHeight(this)+40));
              g.drawImage(targ2, xmax - (targ.getWidth(this)+10), 
                  ymax - targ2.getHeight(this), this);
              g.drawImage(puff2, xmax - (targ.getWidth(this)+15), 
                  ymax - (targ.getHeight(this)+40), this);
              
              // puff3 over targ2
        try {Thread.sleep(75);} catch (InterruptedException e){}
              g.clearRect(xmax-(targ.getWidth(this)+15), 
                  ymax-(targ.getHeight(this)+40),
                  (targ.getWidth(this)+15), (targ.getHeight(this)+40));
              g.drawImage(targ2, xmax - (targ.getWidth(this)+10), 
                  ymax - targ2.getHeight(this), this);    
              g.drawImage(puff3, xmax - (targ.getWidth(this)+10), 
                  ymax - (targ.getHeight(this)+40), this);
              
              // puff4 over targ2
        try {Thread.sleep(75);} catch (InterruptedException e){}
              g.clearRect(xmax-(targ.getWidth(this)+15), 
                  ymax-(targ.getHeight(this)+40),
                  (targ.getWidth(this)+15), (targ.getHeight(this)+40));
              g.drawImage(targ2, xmax - (targ.getWidth(this)+10), 
                  ymax - targ2.getHeight(this), this);
              g.drawImage(puff4, xmax - (targ.getWidth(this)+10), 
                  ymax - (targ.getHeight(this)+40), this);
              dosound = false;
              
        try {Thread.sleep(75);} catch (InterruptedException e){}
            }
          // targ2
          g.clearRect(xmax-(targ.getWidth(this)+15), ymax-(targ.getHeight(this)+40),
                  (targ.getWidth(this)+15), (targ.getHeight(this)+40));
          g.drawImage(targ2, xmax - (targ.getWidth(this)+10), 
                  ymax - targ2.getHeight(this), this);
          x=0;
        }
        }
      for (int i=0; i<4; i++) xo[i] = yo[i] = 0;
    }
    }

  public void start()
    {
    if (frame != null)
    {
    frame.show();
    }
    }      

  public void stop()
     {
     if (frame != null)
    {
    frame.hide();
    }
     }

  public void destroy()
     {
     if (frame != null)
    {
    frame.dispose();
    frame = null;
    }
     }
}

class CannonFrame extends Frame {
    cannon can;

    TextField ang;
    TextField vel;
    TextField grav;
    TextField wind;

    Scrollbar s_ang;
    Scrollbar s_vel;
    Scrollbar s_grav;
    Scrollbar s_wind;

    CannonFrame(cannon can) {
    this.can = can;

    setTitle("Cannon");

    Panel p;
    add("North", p = new Panel());

    p.add(new Label("Ang:"));
    p.add(ang = new TextField("60", 4));
    ang.setEditable(false);

    p.add(new Label("Vel:"));
    p.add(vel = new TextField("15", 4));
    vel.setEditable(false);

    p.add(new Label("Grav:"));
    p.add(grav = new TextField("9.8", 4));
    grav.setEditable(false);

    p.add(new Label("Wind:"));
    p.add(wind = new TextField("0", 4));
    wind.setEditable(false);

    add("Center", p = new Panel());
    p.setLayout(new GridLayout(4, 0));

    p.add(s_ang = new Scrollbar(Scrollbar.HORIZONTAL));
    s_ang.setValues(60, 10, 1, 90);

    p.add(s_vel = new Scrollbar(Scrollbar.HORIZONTAL));
    s_vel.setValues(10, 2, 1, 30);

    p.add(s_grav = new Scrollbar(Scrollbar.HORIZONTAL));
    s_grav.setValues(98, 10, 40, 200);

    p.add(s_wind = new Scrollbar(Scrollbar.HORIZONTAL));
    s_wind.setValues(0, 1, -10, 10);

    add("South", p = new Panel());
    p.add(new Button("Shoot"));
    p.add(new Button("More Ammo"));
    pack();
    //list();
    }

    public boolean handleEvent(Event evt) {
    //System.out.println("evt = " + evt);
    if (evt.target == s_ang) {
        can.changeAngle(((Integer)evt.arg).intValue());
        return true;
    }
    if (evt.target == s_vel) {
        can.changeVelocity(((Integer)evt.arg).intValue());
        return true;
    }
    if (evt.target == s_grav) {
        can.changeGravity(((Integer)evt.arg).intValue());
        return true;
    }
    if (evt.target == s_wind) {
        can.changeWindage(((Integer)evt.arg).intValue());
        return true;
    }
    if ("Shoot".equals(evt.arg)) {
        can.shootShot();
        return true;
    }
    if ("More Ammo".equals(evt.arg)) {
        can.more();
        return true;
    }
    return super.handleEvent(evt);
    }
}