// Code by Sergio Fanchiotti (c) 1997
//
// Free to use and copy for any purpose.
//
// No responsability for any mis-use or problems 
// due to the usage of this code on any device.
// (i.e. crashing your browser and/or your OS)
//

import java.awt.*;
import java.applet.*;
import java.util.*;

public class UFO_Attack extends Applet implements Runnable {

	Image buffer   = null ;	// Temporary image buffer
	Image backdrop = null ; // Backdrop image 
	Image bgimg    = null ; // Original backdrop  image 
	Image ufostrip = null ;	// UFO Sequence
	Image missile  = null ; // Misile Sequence
	Image missile_explosion
	               = null ; // Misile Esplosion Sequence

	MediaTracker tracker = null ;

	Graphics  buf_g = null ; // Buffer graphics object
	Graphics  bkd_g = null ; // Backdrop graphics object
	Dimension window_size = null;
	Font font ;
	Font font_s ;
	
        AudioClip explosion       = null ;
        AudioClip newufo         = null ;
        AudioClip missile_launch = null ;

	
        Thread  game      = null ;
	boolean game_over = true ;
	int     mouse_x   = 100 ;
        Rectangle paint_area = new Rectangle() ;
        Rectangle new_area   = new Rectangle() ;


	Launcher L  = null ;
	Missile  M  = null ;
	Vector   UV = new Vector() ;
	Vector   EV = new Vector() ;
	
        int NU    = 1 ;
	int score = 0 ;
	
	// Colors
	Color gunColor;
	Color mColor;
	Color ufoColor;
	Color scoreColor;
	Color bgColor;
	
	public void init() {
	  System.out.println("UFO Attack: A game by Sergio Fanchiotti") ;
	  tracker = new MediaTracker(this) ;

          bgimg = getImage(this.getCodeBase(),"bgimg.gif") ;
	  tracker.addImage(bgimg,0) ;

          ufostrip = getImage(this.getCodeBase(),"ufostrip.gif") ;
	  tracker.addImage(ufostrip,0) ;

          missile  = getImage(this.getCodeBase(),"missile.gif") ;
	  tracker.addImage(missile,0) ;

          missile_explosion = getImage(this.getCodeBase(),"explosionstrip.gif") ;
	  tracker.addImage(missile_explosion,0) ;

	  font   = new Font("Helvetica", Font.BOLD, 24) ;
	  font_s = new Font("Helvetica", Font.BOLD, 14) ;

          // Define the colors to use
	  bgColor    = new Color(0,0,128);
	  gunColor   = new Color(0,88,0);
	  mColor     = new Color(255,255,255);
	  ufoColor   = new Color(255,0,0);
	  scoreColor = new Color(0,0,255);
	}


	public void start() {
	  // Change the cursor
	  getFrame(this).setCursor(Frame.CROSSHAIR_CURSOR) ;


	  window_size = size();

	  buffer = null;
 	  buffer = createImage(window_size.width, window_size.height);

	  backdrop = null;
 	  backdrop = createImage(window_size.width, window_size.height);

	  buf_g = buffer.getGraphics();
	  buf_g.setColor(bgColor);
	  buf_g.fillRect(0, 0, window_size.width, window_size.height);


          // Display initial message
          set_say_font(font) ;
          set_say_mode(CENTER) ;
          set_say_style(SHADOW) ;
	  say("UFO",10,80) ;
	  say("ATTACK") ;
          set_say_font(font_s) ;
          set_say_style(NORMAL) ;
	  say("") ;
	  say("Click to start") ;
	  say("a game") ;

	  //repaint() ;
	  Graphics g = getGraphics() ;
          g.drawImage(buffer,0,0,this) ;

          // Initialize the launcher
	  mouse_x = window_size.width/2 ; 
          L = new Launcher(this) ;
          L.set_color(gunColor) ;

          // Initialize the missile
          M = new Missile(this) ;
          M.set_color(mColor) ;
		

          // Load the sound files now
	  if (explosion == null) 
	    explosion = getAudioClip(getCodeBase(),"explosion.au") ;

	  if (newufo == null) 
	    newufo    = getAudioClip(getCodeBase(),"sonar.au") ;

	  if (missile_launch == null) 
	    missile_launch = getAudioClip(getCodeBase(),"rocket.au") ;

	  game_over = true ;

          newufo.play() ;         // Play sounds
	  missile_launch.play() ;
	  explosion.play() ;

	}


