/***********************************************************************
 * 
 *  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"

Game *begin_game(XC *xc)
{
  Game *g;
  XWindowAttributes xwa;

  srandom(time(0));

  g = (Game *) malloc(sizeof(Game));
  bzero(g,sizeof(Game));
  g->well = (Well *) malloc(sizeof(Well));
  g->well->game = g;
  g->score = 0;
  g->faces = 0;
  g->round = 0;
  g->block = NULL;
  g->xc = xc;
  g->kd = (Keydef *) malloc(sizeof(Keydef));
  g->kd->up = 'w';
  g->kd->down = 's';
  g->kd->right = 'd';
  g->kd->left = 'a';
  g->kd->rotate1 = 'j';
  g->kd->rotate2 = 'k';
  g->kd->rotate3 = 'l';
  g->kd->drop = ' ';
  g->kd->upright = 'e';
  g->kd->upleft = 'q';
  g->kd->downright = 'c'; 
  g->kd->downleft = 'z';
  XGetWindowAttributes(xc->dsp, xc->mwin, &xwa);
  g->started = (xwa.map_state == IsViewable);
  GetResourceKeydefs(g);
  return g;
}

int end_game(Game *g)		/* returns score */
{
  int sc;
  
  if (g->well)
    free(g->well);
  if (g->block)
    free_block(g,g->block);
  sc = g->score;
  free(g);
  return sc;
}

void begin_round (Game *g)
{
  g->round++;
  bzero(g->well, sizeof(Well));
  g->well->xc = g->xc;
  g->well->game = g;
  configure_well (g);
  g->emptydepth = g->well->depth;
  resize_well(g->well);
  make_level_stack(g);
  if (g->block) {
    free(g->block);
    g->block = NULL;
  }
}

void handle_configure(Game *g,XC *xc, int width, int height)
{
  configure(xc, width, height);
  resize_well(g->well);
  draw_well_all(g->well);
  resize_score(g);
  resize_level_stack(g);
  if(xc->endwin) {
    mutilate_end_window(xc);
    make_end_window(xc);
  }
}

void handle_button (int x, int y, int button, int pressed)
/*#pragma ignore(x,y,button,pressed)*/
{
}

void handle_inout (int entered,Game *g)
/*#pragma ignore(entered)*/ 
{
  if(!entered) 
    wait_for_focus(g); 
}

int try_move_block (Well *w, Block *b, 
		     int dx, int dy, int dz)
{
  int bc;

  b->x += dx;
  b->y += dy;
  b->z += dz;
  bc = block_collide(w,b);
  b->x -= dx;
  b->y -= dy;
  b->z -= dz;
  if (!bc) {
    erase_block(w,b);
    b->x += dx;
    b->y += dy;
    b->z += dz;
    draw_block(w,b);
  } 
  return(!bc);
}

void handle_end_key(char key, Game *g)
{
  if ( key == 3) { 
    exit(0);
  } else if(key == 13) {
     g->started = 0;
  }
}

void handle_key(char key, Game *g)
{
  if ( key == g->kd->up) {
    try_move_block(g->well,g->block,0,-1,0);
  } else if ( key == g->kd->down) {
    try_move_block(g->well,g->block,0,1,0);
  } else if ( key == g->kd->right) { 
    try_move_block(g->well,g->block,1,0,0);
  } else if ( key == g->kd->left) {
    try_move_block(g->well,g->block,-1,0,0);
  } else if ( key == g->kd->rotate1 ) { 
    try_Rotate(g->well, g->block, RotateForward);
  } else if ( key == g->kd->rotate2 ) {
    try_Rotate(g->well, g->block, RotateCClock);
  } else if ( key == g->kd->rotate3 ) {
    try_Rotate(g->well, g->block, RotateRight);
  } else if ( key == g->kd->drop ){
    DropBlock(g);
  } else if ( key == g->kd->upright ) { 
    try_move_block(g->well, g->block,1,-1,0); 
  } else if ( key == g->kd->upleft ) { 
    try_move_block(g->well, g->block,-1,-1,0); 
  } else if ( key == g->kd->downright ) { 
    try_move_block(g->well, g->block,1,1,0); 
  } else if ( key == g->kd->downleft ) { 
    try_move_block(g->well, g->block,-1,1,0); 
  } else if ( key == 9) {
    pause_game(g);
  } else if ( key == 'r' ) {
    draw_well(g->well);
  } else if ( key == 3) {
    exit(0);
  }
}

