import java.awt.*;

/** class Sprite extends Raster
  *
  * class Sprite implements an object that holds an image which can be 
  * drawn onto a Raster.  It contains full support for alpha-blending the
  * sprite onto the background (but that'll be much slower than full
  * transparent or full opaque!). Sprites can move with a velocity, and
  * can collide with other tangible Sprites.
  */
class Sprite extends Raster {
  int x, y;            // current position of sprite on playfield
  Playfield playfield; // current playfield (for dirty rect. updates)
  boolean tangible = false; // Does this sprite collide with other objects?
  String name;         // This sprite's name
  int xvel = 0, yvel = 0;    // x and y velocities

  // initialize sprite with an image
  public Sprite(Image image){ super(image); }

  // set the current playfield for this sprite
  public void setPlayfield(Playfield pf) {
    playfield = pf;
  }

  public void setPos(int newx, int newy) {
    // Dirty old and new locations on the playfield and move the sprite
    playfield.Dirty(x,y,width,height);
    x = newx; y = newy;
    playfield.Dirty(x,y,width,height);  

    // We've moved, now for collision detection
    if (!tangible) return;
    playfield.checkCollision(this);
  }

  public void Tick() {
    // Apply sprite velocity
    setPos(x+xvel, y+yvel);
  }

  public void setVelocity(int xv, int yv) {
    xvel = xv;
    yvel = yv;
  }

  // Does any of this sprite fall in the given rectangle?
  public boolean Occupies(int tx, int ty, int tw, int th) {
    if ((tx > x+width-1) || (ty > y+height-1) || 
	(tx+tw-1 < x) || (ty+th-1 < y)) 
      return false;
    return true;
  }

  // is there a non-transparent pixel from this sprite on the playfield here?
  public boolean isSolid(int tx, int ty) {
    if ((tx < x) || (ty < y) || (tx > x+width-1) || (ty > y+height-1))
      return false;
    if ((pixel[(ty - y)*width + tx-x] >>> 24) == 0)
      return false;
    return true;
  }

  // Sprites don't really collide, but subclases will.
  public void doCollision(Sprite coll) { }
  public void doWallCollision(String side) { }

  // multiply this sprite by an alpha value (0-255), to make it translucent.
  public void multAlpha(int alpha) {
    int pix;

    for (int yloop=0; yloop<height; yloop++)
      for (int xloop=0; xloop<width; xloop++) {
	pix = pixel[yloop*width+xloop]; 
	pixel[yloop*width+xloop] = (pix & 0x00FFFFFF) +  
	  ((((pix >>> 24) * alpha) << 16) & 0xFF000000);
      }
  }

  // draws sprite on a Raster (with transparency)
  public void Draw(Raster bgnd){
    Draw(bgnd, 0, 0, bgnd.width, bgnd.height);
  }

  // draws sprite on a Raster (with transparency and clipping)
  public void Draw(Raster bgnd, int clipx, int clipy, int clipw, int cliph){
    int pix;

    // set clip box
    int xmin = (x < 0) ? -x : 0;
    int ymin = (y < 0) ? -y : 0;
    int xlen = ((x+width) > bgnd.width) ? bgnd.width - x : width;
    int ylen = ((y+height) > bgnd.height) ? bgnd.height - y : height;

    if (clipx > (x + xmin)) xmin = clipx - x;
    if (clipy > (y + ymin)) ymin = clipy - y;
    if ((clipx+clipw) < (x + xlen)) xlen = clipx+clipw-x;
    if ((clipy+cliph) < (y + ylen)) ylen = clipy+cliph-y;

    for (int yloop=ymin; yloop<ylen; yloop++)
      for (int xloop=xmin; xloop<xlen; xloop++) {
	// A sane compiler better make this a register variable...
	pix = pixel[yloop*width+xloop]; 
	switch (pix >>> 24) {             // common cases first
	case 0:                           // full transparent
	  continue;

	case 255:                         // full opaque
	  bgnd.setPixel(pix,x+xloop,y+yloop);
	  break;

	default:                          // real alpha channel
	  int oldpix = bgnd.getPixel(x+xloop,y+yloop);
	  int alpha = (pix >>> 24)+1;
	  int newpix = (255 << 24) +                           // alpha
	    (((alpha*((pix >>> 16) & 0xFF) + 
	      (256 - alpha)*((oldpix >>> 16) & 0xFF)) & 0xFF00) << 8) + // red
	    ((alpha*((pix >>> 8) & 0xFF) + 
	     (256 - alpha)*((oldpix >>> 8) & 0xFF)) & 0xFF00) +       // green
	    ((alpha*(pix & 0xFF) + 
	      (256 - alpha)*(oldpix & 0xFF)) >>> 8);           // blue
	  bgnd.setPixel(newpix,x+xloop,y+yloop);
	}
      }
  }
}
