/***********************************************************************
 * 
 *  G F O ! 
 *  by Chee Chew
 *      and 
 *     Ken Duda 
 *
 *  (c) 1990
 *
 *  This software is free for distribution.  This notice, however, may 
 *  not be altered.
 *  
 *  Enjoy! (and punt... )
 *
 ***********************************************************************/

#include "gfo.h"

redraw_well(Well *w, int x, int y, unsigned int width, unsigned int height)
{
  w->xc->CopyFunction(w->xc->dsp, w->xc->wellpixmap, w->xc->mwin, w->xc->bdraw_gc,
		   x, y, width, height, x,y);
}

clear_well_pixmap(XC *xc)
{
  XFillRectangle(xc->dsp, xc->wellpixmap, xc->wellclear, 0, 0, 
		 xc->width + 1, xc->height  + 1);
}
draw_well_all(Well *w)
{
  clear_well_pixmap(w->xc);
  draw_well(w);
  draw_well_bottom(w);
  w->xc->CopyFunction(w->xc->dsp, w->xc->wellpixmap, w->xc->mwin, w->xc->bdraw_gc, 
		0, 0, w->xc->width, w->xc->height, 0, 0); 
}

XPoint *make_block_poly( Well  *w,  int  x,  int y,  int z)
{
  int x1, x2, y1, y2, t, xx1, xx2, yy1, yy2;
  static XPoint points[7];

  x1 = project_x(w,x,y,z);
  y1 = project_y(w,x,y,z);
  x2 = project_x(w,x+1,y+1,z);
  y2 = project_y(w,x+1,y+1,z);
  if (x1 > x2) { t = x1; x1 = x2; x2 = t; }
  if (y1 > y2) { t = y1; y1 = y2; y2 = t; }  

  xx1 = project_x(w,x,y,z+1);
  yy1 = project_y(w,x,y,z+1);
  xx2 = project_x(w,x+1,y+1,z+1);
  yy2 = project_y(w,x+1,y+1,z+1);
  if (xx1 > xx2) { t = xx1; xx1 = xx2; xx2 = t; }
  if (yy1 > yy2) { t = yy1; yy1 = yy2; yy2 = t; }

  /* completely covered */
  if (y1 <= yy1 && x1 <= xx1 && y2 >= yy2 && x2 >= xx2) {
    points[0].x = x1;
    points[0].y = y1;
    points[1].x = x2;
    points[1].y = y1; 
    points[2].x = x2;  
    points[2].y = y2;
    points[3].x = x1;
    points[3].y = y2;
    points[4].x = x1;
    points[4].y = y1;
    points[5].x = x1;
    points[5].y = y1;
    points[6].x = x1;
    points[6].y = y1;
    return points;
  }
  /* bottom right */
  if ( y1 >= yy1  && x1 >= xx1 )  {
    points[0].x = xx1;
    points[0].y = yy1;
    points[1].x = xx2;
    points[1].y = yy1; 
    points[2].x = x2;  
    points[2].y = y1;
    points[3].x = x2;
    points[3].y = y2;
    points[4].x = x1;
    points[4].y = y2;
    points[5].x = xx1;
    points[5].y = yy2;
    points[6].x = xx1;
    points[6].y = yy1;
    return points;

  }
  
  /* bottom left */
  if  ( y1 >=  yy1 && x1 <= xx1) {
    points[0].x = x1;
    points[0].y = y1;
    points[1].x = xx1;
    points[1].y = yy1; 
    points[2].x = xx2;  
    points[2].y = yy1;
    points[3].x = xx2;
    points[3].y = yy2;
    points[4].x = x2;
    points[4].y = y2;
    points[5].x = x1;
    points[5].y = y2;
    points[6].x = x1;
    points[6].y = y1;
    return points;

  }

  /*  top right */ 
  if  ( y1  <= yy1 && x1 >= xx1 ) {
    points[0].x = x1;
    points[0].y = y1;
    points[1].x = x2;
    points[1].y = y1; 
    points[2].x = x2;  
    points[2].y = y2;
    points[3].x = xx2;
    points[3].y = yy2;
    points[4].x = xx1;
    points[4].y = yy2;
    points[5].x = xx1;
    points[5].y = yy1;
    points[6].x = x1;
    points[6].y = y1;
    return points;

  }
  /* top  left */ 
  if ( y1 <= yy1 && x1 <= xx1 ) {
    points[0].x = x1;
    points[0].y = y1;
    points[1].x = x2;
    points[1].y = y1; 
    points[2].x = xx2;  
    points[2].y = yy1;
    points[3].x = xx2;
    points[3].y = yy2;
    points[4].x = xx1;
    points[4].y = yy2;
    points[5].x = x1;
    points[5].y = y2;
    points[6].x = x1;
    points[6].y = y1;
    return points;
  }
}