DropBlock(Game *g) 
{
  while (try_move_block(g->well, g->block, 0, 0, 1));
}


void handle_refresh (Game *g, int x, int y, int width, int height)
{
  g->started = 1;

  redraw_well(g->well, x, y, width, height);

  if (g->block)
    draw_block(g->well, g->block);
}



void new_block (Game *g);
void handle_score_refresh(Game *g, int x, int y, int width, int height);

void game_loop(Game *g)
{
  configure_well(g);
  draw_well_all(g->well);
  handle_score_refresh(g, 0,0,200, 200);
  do {
    if (!g->block)
      new_block(g);

    x_event_loop(handle_button, handle_inout, handle_key, handle_configure,
		 handle_refresh,
		 handle_score_refresh,
		 g->xc, g->usecs, g);

    if (g->started) {
      if (!advance_block(g->well, g->block)) {
	weld_block(g->well, g->block);
	score_block(g,g->block);
	free(g->block);
	g->block = NULL;
	if (g->faces >= g->faces_required) {
	  g->faces = 0;
	  g->score += 100; 
	  new_round_message(g);
/* THIS IS AWEFUL!!! KILL IT! */
	  begin_round(g);
	  draw_well_all(g->well);
	}
      }
    }
  } while (!game_over_dude(g));
  if(is_high(g->score)) add_high(getenv("USER"), getenv("USER"), g->score, g->round);
  make_end_window(g->well->xc);
  while(g->started) {
    x_event_loop(NULL,NULL,handle_end_key,handle_configure,
		 handle_refresh,
		 handle_score_refresh,
		 g->well->xc, 100000, (struct t_Game *) g);
  }
  mutilate_end_window(g->well->xc);
  bzero(g->well->filled, sizeof (g->well->filled));
  g->round = 1;
}

int game_over_dude(Game *g)
{
  int x, y;

  for (x = 0; x < g->well->length; x++)
    for (y = 0; y < g->well->width; y++)
      if (g->well->filled[x][y][1])
	return 1;
  return 0;
}

void new_block (Game *g)
{
  int block_num;

  if (g->block)
    free_block(g,g->block);
  g->block = (Block *) malloc(sizeof(Block));
  g->block->object = (Object *) malloc(sizeof(Object));
  do
    block_num = random() % 12;
  while (((1 << block_num) & g->well->valid_blocks) == 0);
  make_object(g->block->object, block_num);
  g->block->z = 1;
  g->block->x = 0;
  g->block->y = 0;
  XSync(g->xc->dsp, 0); /* waits for new stuff and everything to be cleared*/
  draw_block(g->well,g->block);

}

free_block(Game *g, Block *b)
{
  if (b) {
    free(b);
  }
}

check_for_gfo(Game *g)
{
  static int counter=0;
  static char message[][30] = {"B-b-b-b-gfo dude","Eat my shorts, man","Well looky here"};
  counter ++; counter %= 3;
  if(g->emptydepth == g->well->depth) show_gfo(g, message[counter]); 
}


new_round_message(Game *g) 
{
  static int counter = 0;
  static char message[][30] = {"HEY! You're cheating", "Aw man.. must be a bug","Looky them GFO's", "Limey Marc, dude"};
  counter ++; counter %= 3;
  
  ClearMainWin(g->xc);
  show_dudely_face(g, message[counter]);
}