	public void stop() {
	  // Stop the game if running 
	  if (game != null) {
	    game.stop() ;
	    game = null ; // and eliminate the thread
	  }
	  // Reset the cursor
	  getFrame(this).setCursor(Frame.DEFAULT_CURSOR) ;
	}


        // The main game thread
	public void run() {
	  // Define some local variables
	  UFO  U ;
	  Explosion  E ;
	  long count = 0 ;
          long ti    = 0 ;
	   
	  // Wait for the images to load
	  Graphics g = getGraphics() ;
	  g.setColor(Color.red) ;
	  g.drawString("Starting Game...", 20,20) ;

          while (tracker.checkAll(true) == false) { 
	    if ((ti++ % 2) == 0) 
	      g.setColor(Color.red) ;
	    else 
	      g.setColor(Color.green) ;

	    g.drawString("*", 10,22) ;
            try {Thread.sleep(50);} catch (InterruptedException e) { } ;

	    if (ti > 1000) break ;
	  }
	  
          if (tracker.isErrorAny()) {
	    showStatus("Error getting images") ;
            return ;
	  }
	  showStatus("Loading completed") ;
	  g.dispose() ;


          // Paint the backdrop buffer
	  buf_g = backdrop.getGraphics();
          buf_g.drawImage(bgimg,0,0,window_size.width,window_size.height,this) ;

          // Paint the screen
	  buf_g = getGraphics();
          buf_g.drawImage(backdrop,0,0,this) ;

          // Paing the buffer
	  buf_g = buffer.getGraphics();
          buf_g.drawImage(bgimg,0,0,window_size.width,window_size.height,this) ;

          // Display the buffer
	  repaint() ;

          // Display the initial setup
	  display_score() ;
	  L.draw() ;
          showStatus("UFO ATTACK") ;

	  // Action loop
          for (;;) {
	    ti = System.currentTimeMillis() ;

            // If there is place for one more UFO, try to add one
	    // with some probability 
	    if ((UV.size() < NU) && 
	        (Math.random() > (UV.size() == 0 ? 0.90 : 0.98))) {
              newufo.play() ;  // Play a bell 
	      U = new UFO(this) ; 
              U.set_color(ufoColor) ;

              // Set the UFO to fast descent if:
	      if (score > 10 && Math.random() > 0.7) U.vy -= 1 ;

              // Add UFO to the list
	      UV.addElement(U) ;
	    }

            // Draw the explosion in the backdrop
	    // and eliminate it from the list if ended
	    for (int j=EV.size()-1; j>=0 ; --j) {
	      E = (Explosion) EV.elementAt(j) ;
	      if (E.active) {
	        // System.out.println("Drawing Explosion " + j) ;
	        E.draw() ;
              }
              else {
	        // System.out.println("Ending Explosion " + j) ;
	        E.erase() ;
		EV.removeElementAt(j) ;
	      }
	    }
	  
	    // Move the launcher and the missile
	    L.move() ;
	    if (M.active() == true) M.move() ;

            // Move each UFO
	    for (int i=0; i < UV.size(); ++i) {
	      U = (UFO) UV.elementAt(i) ;
	      U.move() ;
	    }


            // Check for collision between UFO and missile
	    for (int i=(UV.size()-1); i >=0 ; --i) {
	      U = (UFO) UV.elementAt(i) ;
	      if (U.active() && M.active() && U.collision(M)) {
		++score ;
	        explosion.stop() ; 
		display_score() ;
	        explosion.play() ; 

                // Increase the max # of UFOs every 10 destroyed
		// till we reach a max of 5 attacking
	        if ((NU < 5) && (score % 10) == 1)  ++NU ;

                // Erase the missile and deactivate it
	        M.active(false) ;
		M.erase() ;

                // Erase and deactivate the UFO hit
		U.active(false) ;
		U.erase() ;

		// Display an explosion
		E = new Explosion(this,U.px,U.py) ;
	        // System.out.println("Adding Explosion") ;
		EV.addElement(E) ;
	      }

              // Draw the UFO or eliminate it from the list
	      if (U.active()) 
	        U.draw() ;
              else 
	        UV.removeElementAt(i) ;

              // If a UFO reaches the floor then you've lost
              if ((U.py - U.h/2) <=0) {
	        game_over = true ;
		display_game_over() ;
		return ;
	      }
	    }

            // If the launcher moves... redraw
	    if (L.has_moved() || ((M.py-M.h) < (L.py+L.h)) || (! M.active()) )
	      L.draw() ;

            // If active redraw the missile
	    if (M.active() == true) M.draw() ;


            // Make the loop last 20ms in case the CPU is too fast...
            ti = System.currentTimeMillis() - ti ;
	    ti = 20 - ti ; 
	    ti = ti > 0 ?  10 + ti : 10 ; // At least sleep por 10ms
            Thread.yield() ; // Let the GC work?
            try {Thread.sleep(ti);} catch (InterruptedException e) { } ;

            // Repaint every 100 cycles... just in case
	    if ((count = ++count % 500) == 0) {
	      repaint() ;
              // g.drawImage(buffer,0,0,this) ;
	    }
	  }
	}


