import java.applet.*;
import java.awt.event.*;
import java.awt.*;
import java.io.*;
import java.net.*;

public class Iridium extends Applet
 implements Runnable, KeyListener, MouseListener, MouseMotionListener
{
 volatile Thread runThread;

 Font      defFont     = new Font("Serif", 0, 12);
 Font      infoFont    = new Font("TimesRoman", 0, 11);
 Font      annFont     = new Font("Sans-Serif", 1, 20);
 int       counter;
 int       width;
 int       height;

 int       mouseX       = -1;
 int       mouseY       = -1;
 int       pressedKey   =  0;
 boolean   controlDown  = false;
 boolean   paused       = false;
 boolean   mouseEntered = false;

 Help           help;
 Irue           irue;
 Asteroid[]     asteroids;
 int            maxAsteroids;
 Interceptor[]  interceptors;
 int            maxInterceptors;
 HeavyFighter[] heavyFighters;
 int            maxHeavyFighters;
 Zephi[]        zephis;
 
 Image   infoImg;
 boolean mouseOverInfoImg = false;
 boolean showShieldBars   = true;
 int     score;
 int     highScore;
 int     lastScore;
 int     levelC;
 int     level;
 int     levelWait = 0;
 int     countSinceLevel;
 boolean cheated;

 Ship ship;

  // Bakgrunds-stjärnornas variabler
 int       SFnumOfStars;
 int       SFwidth;
 int       SFheight;
 boolean[] SFshown;
 int[]     SFposX;
 int[]     SFposY;
 int[]     SFspeedX;
 int[]     SFspeedY;

//--------------------------------------------- init() ------/

 public void init()
 {
  String param;
  width  = getSize().width;
  height = getSize().height;
  setBackground(new Color(0x222222));

  param = getParameter("Sounds");
  if(param != null)
  {
   switch(param.charAt(0))
   {
    case 'Y':
    case 'y':
    case '1':
    case 'T':
    case 't':
     Sounds.play = true;
     break;
    default:
     Sounds.play = false;
   }
  }

  highScore    = 0;
  SFnumOfStars = 200;
  SFwidth      = width;
  SFheight     = height;
  SFshown      = new boolean[200];
  SFposX       = new int[200];
  SFposY       = new int[200];
  SFspeedX     = new int[200];
  SFspeedY     = new int[200];

  restart();

  infoImg = getImage(getCodeBase(), "info.gif");

  help = new Help(width, height, infoImg, this);

  counter   = 0;

  setBackground(new Color(0x111111));
 }

 public void start()
 {
  //readHighscore();
  this.addKeyListener(this);
  this.addMouseListener(this);
  this.addMouseMotionListener(this);
  help.show(0);

  setBackground(new Color(0));

  if(runThread == null)
  {
   runThread = new Thread(this);
   runThread.start();
  }
 }

//------------------------------------------ run() -----------/

 public void run()
 {
  while(true)
  {
   do
   {
    try
    {
     Thread.sleep(50);
    }
    catch(InterruptedException e)
    {
     return;
    }
   }
   while(paused || help.visible);

   if(ship.shieldCounter == 0)
   {
    ship.usingShield = false;
   }
   else
   {
    ship.shieldCounter -= 1;
   }

   if(levelWait != 0)
   {
    levelWait--;
    if(levelWait == 20)
    {
     Sounds.play(Sounds.level);
    }
    if(level != 1 && levelWait != 1)
    {
     incScore(1, 0);
     if(levelWait % 10 == 0)
     {
      if(ship.shield == 100)
      {
       incScore(20, 0);
      }
      else
      {
       ShChangeShield(1);
      }
     }
     if(levelWait == 0)
     {
      if(level == 10)
      {
       if(!cheated)
       {
        help.show(10);
       }
       irue.start(getImage(getCodeBase(), "Irue.gif"), zephis);
      }
     }
    }
   }

   irue.move();
   for(int i = 0; i < 20; i++)
   {
    if(i < maxAsteroids && levelWait == 0
     && countSinceLevel > i * 20 + 100)
    {
     asteroids[i].start(1);
    }
    asteroids[i].move();
   }
   for(int i = 0; i < 15; i++)
   {
    if(i < maxInterceptors && levelWait == 0
     && countSinceLevel > i * 50 + 200 && Math.random() < 0.01)
    {
     interceptors[i].start();
    }
    if(i < maxHeavyFighters && levelWait == 0
     && countSinceLevel > i * 50 + 200 && Math.random() < 0.003)
    {
     heavyFighters[i].start();
    }
    if(irue.alive && levelWait == 0
     && countSinceLevel < 1600
     && countSinceLevel > i * 200 + 50)
    {
     zephis[i].start();
    }
    interceptors[i].move();
    heavyFighters[i].move();
    zephis[i].move();
    if(zephis[i].hitting)
    {
     if(irue.hit(20))
     {
      crashAll();
     }
    }
   }

   if(irue.nova.stadium > 2
    && irue.nova.stadium > width - ship.middleX
    && irue.nova.stadium > ship.middleX - width)
   {
    ShChangeShield(-100);
   }

   if(ship.angle != ship.goToAngle)
   {
    if(ship.angle > ship.goToAngle)
    {
     if(ship.wonTheGame)
     {
      ship.angle -= 0.01;
     }
     else
     {
      ship.angle -= 0.2;
     }
     if(ship.angle < ship.goToAngle)
     {
      ship.angle = ship.goToAngle;
     }
     ShRender();
    }
    else
    {
     if(ship.wonTheGame)
     {
      ship.angle += 0.01;
     }
     else
     {
      ship.angle += 0.2;
     }
     if(ship.angle > ship.goToAngle)
     {
      ship.angle = ship.goToAngle;
     }
     ShRender();
    }
   }

   for(int i = 0, body = -1; i < 10; i++)
   {
    ship.shots[i].move();
    if(ship.shots[i].hitting)
    {
     body = inAsteroid(ship.shots[i].targetX, ship.shots[i].targetY);
     if(body != -1)
     {
      ship.shotExplosions[i].explode(ship.shots[i].targetX,
       ship.shots[i].targetY, 5);
      if(asteroids[body].hit(1))
      {
       incScore(50, 2);
      }
      incScore(1, 0);
     }
     body = inInterceptor(ship.shots[i].targetX, ship.shots[i].targetY);
     if(body != -1)
     {
      ship.shotExplosions[i].explode(ship.shots[i].targetX,
       ship.shots[i].targetY, 5);
      if(interceptors[body].hit(1))
      {
       incScore(100, 8);
      }
      incScore(1, 0);
     }
     body = inHeavyFighter(ship.shots[i].targetX, ship.shots[i].targetY);
     if(body != -1)
     {
      ship.shotExplosions[i].explode(ship.shots[i].targetX,
       ship.shots[i].targetY, 5);
      if(heavyFighters[body].hit(1))
      {
       incScore(350, 20);
      }
      incScore(1, 0);
     }
     body = inZephi(ship.shots[i].targetX, ship.shots[i].targetY);
     if(body != -1)
     {
      ship.shotExplosions[i].explode(ship.shots[i].targetX,
       ship.shots[i].targetY, 5);
      if(zephis[body].hit(1))
      {
       incScore(50, 1);
      }
      incScore(1, 0);
     }
     if(irue.alive
      && ship.shots[i].targetX > width/2 - 50
      && ship.shots[i].targetX < width/2 + 50
      && ship.shots[i].targetY > height/2 - 50
      && ship.shots[i].targetY < height/2 + 50)
     {
      ship.shotExplosions[i].explode(ship.shots[i].targetX,
       ship.shots[i].targetY, 5);
      Sounds.play(Sounds.hit);
      if((i & 3) == 0)
      {
       if(irue.hit(1))
       {
        crashAll();
       }
      }
     }
    }
    ship.shotExplosions[i].go();
   }
   ship.explosion.go();

   if(irue.shown)
   {
    if(irue.shot.hitting)
    {
     int body = inZephi(irue.shot.targetX, irue.shot.targetY);
     if(body != -1)
     {
      if(zephis[body].hit(1))
      {
       incScore(0, 1);
      }
     }
    }
   }

   for(int i = 0; i < asteroids.length; i++)
   {
    for(int j = 0; j < ship.sprite.npoints; j++)
    {
     if(asteroids[i].zLevel >= 100
      && asteroids[i].inside(ship.sprite.xpoints[j], ship.sprite.ypoints[j]))
     {
      asteroids[i].crash();
      ShChangeShield(-10);
      incScore(0, 1);
     }
    }
   }
   for(int i = 0; i < 15; i++)
   {
    for(int j = 0; j < interceptors[i].shots.length; j++)
    {
     if(interceptors[i].shots[j].hitting
      && ship.sprite.contains(interceptors[i].shots[j].targetX, 
       interceptors[i].shots[j].targetY))
     {
      ShChangeShield(-1);
      Sounds.play(Sounds.hit);
     }
    }
    for(int j = 0; j < ship.sprite.npoints; j++)
    {
     if(interceptors[i].zLevel >= 100
      && interceptors[i].inside(ship.sprite.xpoints[j], ship.sprite.ypoints[j]))
     {
      interceptors[i].crash();
      ShChangeShield(-10);
      incScore(0, 4);
     }
    }
    for(int j = 0; j < heavyFighters[i].shots.length; j++)
    {
     if(heavyFighters[i].shots[j].hitting
      && ship.sprite.contains(heavyFighters[i].shots[j].targetX, 
       heavyFighters[i].shots[j].targetY))
     {
      ShChangeShield(-1);
      Sounds.play(Sounds.hit);
     }
    }
    for(int j = 0; j < heavyFighters[i].missiles.length; j++)
    {
     if(heavyFighters[i].missiles[j].hitting)
     {
      heavyFighters[i].missiles[j].crash();
      ShChangeShield(-15);
      Sounds.play(Sounds.asteroid);
     }
    }
    for(int j = 0; j < ship.sprite.npoints; j++)
    {
     if(heavyFighters[i].zLevel >= 100
      && heavyFighters[i].inside(ship.sprite.xpoints[j], ship.sprite.ypoints[j]))
     {
      heavyFighters[i].crash();
      ShChangeShield(-20);
      incScore(0, 7);
     }
    }
   }

   if(ship.alive && ship.middleY < height / 2)
   {
    ship.middleY += ship.autoDownSpeed;
    ShRender();
   }
   else if(!ship.alive && ship.middleY < height + 500)
   {
    ship.middleY   += ship.autoDownSpeed;
    ship.angle     += 0.1;
    ship.goToAngle += 0.1;
    if(score > lastScore && score > highScore)
    {
     highScore = score;
    }
    ShRender();
   }
   else
   {
    ship.autoDownSpeed = 0;
    seeIfWon:
    {
     if(level == 10 && !ship.wonTheGame
      && countSinceLevel > 1500 && irue.alive)
     {
      for(int i = 0; i < 15; i++)
      {
       if(zephis[i].shown)
       {
        break seeIfWon;
       }
      }
      incScore(1000 +(irue.shield+ship.shield)*20, 0);
      ship.wonTheGame = true;
      ship.goToAngle  = 0;
     }
    }
    if(ship.wonTheGame && ship.angle == 0)
    {
     if(ship.landingStadium < 100)
     {
      ship.landingStadium += 1;
      if(ship.middleX > width/2)
      {
       ship.middleX += (width/2-ship.middleX)/80 - 1;
      }
      else if(ship.middleX < width/2)
      {
       ship.middleX += (width/2-ship.middleX)/80 + 1;
      }
      if(ship.middleY > height/2)
      {
       ship.middleY += (height/2-ship.middleY)/80 - 1;
      }
      else if(ship.middleY < height/2)
      {
       ship.middleY += (height/2-ship.middleY)/80 + 1;
      }
      ShRender();
     }
    }
   }

   switch(pressedKey)
   {
    case KeyEvent.VK_NUMPAD8:
    case KeyEvent.VK_UP:
    case 'W':
     ship.goToAngle = 0;
     if(ship.angle == ship.goToAngle)
     {
      ShMove(0, -25);
     }
     break;
    case KeyEvent.VK_NUMPAD4:
    case KeyEvent.VK_LEFT:
    case 'A':
     ship.goToAngle = Math.PI / 8;
     if(ship.angle == ship.goToAngle)
     {
      ShMove(-25, 0);
     }
     break;
    case KeyEvent.VK_NUMPAD5:
    case KeyEvent.VK_DOWN:
    case 'S':
     ship.goToAngle = 0;
     if(ship.angle == ship.goToAngle)
     {
      ShMove(0, 25);
     }
     break;
    case KeyEvent.VK_NUMPAD6:
    case KeyEvent.VK_RIGHT:
    case 'D':
     ship.goToAngle = Math.PI / -8;
     if(ship.angle == ship.goToAngle)
     {
      ShMove(25, 0);
     }
     break;
    case ' ':
     if((counter & 3) == 0)
     {
      ShShoot();
     }
     break;
   }

   if(mouseEntered)
   {
    moveTargeter(mouseX, mouseY);
   }

   if((!irue.alive || irue.stadium < 120)&& !ship.wonTheGame)
   {
    int SFstarsShownYet = 0;
    for(int i = 0; i < SFnumOfStars
     && SFstarsShownYet < 6 && levelWait == 0; i++)
    {
     if(!SFshown[i])
     {
      SFstarsShownYet += 1;
      SFshown[i]  = true;
      SFposX[i]   = SFwidth / 2;
      SFposY[i]   = SFheight / 2;
      SFspeedX[i] = 0;
      SFspeedY[i] = 0;
      while(SFspeedX[i] == 0 || SFspeedY[i] == 0)
      {
       SFspeedX[i] = (int)((Math.random()-0.5)*13);
       SFspeedY[i] = (int)((Math.random()-0.5)*13);
      }
     }
    }
    for(int i = 0; i < SFnumOfStars; i++)
    {
     if(SFshown[i])
     {
      SFposX[i] += SFspeedX[i];
      SFposY[i] += SFspeedY[i];
      if(SFposX[i] < 0 || SFposY[i] < 0
       || SFposX[i] > SFwidth || SFposY[i] > SFheight) 
      {
       SFshown[i] = false;
      }
     }
    }
   }

   asteroids = Flying.sort(asteroids);

   if(ship.alive && !ship.wonTheGame)
   {
    counter += 1;
    if(cheated && counter % 20 == 0)
    {
     counter -= 4;
    }
   }
   countSinceLevel += 1;
   repaint(50);
  }
 }

//----------------------------------- paint() ----------------/

 public void update(Graphics g)
 {
  if(Sounds.loaded || !Sounds.play)
  {
   paint(g);
  }
 }

 public void paint(Graphics g)
 {
  Graphics bg;
  Image    bgImg;
  bgImg  = createImage(width, height);
  bg     = bgImg.getGraphics();
  bg.setFont(defFont);

  bg.setColor(Color.white);
  for(int i = 0; i < SFnumOfStars; i++)
  {
   if(SFshown[i])
   {
    bg.drawLine(SFposX[i], SFposY[i], SFposX[i]+SFspeedX[i]/2, SFposY[i]+SFspeedY[i]/2);
   }
  }

  irue.paint(bg);
  Flying[] flyers = new Flying[66];
  int inFlyer = 0;

  for(int i = 0; i < 15; i++)
  {
   flyers[inFlyer++] = interceptors[i];
   flyers[inFlyer++] = heavyFighters[i];
   flyers[inFlyer++] = zephis[i];
  }
  for(int i = 0; i < 20; i++)
  {
   flyers[inFlyer++] = asteroids[i];
  }
  flyers[inFlyer++] = ship;

  Flying.sort(flyers);

  for(int i = 0; i < flyers.length; i++)
  {
   flyers[i].paint(bg);
  }

  if(showShieldBars && levelWait == 0)
  {
   for(int i = 0; i < 15; i++)
   {
    interceptors[i].paintBar(bg);
    heavyFighters[i].paintBar(bg);
    zephis[i].paintBar(bg);
   }
   for(int i = 0; i < 20; i++)
   {
    asteroids[i].paintBar(bg);
   }
   irue.paintBar(bg);
  }

  if(levelWait != 0 && ship.alive && !ship.wonTheGame)
  {
   bg.setFont(annFont);
   bg.setColor(new Color(0xFFFF77));
   bg.drawString("Level " + level, width/2 - 30, height/2 + 7);
  }

  bg.setFont(defFont);
  bg.setColor(Color.green);
  bg.drawString("Time Elapsed: "+(counter/1200)+" min "+(counter/20)%60+" s",
   5, height - 5);
  bg.drawString("Score: " + score, 5, 15);
  bg.drawString("Level: " + level, width / 4 + 5, 15);
  bg.drawString("Highscore: " + highScore, width / 2 + 5, 15);
  bg.setColor(mix(new Color(0xBB0000), new Color(0x00AA00),
   100-ship.shield+(ship.shield*(100-ship.shield)/70),
   ship.shield+(ship.shield*(100-ship.shield)/50)));
  bg.fillRect(width - 5 - ship.shield, 5, ship.shield, 10);
  bg.setColor(Color.lightGray);
  bg.draw3DRect(width - 105, 5, 100, 10, false);

  if(!ship.alive || ship.wonTheGame)
  {
   bg.setFont(annFont);
   bg.setColor(new Color(0xFFFF77));
   if(!ship.alive || cheated)
   {bg.drawString("G A M E   O V E R", width/2 - 80, height/2);}
   else
   {bg.drawString("YOU WON THE GAME", width/2 - 90, height/2);}
   bg.setFont(defFont);
   bg.drawString("Press F2 to restart", width/2 - 35, height/2 + 12);
   if(score > lastScore)
   {
    bg.drawString("You got the highscore!", width/2 - 45, height/2 - 22);
   }
  }

  if(paused)
  {
   bg.setColor(new Color(0xFFFF77));
   bg.setFont(defFont);
   bg.drawString("Paused", 5, height - 35);
  }
  if(Sounds.loaded && Sounds.play && Sounds.mute)
  {
   bg.setColor(new Color(0xFFFF77));
   bg.setFont(defFont);
   bg.drawString("Mute", 5, height - 20);
  }

  help.paint(bg);

  if(!help.visible)
  {
   if(bg.drawImage(infoImg, width-infoImg.getWidth(this)-2,
    height-infoImg.getHeight(this)-2, this))
   {
    if(mouseOverInfoImg)
    {
     bg.setColor(Color.gray);
     bg.draw3DRect(width-infoImg.getWidth(this)-4,
      height-infoImg.getHeight(this)-4,
      infoImg.getWidth(this)+2, infoImg.getHeight(this)+2, true);
    }
   }
   else
   {
    bg.setFont(defFont);
    bg.setColor(Color.gray);
    if(mouseOverInfoImg)
    {
     bg.draw3DRect(width - 26, height - 15,
      23, 12, true);
     bg.setColor(new Color(0x9999ff));
    }
    else
    {
     bg.setColor(Color.white);
    }
    bg.drawString("info", width - 24, height - 4);
   }
  }

  g.drawImage(bgImg, 0, 0, this);

  if(!Sounds.loaded && Sounds.play)
  {
   g.setColor(new Color(0xFFFF77));
   g.setFont(defFont);
   g.drawString("Loading Sounds", 5, height - 20);
   Sounds.laser = getAudioClip(getCodeBase(), "Laser.au");
   g.fillRect(0, 0, width*2/78, 3);
   Sounds.asteroid = getAudioClip(getCodeBase(), "Asteroid.au");
   g.fillRect(0, 0, width*13/78, 3);
   Sounds.enemy = getAudioClip(getCodeBase(), "Enemy.au");
   g.fillRect(0, 0, width*35/78, 3);
   Sounds.hit = getAudioClip(getCodeBase(), "Hit.au");
   g.fillRect(0, 0, width*37/78, 3);
   Sounds.die = getAudioClip(getCodeBase(), "Die.au");
   g.fillRect(0, 0, width*69/78, 3);
   Sounds.level = getAudioClip(getCodeBase(), "Level.au");
   g.setColor(Color.black);
   g.fillRect(0, 0, width, 3);
   Sounds.loaded = true;
  }
 }

//------------------------------ Skeppets metoder --------------/

 void moveTargeter(int xTarget, int yTarget)
 {
  ship.targetX = xTarget;
  ship.targetY = yTarget;
  if(ship.targetX < 5)
  {ship.targetX = 5;}
  if(ship.targetY < 5)
  {ship.targetY = 5;}
  if(ship.targetX > width - 5)
  {ship.targetX = width - 5;}
  if(ship.targetY > height - 5)
  {ship.targetY = height - 5;}
 }

 void ShMove(int xMove, int yMove)
 {
  if(ship.alive && !ship.wonTheGame)
  {
   ship.middleX += xMove;
   ship.middleY += yMove;
   if(ship.middleX < 30)
   {ship.middleX = 30;}
   if(ship.middleY < 35)
   {ship.middleY = 35;}
   if(ship.middleX > width - 30)
   {ship.middleX = width - 30;}
   if(ship.middleY > height - 35)
   {ship.middleY = height - 35;}
   ship.autoDownSpeed = 0;
   ShRender();
  }
  
 }

 void ShRender()
 {
  ship.sprite = new Polygon();
  if(ship.landingStadium == 0)
  {
   for(int i = 0; i < ship.shape.npoints; i++)
   {
    double sin_a = Math.sin(ship.angle);
    double cos_a = Math.cos(ship.angle);
    ship.sprite.addPoint((int)(Math.round(ship.shape.xpoints[i]*cos_a
     + ship.shape.ypoints[i]*sin_a)) + ship.middleX,
     (int)(Math.round(ship.shape.ypoints[i]*cos_a
     - ship.shape.xpoints[i]*sin_a)) + ship.middleY);
   }
  }
  else
  {
   for(int i = 0; i < ship.shape.npoints; i++)
   {
    ship.sprite.addPoint(ship.shape.xpoints[i]*(101-ship.landingStadium)/100+ ship.middleX,
     ship.shape.ypoints[i]*(101-ship.landingStadium)/100+ ship.middleY);
   }
  }
 }

 void ShShoot()
 {
  if(ship.alive && levelWait == 0 && !ship.wonTheGame)
  {
   Sounds.play(Sounds.laser);
   for(int i = 0; i < 20; i += 4)
   {
    if(!ship.shots[i].shooting)
    {
     ship.shots[i].shoot(ship.sprite.xpoints[2], ship.sprite.ypoints[2],
      ship.targetX, ship.targetY);
     ship.shots[i+1].shoot(ship.sprite.xpoints[4], ship.sprite.ypoints[4],
      ship.targetX, ship.targetY);
     ship.shots[i+2].shoot(ship.sprite.xpoints[8], ship.sprite.ypoints[8],
      ship.targetX, ship.targetY);
     ship.shots[i+3].shoot(ship.sprite.xpoints[10], ship.sprite.ypoints[10],
      ship.targetX, ship.targetY);
     incScore(-1, 0);
     return;
    }
   }
  }
 }

 void ShChangeShield(int inc)
 {
  if(ship.alive)
  {
   if(inc < 0)
   {
    ship.usingShield    = true;
    ship.shieldCounter -= inc;
   }
   ship.shield += inc;
   if(ship.shield <= 0)
   {
    ship.autoDownSpeed = 4;
    ship.shield        = 0;
    ship.shieldCounter = 0;
    ship.alive         = false;
    Sounds.play(Sounds.die);
   }
   if(ship.shield > 100)
   {
    ship.shield = 100;
   }
  }
 }

//----------------------------------- Andra funktioner -------/

 void restart()
 {
  ship = new Ship(width, height, this);
  lastScore = highScore;
  irue = new Irue(width, height, this);

  asteroids = new Asteroid[20];
  for(int i = 0; i < 20; i++)
  {
   asteroids[i] = new Asteroid(width, height);
  }
  interceptors  = new Interceptor[15];
  heavyFighters = new HeavyFighter[15];
  zephis        = new Zephi[15];
  for(int i = 0; i < 15; i++)
  {
   interceptors[i]  = new Interceptor(width, height, ship);
   heavyFighters[i] = new HeavyFighter(width, height, ship);
   zephis[i]        = new Zephi(width, height, ship);
  }

  maxAsteroids     = 8;
  maxInterceptors  = 0;
  maxHeavyFighters = 0;
  score            = 0;
  levelC           = 0;
  level            = 1;
  levelWait        = (height/2 - ship.middleY)/3;
  countSinceLevel  = 0;
  counter          = 0;
  cheated          = false;

  for(int i = 0; i < SFnumOfStars; i++)
  {
   SFshown[i]  = false;
   SFposX[i]   = 0;
   SFposY[i]   = 0;
   SFspeedX[i] = 0;
   SFspeedY[i] = 0;
  }
 }

 int inAsteroid(int x, int y)
 {
  for(int i = 0; i < 20; i++)
  {
   if(asteroids[i].inside(x, y))
   {
    return i;
   }
  }
  return -1;
 }

 int inInterceptor(int x, int y)
 {
  for(int i = 0; i < 15; i++)
  {
   if(interceptors[i].inside(x, y))
   {
    return i;
   }
  }
  return -1;
 }

 int inHeavyFighter(int x, int y)
 {
  for(int i = 0; i < 15; i++)
  {
   if(heavyFighters[i].inside(x, y))
   {
    return i;
   }
  }
  return -1;
 }

 int inZephi(int x, int y)
 {
  for(int i = 0; i < 15; i++)
  {
   if(zephis[i].inside(x, y))
   {
    return i;
   }
  }
  return -1;
 }

 void crashAll()
 {
  for(int i = 0; i < 20; i++)
  {
   asteroids[i].crash();
  }
  for(int i = 0; i < 15; i++)
  {
   interceptors[i].crash();
   heavyFighters[i].crash();
   zephis[i].crash();
  }
 }

 void incScore(int points, int levelCount)
 {
  if(!ship.alive || ship.wonTheGame)
  {
   return;
  }
  if(!cheated)
  {
   score  += points;
  }
  levelC += levelCount;
  if(level == 1 && levelC >= 12)
  {
   level           = 2;
   levelWait       = 100;
   levelC          = 0;
   maxAsteroids    = 5;
   maxInterceptors = 1;
   countSinceLevel = 0;
   crashAll();
  }
  else if(level == 2 && levelC >= 35)
  {
   level            = 3;
   levelWait        = 100;
   levelC           = 0;
   maxAsteroids     = 9;
   maxInterceptors  = 2;
   maxHeavyFighters = 0;
   countSinceLevel  = 0;
   crashAll();
  }
  else if(level == 3 && levelC >= 45)
  {
   level            = 4;
   levelWait        = 100;
   levelC           = 0;
   maxAsteroids     = 20;
   maxInterceptors  = 1;
   maxHeavyFighters = 0;
   countSinceLevel  = 0;
   crashAll();
  }
  else if(level == 4 && levelC >= 20)
  {
   level            = 5;
   levelWait        = 100;
   levelC           = 0;
   maxAsteroids     = 10;
   maxInterceptors  = 3;
   maxHeavyFighters = 0;
   countSinceLevel  = 0;
   crashAll();
  }
  else if(level == 5 && levelC >= 45)
  {
   level            = 6;
   levelWait        = 100;
   levelC           = 0;
   maxAsteroids     = 6;
   maxInterceptors  = 1;
   maxHeavyFighters = 1;
   countSinceLevel  = 0;
   crashAll();
  }
  else if(level == 6 && levelC >= 50)
  {
   level            = 7;
   levelWait        = 100;
   levelC           = 0;
   maxAsteroids     = 15;
   maxInterceptors  = 1;
   maxHeavyFighters = 3;
   countSinceLevel  = 0;
   crashAll();
  }
  else if(level == 7 && levelC >= 80)
  {
   level            = 8;
   levelWait        = 100;
   levelC           = 0;
   maxAsteroids     = 15;
   maxInterceptors  = 5;
   maxHeavyFighters = 2;
   countSinceLevel  = 0;
   crashAll();
  }
  else if(level == 8 && levelC >= 60)
  {
   level            = 9;
   levelWait        = 100;
   levelC           = 0;
   maxAsteroids     = 10;
   maxInterceptors  = 12;
   maxHeavyFighters = 0;
   countSinceLevel  = 0;
   crashAll();
  }
  else if(level == 9 && levelC >= 40)
  {
   level            = 10;
   levelWait        = 100;
   levelC           = 0;
   maxAsteroids     = 0;
   maxInterceptors  = 0;
   maxHeavyFighters = 0;
   countSinceLevel  = 0;
   crashAll();
  }
  if(score < 0)
  {
   score = 0;
  }
  if(score >= lastScore && levelWait == 0)
  {
   highScore = score;
  }
 }

 Color mix(Color c1, Color c2, int pc1, int pc2)
 {
  int red   = c1.getRed()*pc1   + c2.getRed()*pc2;
  int green = c1.getGreen()*pc1 + c2.getGreen()*pc2;
  int blue  = c1.getBlue()*pc1  + c2.getBlue()*pc2;
  return new Color(red/100, green/100, blue/100);
 }

//----------------------- Händelsehanterare för KeyListener ----/

 public void keyTyped(KeyEvent e)
 {
 }

 public void keyPressed(KeyEvent e)
 {
  if(e.getKeyCode() == KeyEvent.VK_CONTROL)
  {
   controlDown = true;
  }
  else if(e.getKeyCode() == KeyEvent.VK_F2)
  {
   restart();
  }
  else if(e.getKeyCode() == KeyEvent.VK_F12)
  {
   cheated   = true;
   if(level == 10)
   {
    if(!irue.alive)
    {
     irue.alive   = true;
     irue.stadium = 100;
    }
    countSinceLevel = 2000;
    crashAll();
   }
   else
   {
    incScore(0, 1000);
   }
   if(levelWait > 20)
   {
    levelWait = 20;
   }
  }
  else if(e.getKeyCode() == 'P')
  {
   paused = !paused;
   if(paused || help.visible)
   {
    repaint();
   }
  }
  else if(e.getKeyCode() == 'M')
  {
   Sounds.mute = !Sounds.mute;
   if(paused || help.visible)
   {
    repaint();
   }
  }
  else if(e.getKeyCode() == 'B')
  {
   showShieldBars = !showShieldBars;
   if(paused)
   {repaint();}
  }
  else if(!e.isActionKey())
  {
   pressedKey = e.getKeyCode();
  }
 }

 public void keyReleased(KeyEvent e)
 {
  if(e.getKeyCode() == KeyEvent.VK_CONTROL)
  {
   controlDown = false;
  }
  else
  {
   if(e.getKeyCode() == pressedKey && !e.isActionKey())
   {
    pressedKey = 0;
   }
  }
 }

//--------------------- Händelsehanterare för MouseListener -----/

 public void mouseClicked(MouseEvent e)
 {
 }

 public void mousePressed(MouseEvent e)
 {
  if(mouseOverInfoImg)
  {
   help.show(0);
   repaint();
  }
  else
  {
   if(help.visible)
   {
    if(help.click(e.getX(), e.getY()))
    {
     repaint();
    }
   }
   else if((~e.getModifiers() & MouseEvent.BUTTON1_MASK) == 0)
   {
    ShShoot();
   }
   else if((~e.getModifiers() & MouseEvent.BUTTON3_MASK) == 0)
   {
   }
  }
 }

 public void mouseReleased(MouseEvent e)
 {
 }

 public void mouseEntered(MouseEvent e)
 {
  mouseEntered = true;
 }

 public void mouseExited(MouseEvent e)
 {
  mouseEntered     = false;
  mouseOverInfoImg = false;
  if(paused || help.visible)
  {
   repaint();
  }
 }

//--------------- Händelsehanterare för MouseMotionListener -----/

 public void mouseDragged(MouseEvent e)
 {
  mouseEntered = true;
  mouseX       = e.getX();
  mouseY       = e.getY();
  if((counter & 3) == 0 
   &&(~e.getModifiers() & MouseEvent.BUTTON1_MASK) == 0)
  {
   ShShoot();
  }
  else if((~e.getModifiers() & MouseEvent.BUTTON3_MASK) == 0)
  {
  }
 }

 public void mouseMoved(MouseEvent e)
 {
  mouseEntered = true;
  mouseX       = e.getX();
  mouseY       = e.getY();
  if(!help.visible
   &&((e.getX() > width - 26 && e.getY() > height - 14)
   ||(e.getX() > width-infoImg.getWidth(this)-4
   && e.getY() > height-infoImg.getHeight(this)-4)))
  {
   setCursor(new Cursor(Cursor.HAND_CURSOR));
   mouseOverInfoImg = true;
   if(paused || help.visible)
   {
    repaint();
   }
  }
  else
  {
   if(ship.alive && !help.visible && !ship.wonTheGame)
   {
    setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
   }
   else
   {
    setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
   }
   mouseOverInfoImg = false;
   if(paused || help.visible)
   {
    repaint();
   }
  }
 }

//----------------------------------- HighScore -----------------/

void readHighscore()
{
 if(getCodeBase().getProtocol().equals("http"))
 {
  int currHs = highScore;
  try
  {
   InputStream is = new URL(getCodeBase(), "hs/highscore").openStream();
   byte[] bytes = new byte[4];
   if(is.available() >= 4)
   {
    is.read(bytes);
    highScore = bytes[0] << 24 | bytes[1] << 16 | bytes[2] << 8 | bytes[3];
    if(currHs > highScore)
    {
     highScore = currHs;
    }
   }
   is.close();
  }
  catch(Exception e)
  {
   highScore = currHs;
  }
 }
}

void writeHighscore()
{
 if(getCodeBase().getProtocol().equals("http"))
 {
  try
  {
   URLConnection uc = new URL(getCodeBase(), "hs/highscore").openConnection();
   OutputStream os = uc.getOutputStream();
   byte[] bytes = new byte[4];
   bytes[0] = (byte)(highScore >> 24);
   bytes[1] = (byte)(highScore >> 16);
   bytes[2] = (byte)(highScore >> 8);
   bytes[3] = (byte)(highScore);
   os.write(bytes);
   os.close();
  }
  catch(Exception e)
  {
  }
 }
}

//-------------------------------------- stop() -----------------/

 public void stop()
 {
  if(runThread != null)
  {
   runThread.interrupt();
  }
  //writeHighscore();
 }

 public void destroy()
 {
  if(runThread != null)
  {
   runThread = null;
  }
 }
}