draw_well_bottom(Well *w)
{
  int x,y,z, x1,x2,y1,y2, t;
  XPoint  *points;

  for (z = w->depth-1 ; z >= 0; z--)
    for (x = 0; x < w->length; x++)
      for (y = 0; y < w->width; y++)
	if (w->filled[x][y][z]) {
	  x1 = project_x(w,x,y,z);
	  y1 = project_y(w,x,y,z);
	  x2 = project_x(w,x+1,y+1,z);
	  y2 = project_y(w,x+1,y+1,z);
	  if (x1 > x2) { t = x1; x1 = x2; x2 = t; }
	  if (y1 > y2) { t = y1; y1 = y2; y2 = t; }

	  points = make_block_poly(w,x,y,z);
	  XFillPolygon(w->xc->dsp, w->xc->wellpixmap, w->xc->tilegc[z], points,
		       7, Complex, CoordModeOrigin); 
	  XDrawRectangle(w->xc->dsp, w->xc->wellpixmap, w->xc->wellgc,
			 x1, y1, x2-x1, y2-y1); 
	}
}

draw_well(Well *w)
{
  int x, y, z;

  for (z = 1; z <= w->depth; z++) {
    draw_line(w,w->xc->wellpixmap, w->xc->wellgc,0,        0,       z,w->length,0,       z);
    draw_line(w,w->xc->wellpixmap, w->xc->wellgc,w->length,0,       z,w->length,w->width,z);
    draw_line(w,w->xc->wellpixmap, w->xc->wellgc,0,        w->width,z,w->length,w->width,z);
    draw_line(w,w->xc->wellpixmap, w->xc->wellgc,0,        w->width,z,0,        0,       z);
  }
  
  for (x = 0; x <= w->length; x++) {
    draw_line(w,w->xc->wellpixmap, w->xc->wellgc,x,0,1,x,0,w->depth);
    draw_line(w,w->xc->wellpixmap, w->xc->wellgc,x,w->width,w->depth,x,w->width,1);
  }

  for (y = 0; y <= w->width; y++) {
    draw_line(w,w->xc->wellpixmap, w->xc->wellgc,0,y,1,0,y,w->depth);
    draw_line(w,w->xc->wellpixmap, w->xc->wellgc,w->length,y,w->depth,w->length,y,1);
  }

}

int check_zap_layer(Well *w)
{
  int found = 0, this;
  int x,y,z, zz;

  z = 0;
  while (z < w->depth) {
    this = 1;
    for (x = 0; x < w->length; x++)
      for (y = 0; y < w->width; y++)
	this = this && w->filled[x][y][z];
    if (this) {
      found++;

      score_layer(w->game, z);
      if(w->game->usecs > 100000) w->game->usecs -= 100000; 
      else w->game->usecs /= 2;
      for (zz = z; zz > 0; zz--)
	for (x = 0; x < w->length; x++)
	  for (y = 0; y < w->width; y++)
	    w->filled[x][y][zz] = w->filled[x][y][zz-1];
      for (x = 0; x < w->length; x++)
	for (y = 0; y < w->width; y++)
	  w->filled[x][y][0] = 0;
    } else z++;
  }

  if (found) {
    draw_well_all(w);
    w->game->emptydepth += found;
  } 
    
  return found;
}


void weld_block (Well *w, Block *b)
{
  int x, y, z, i,olddepth;

  olddepth = w->game->emptydepth;
  for (x = 0; x < b->object->length; x++)
    for (y = 0; y < b->object->width; y++)
      for (z = 0; z < b->object->depth; z++)
	w->filled[x+b->x][y+b->y][z+b->z] |= b->object->filled[x][y][z];

  erase_block(w,b); 
  if (!check_zap_layer(w)) {
    draw_well_bottom(w);
    redraw_well(w, b->min_x - 8, b->min_y - 8, 
		b->max_x - b->min_x + 16, b->max_y - b->min_y + 16);
  }
  i = w->game->emptydepth = new_depth(w);
  if(i != olddepth) {
    if (i > olddepth) {
      for(;i > olddepth  ; olddepth++) {
	clear_level_win(w->xc,olddepth);
	check_for_gfo(w->game);
      }
    } else {
      for(;i < olddepth; i++) {
	redraw_level_win(w->game, i);
      }
    }
  }
}

new_depth(Well *w)
{
  int x ,y ,z;
  for(z = 0; z < w->depth; z++) 
    for( x = 0; x < w->length ; x++) 
      for(y = 0; y < w->width; y++) 
	if(w->filled[x][y][z] ) return(z);
  return(z);
}