	public void display_score() {
          Graphics bkd_g = backdrop.getGraphics();
          bkd_g.clipRect(window_size.width/2, 0, window_size.width/2, 40);
          bkd_g.drawImage(bgimg,0,0,window_size.width,window_size.height,this) ;

          bkd_g.setColor(Color.red) ;
          bkd_g.setFont(font) ;
	  String aux = score > 9 ? "" : "0" ;
          bkd_g.drawString(aux+score, window_size.width - 60,30) ;
          bkd_g.dispose() ;
          // bkd_g = null ;

          Graphics bg = buffer.getGraphics() ;
          bg.clipRect(0, 0, window_size.width, 40);
          bg.drawImage(backdrop,0,0,this) ;
          bg.dispose() ;
          // bg = null ;

          Graphics g = getGraphics() ;
          g.clipRect(0, 0, window_size.width, 40);
          g.drawImage(buffer,0,0,this) ;
          g.dispose() ;
          // g = null ;
	}

	public void display_game_over() {
          set_say_font(font) ;
          set_say_mode(CENTER) ;
          set_say_style(SHADOW) ;
	  set_say_pos(10,80) ;
	  say("GAME OVER") ;
          set_say_font(font_s) ;
          set_say_style(NORMAL) ;
	  say("(click to start)") ;
	  repaint() ;
          try {Thread.sleep(500);} catch (InterruptedException e) { } ;
	}

	public boolean mouseMove(Event e, int x, int y) {
	  // showStatus("mouse at: (" + x + ", " + y + ")");
	  mouse_x = x ;
	  return true;
	}

        // Capture the mouse clicks
	public boolean mouseDown(Event e, int x, int y) {
	  if (game_over) {
	    game_over = false ;
	    if (game != null) {
	      game.stop() ;
	      game = null ;
	    }
	    NU    = 1 ;
	    score = 0 ;
	    M.active(false) ;
	    UV.removeAllElements() ;
	    EV.removeAllElements() ;

	    game  = new Thread(this) ;
	    game.setPriority(Thread.MIN_PRIORITY) ;
	    game.start() ;

	    buf_g.dispose() ;

	    return true ;
	  }

	  if (M != null && ! M.active()) {
	    missile_launch.stop() ;
	    missile_launch.play() ;
	    M.set_pos(L.px,L.py) ;
	    M.active(true) ;
	  }

	  return true;
	}

	
	// The paint methos just draws the buffer
	public void paint(Graphics g) {
 	  if (buffer != null) g.drawImage(buffer, 0, 0, this);
	}

        // Makes an animation smoother
	public void update(Graphics g) { 
	  paint(g) ; 
	}

        // Get the Frame of this applet
        public Frame getFrame(Component c) {
          while( c != null && !(c instanceof java.awt.Frame) )
                c = c.getParent();
          return (Frame) c;
        }


        // Text Display Constants
        public static final int CENTER = 1 ;  // Modes: Centered
        public static final int LEFT   = 2 ;  //        Left Justified
        public static final int RIGHT  = 3 ;  //        Right Justified
        public static final int FREE   = 0 ;  //        At x,y

        public static final int NORMAL = 0 ;  // Styles: Normal
        public static final int SHADOW = 1 ;  //         Shadowed 

        // Text Display Variables
        private int  say_pos_y   =  0 ;
        private int  say_pos_x   =  0 ;
        private int  say_mode    = -1 ;
        private int  say_style   = -1 ;
        private int  say_margin  = 10 ;
        private Font say_font    = null ;

        // Text Print Methods
	public void say(String s, int x, int y) {
	  set_say_pos(x, y) ;
	  say(s) ;
	}

	public void say(String s) {
	  FontMetrics fm = getFontMetrics(say_font) ;

          // Compute the x position
	  switch(say_mode) {
	    case CENTER:
	      say_pos_x = (window_size.width - fm.stringWidth(s))/2 ;
	      break ;
	    case RIGHT:
	      say_pos_x = window_size.width - fm.stringWidth(s) - say_margin ;
	      break ;
	    case LEFT:
	    default :
	      say_pos_x = say_margin ;
	      break ;
	  }

          Graphics bg = buffer.getGraphics() ;
          bg.setFont(say_font) ;

          // Print style extras
	  if (say_style == SHADOW) {
            bg.setColor(new Color(150,150,150)) ;
            bg.drawString(s, say_pos_x+2,say_pos_y+1) ;
	  }

          // Print string
          bg.setColor(Color.white) ;
          bg.drawString(s, say_pos_x,say_pos_y) ;

          // Shift y position to next line
	  say_pos_y += (int) (1.2 * fm.getHeight()) ;

          // Free some resources
          bg.dispose() ;
	}

	public void set_say_mode(int m) {
	  say_mode = m ;
	}

	public void set_say_style(int s) {
	  say_style = s ;
	}

	public void set_say_font(Font f) {
	  say_font = f ;
	}

	public void set_say_margin(int margin) {
	  say_margin = margin ;
	}

	public void set_say_pos(int x, int y) {
	  say_pos_x = x ;
	  say_pos_y = y ;
	}
}


class Piece {
  UFO_Attack a ;

  int px,py ;
  int opx,opy ;
  int w,h ;
  int vx,vy ;
  Color c ;
  boolean active = false ;
  Image img = null ;

  public void set_pos(int x, int y) {
    px = opx = x ;
    py = opy = y ;
  }

  public void set_vel(int x,int y) {
    vx = x ;
    vy = y ;
  }

  public void set_size(int x,int y) {
    w = x ;
    h = y ;
  }

  public void set_color(Color c) {
    this.c = c ;
  }

  public void set_draw_rectangles(Rectangle o, Rectangle n) {
    int sh = a.window_size.height ; 

    int x  = px - w/2 ;
    int y  = (sh - py) - h/2 ;

    int ox = opx - w/2 ;
    int oy = (sh - opy) - h/2 ;
    
    o.reshape(ox,oy,w,h) ; 
    n.reshape(x,y,w,h) ; 
  }

  public boolean active() {
    return active ;
  }

  public void active(boolean s) {
    active = s ;
  }

  public boolean collision(Piece p) {
    int dpx = Math.abs(px - p.px) ;
    int dpy = Math.abs(py - p.py) ;

    if ((dpx < (Math.max(w/2,p.w/2))+1) && (dpy < (Math.max(h/2,p.h/2)+1))) 
      return true ;

    return false ;
  }

  public void draw() {
    set_draw_rectangles(a.paint_area, a.new_area) ;

    // a.buf_g.setColor(a.bgColor);
    // a.buf_g.fillRect(a.paint_area.x, a.paint_area.y, w, h);

    Graphics bg = a.buffer.getGraphics() ;
    bg.clipRect(a.paint_area.x, a.paint_area.y, w, h);
    bg.drawImage(a.backdrop,0,0,a) ;
    bg.dispose() ;
    // bg = null ;

    a.buf_g.setColor(c);
    a.buf_g.fillRect(a.new_area.x, a.new_area.y, w, h);

    a.paint_area.add(a.new_area) ;

    Graphics g = a.getGraphics() ;
    g.clipRect(a.paint_area.x ,a.paint_area.y, a.paint_area.width, a.paint_area.height);
    g.drawImage(a.buffer, 0, 0, a);
    g.dispose() ;
    // g = null ;
  }

  public void erase() {
    set_draw_rectangles(a.paint_area, a.new_area) ;
    a.paint_area.add(a.new_area) ;

    // Copy the backdrop into the buffer
    Graphics bg = a.buffer.getGraphics() ;
    bg.clipRect(a.paint_area.x, a.paint_area.y, a.paint_area.width, a.paint_area.height);
    bg.drawImage(a.backdrop,0,0,a) ;
    bg.dispose() ;

    // Paint the change into the screen
    Graphics g = a.getGraphics() ;
    g.clipRect(a.paint_area.x,a.paint_area.y,a.paint_area.width,a.paint_area.height);
    g.drawImage(a.buffer,0,0, a);
    g.dispose() ;
  }
}

class Launcher extends Piece {

  public Launcher (UFO_Attack a) {
    this.a = a ; 
    w  = 12 ;
    h  = 22 ;
    px = opx = a.window_size.width/2 ;
    py = opy = w/2+1 ;
    active = true ;
    img = a.missile ;
  }

  public void move() {
    opx = px ;
    opy = py ;

    int dx     = a.mouse_x - px ;
    int abs_dx = Math.abs(dx) ;
    int step = 1 ;

    if (abs_dx > 10) 
      step = 5 ;
    else if (abs_dx > 1)
      step = abs_dx/2 ;

    if (dx != 0) {
      px += step*(dx/abs_dx) ;
      if (px < w/2) 
        px = w/2 ;
      else if (px > (a.window_size.width - w/2)) 
        px = a.window_size.width - w/2 ;
    }
  }

  public boolean has_moved() {
    if ((px - opx) != 0) return true ;

    return false ;
  }

  public void draw() {
    set_draw_rectangles(a.paint_area, a.new_area) ;

    // a.buf_g.setColor(a.bgColor);
    // a.buf_g.fillRect(a.paint_area.x, a.paint_area.y, w, h);

    Graphics bg = a.buffer.getGraphics() ;
    bg.clipRect(a.paint_area.x, a.paint_area.y, w, h);
    bg.drawImage(a.backdrop,0,0,a) ;
    bg.dispose() ;
    // bg = null ;


    if (a.M.active()) {
      a.buf_g.setColor(c);
      a.buf_g.fillRect(a.new_area.x, a.new_area.y, w, h);
    }
    else {
      bg = a.buffer.getGraphics() ;
      bg.clipRect(a.new_area.x, a.new_area.y, w, h);
      bg.drawImage(img,a.new_area.x,a.new_area.y,a) ;
      bg.dispose() ;
      // bg = null ;
    }

    a.paint_area.add(a.new_area) ;

    Graphics g = a.getGraphics() ;
    g.clipRect(a.paint_area.x ,a.paint_area.y, a.paint_area.width, a.paint_area.height);
    g.drawImage(a.buffer, 0, 0, a);
    g.dispose() ;
    // g = null ;
  }

}

class Missile extends Piece {
  public Missile (UFO_Attack a) {
    this.a = a ; 
    px = opx = 0 ;
    py = opy = 0 ;
    vx = 0 ;
    vy = 7 ;
    w  = 12 ;
    h  = 22 ;
    active = false ;

    img = a.missile ;
  }

  public void move() {
    opx = px ;
    opy = py ;

    px = a.L.px ;

    // Try to make the speed more realistic
    int dx = px - opx ;
    int nvy = vy*vy - dx*dx ;
    if (nvy > 0) nvy = (int) Math.sqrt(nvy) ; // Should exceptions
    if (nvy < 1) nvy = 1 ;

    py += nvy ;

    if (py > a.window_size.height + 2*h) active = false ;
  }

  int seq  = 0 ;
  // int seq2 = 0 ;
  public void draw() {
    set_draw_rectangles(a.paint_area, a.new_area) ;

    // a.buf_g.setColor(a.bgColor);
    // a.buf_g.fillRect(a.paint_area.x, a.paint_area.y, w, h);

    Graphics bg = a.buffer.getGraphics() ;
    bg.clipRect(a.paint_area.x, a.paint_area.y, w, h);
    bg.drawImage(a.backdrop,0,0,a) ;
    bg.dispose() ;
    // bg = null ;


    // if ((++seq2 % 4) == 0) seq = ++seq % 1 ;
    int dx = px - opx ;
    seq = 0 ;
    if (dx > 0) 
      seq = 1 ;
    else if (dx < 0)
      seq = 2 ;

    bg = a.buffer.getGraphics() ;
    bg.clipRect(a.new_area.x, a.new_area.y, w, h);
    bg.drawImage(img,a.new_area.x-w*seq,a.new_area.y,a) ;

    bg.dispose() ;
    // bg = null ;

    a.paint_area.add(a.new_area) ;

    Graphics g = a.getGraphics() ;
    g.clipRect(a.paint_area.x ,a.paint_area.y, a.paint_area.width, a.paint_area.height);
    g.drawImage(a.buffer, 0, 0, a);
    g.dispose() ;
    // g = null ;
  }

}

class UFO extends Piece {
  public UFO (UFO_Attack a) {
    this.a = a ; 
    vx = (Math.random() > 0.5 ? 1 : -1) ;
    vy = -2 ;
    w  = 20 ;
    h  = 8 ;
    int aw = a.window_size.width ;
    px = opx =  (int) (w/2+1 + (aw-w-2)* Math.random()) ;
    py = opy = a.window_size.height + h/2 + 1  ;
    active = true ;

    img = a.ufostrip ;
  }

  public void move() {
    opx = px ;
    opy = py ;

    px += vx ;
    py += vy ;

    if (py < -h/2) active = false ;

    if ((px <= w/2) || 
        (px >= (a.window_size.width - w/2)) ||
        (Math.random() > 0.96)) {
      vx = -vx ;
    }
  }

  int seq  = 0 ;
  int seq2 = 0 ;
  public void draw() {
    set_draw_rectangles(a.paint_area, a.new_area) ;

    // Clear the old image
    Graphics bg = a.buffer.getGraphics() ;
    bg.clipRect(a.paint_area.x, a.paint_area.y, w, h);
    bg.drawImage(a.backdrop,0,0,a) ;
    bg.dispose() ;
    // bg = null ;


    // Choose the image sequence (every 4 draws change frame)
    if ((++seq2 % 4) == 0) seq = ++seq % 4 ;

    // Paint new region into buffer
    bg = a.buffer.getGraphics() ;
    bg.clipRect(a.new_area.x, a.new_area.y, w, h);
    bg.drawImage(img,a.new_area.x-w*seq,a.new_area.y,a) ;
    bg.dispose() ;

    // Add old and new areas for updating
    a.paint_area.add(a.new_area) ;

    // Paint changes into screen buffer
    Graphics g = a.getGraphics() ;
    g.clipRect(a.paint_area.x ,a.paint_area.y, a.paint_area.width, a.paint_area.height);
    g.drawImage(a.buffer, 0, 0, a);
    g.dispose() ;
  }
}
	
class Explosion extends Piece {
  public Explosion (UFO_Attack a, int x, int y) {
    this.a = a ; 
    w  = 30 ;
    h  = 30 ;
    px = opx = x ;
    py = opy = y ;
    active = true ;
    img = a.missile_explosion ;
  }

  int seq  = 0 ;
  int seq2 = 0 ;
  public void draw() {
    set_draw_rectangles(a.paint_area, a.new_area) ;

    // Clear the old image
    Graphics bkd_g = a.backdrop.getGraphics();
    bkd_g.clipRect(a.paint_area.x, a.paint_area.y, w, h);
    bkd_g.drawImage(a.bgimg,0,0,a.window_size.width,a.window_size.height,a) ;

    // Choose the image sequence (every 4 draws change frame)
    if ((++seq2 % 4) == 0) seq = ++seq % 5 ;

    // Deactivate after drawing the last explosion frame
    if (seq == 4) active = false ;

    // Paint new region into buffer
    bkd_g.clipRect(a.new_area.x, a.new_area.y, w, h);
    bkd_g.drawImage(img,a.new_area.x-w*seq,a.new_area.y,a) ;
    bkd_g.dispose() ;

    // Paint changes into the buffer
    Graphics bg = a.buffer.getGraphics() ;
    bg.clipRect(a.new_area.x,a.new_area.y,w,h);
    bg.drawImage(a.backdrop,0,0,a) ;
    bg.dispose() ;

    // Paint changes into screen buffer
    Graphics g = a.getGraphics() ;
    g.clipRect(a.paint_area.x ,a.paint_area.y, a.paint_area.width, a.paint_area.height);
    g.drawImage(a.buffer, 0, 0, a);
    g.dispose() ;
  }

  public void erase() {
    set_draw_rectangles(a.paint_area, a.new_area) ;

    // Clear the old image
    Graphics bkd_g = a.backdrop.getGraphics();
    bkd_g.clipRect(a.paint_area.x, a.paint_area.y, w, h);
    bkd_g.drawImage(a.bgimg,0,0,a.window_size.width,a.window_size.height,a) ;
    bkd_g.dispose() ;

    // Do the same for the buffer and the screen
    // It will flicker any UFO on top...
    super.erase() ;
  }
}
