#define OVERBOARD 2
#define NEWPIECE 0
#define PLACEFOUND 1
#define NOPLACE 0 

#define STEALMOVE 0
#define BUTTONPRESS 1
#define BUTTONRELEASE 2
#define MOTIONNOTIFY 3
#define PAUSEGAME 4
#define CONFIRMMOVE 5
#define CONFIRMED 6
#define DISAGREE 7
#define ASSERTTIME 8

#define SERVER 0
#define DAEMON 1
#define OPPONENT 2

#define thisboard(gnc) ((gnc & 2) == (game_and_color & 2))

#define putshort(x,y) temp = htons(y); bcopy(&temp, x, sizeof(u_short))
#define getshort(x,y)   bcopy(y, &temp, sizeof(u_short)); x = htons(temp)

#define putlong(x,y) templ = htonl(y); bcopy(&templ, x, sizeof(u_long))
#define getlong(x,y)    bcopy(y, &templ, sizeof(u_long)); x = htonl(templ)

#include "xbugchess.h"
#include "blackstip"
#include "cursor"
#include "wait"
#include "table.h"
#include "clocks.h"

#include "bitmaps/pawn_piece"
#include "bitmaps/rook_piece"
#include "bitmaps/knight_piece"
#include "bitmaps/bishop_piece"
#include "bitmaps/queen_piece"
#include "bitmaps/king_piece"
#include "bitmaps/qmutant_piece"


#include "bitmaps/pawn_out"
#include "bitmaps/rook_out"
#include "bitmaps/knight_out"
#include "bitmaps/bishop_out"
#include "bitmaps/queen_out"
#include "bitmaps/king_out"
#include "bitmaps/qmutant_out"

/* REMOVE WHEN COMPILING FULL GAME */
char mycolor,color=WHITE,opcolor;
char whoseturn=WHITE,whosegrabbing=WHITE;
Window window, rootwindow, ClockWindow();
Display *display;
GC gc, gc_white, gc_black,gc_outline, gc_piece[2];
XGCValues gcvalues,gcvals_black, gcvals_w_piece,gcvals_b_piece, gcvals_out;
XSizeHints size_hints;
unsigned int button;
XClassHint class_hints;
XFontStruct *font;
int screen;
XEvent xevent;
Pixmap icon_pixmap,cur_pix,piece_pix[8][2], wait_pix;
XButtonPressedEvent *buttonpressed;
Cursor curse,wait_cur;
int wascovered,eventfrom,jiggled= -1, gametype,timelimit=0;
int runningdaemon = 0, piecefixed = 0;
int beeped = 0;
Move *curmove;
int planes;
Table table;

int grab_x, grab_y,graboff_x, graboff_y,move,erased,newpiece;
int piecegrabbed=NOPIECE,clearwhich= -1,piececovered= -1, prepiececover;
int funkymove = 0 ,whichrook, rookx;
int attackx, attacky;


#define PORTNUM 2152
int sock,op_sock;
char opponent[50],color,*ophost,code, game_and_color;
char partner[50], partnerop[50];
char *name;

main(argc, argv)
int argc;
char *argv[];
{
  int dum = 0; 
  if (( name = rindex(argv[0], '/')) == 0) name = argv[0];
  else name++;

  setgametype(name);
  
  if(((gametype == BUGCHESS) || (gametype == SPEEDCHESS)) && (argc < 2) ) {
    puts("What is the time limit? (in minutes)");
    scanf("%d",&timelimit); 
    fflush(stdin);
    fflush(stdout);
  }

  if ((gametype == BUGCHESS) && !strcmp(argv[1] , "fuzzy-brownies")) timelimit = 3;
  if(argc==2) {
    while ((sock = call_socket(argv[1], PORTNUM)) == -1) {
      if(!dum) {
	fprintf(stderr, "cannot connect to game server %s retrying . . . \n",argv[1]);
	dum=1;
      }
      sleep(1);
    } 
  } else {
    runningdaemon = 1;
    switch(fork()) {
    case -1:
      perror("fork");
      exit(1);
    case 0:
      set_host_here();
      break;
    default:
      if (argc == 6) {
	execl(DAEMON_PROG, "daemon", argv[1], argv[2],argv[3], argv[4], argv[5], 0);
      } else {
	execl(DAEMON_PROG, "daemon", name,0);
      }
      perror("execl");
      exit(1);
    }
  }

  if ( !runningdaemon ) {
    puts("Connection established. . .");
    puts("Waiting for Daemon Demon to choose colors . . . ");
  }

  send_name();
  get_opponent();

  if (!runningdaemon) {
    switch(fork()) {
    case -1:
      perror("fork");
      exit(1);
    case 0:
      break;
    default:
      exit(0);
    }
  }

  play_game(argc,argv);

}

setgametype(name)
char  *name;
{
  if( !strcmp(name, "xspeedchess") ) { gametype = SPEEDCHESS; return; }
  if( !strcmp(name, "xchess") ) { gametype = BORING; return; }
  if( !strcmp(name, "xbugchess") ) { gametype = BUGCHESS; return; }
  gametype = SPEEDCHESS;
}


send_name()
{
  char me[50],hostname[80],buffer[2];
  
  strcpy(me,getenv("USER"));
  gethostname(hostname,80);
  strcat(me,"@");
  strcat(me,hostname);
  sprintf(buffer,"%c",(char)strlen(me));
  write_data(sock,buffer,1);
  write_data(sock,me,strlen(me));
  
  if(((gametype == BUGCHESS ) ||  ( gametype == SPEEDCHESS )) && (runningdaemon) ) {
    hostname[0] = timelimit; 
    write_data(sock,hostname,10);
  }
}

get_funky_and_briefed()
{
  char temp[50];
  read_data(sock,partner,50);
  read_data(sock,partnerop,50);
  printf("Your partner is: %s \n", partner);
  printf("Your partner's opponent is %s\n",partnerop);
}

get_opponent()
{
  char temp[10];
  read_data(sock,opponent,50);
  if(gametype == BUGCHESS)  get_funky_and_briefed();
  if (((gametype == BUGCHESS) || ( gametype == SPEEDCHESS)) && (!runningdaemon) ) {
    read_data(sock,temp, 10);
    timelimit = temp[0];
  }

  game_and_color=opponent[strlen(opponent)+1];
  ophost=index(opponent,'@')+1;
  if((color=(game_and_color & 1)) == WHITE) be_host();
  else be_client();

  printf("Your opponent is %s\n", opponent);

}

be_client()
{
  int counter;

  for(counter=0; counter< 50; counter++) {
    sleep(1);
    if(((op_sock=call_socket(ophost, PORTNUM+1)) == -1)) {
      if(counter>40) {
	perror("being_client");
	puts("Can not find host");
      }
    } else {
      return;
    }
  }
  if(counter==10) {
    fprintf(stderr,"Can not connect to opponent");
    exit(-1);
  }
}

be_host()
{
  int tryagain=0,opsock;

  if((opsock = establish((unsigned short)PORTNUM+1)) < 0 ) {
    perror("establish");
    exit(1);
  }

  do {
    if((op_sock = get_connection(opsock)) < 0) {
      if(errno==EINTR)
	tryagain=1;
      perror("accept");
      exit(1);
    }
  } while(tryagain);
		   
}

set_host_here()
{
  char hostname[80];
  int counter;

  gethostname(hostname,80);
  for(counter=0;counter < 10; counter++) {
      sleep(1);
      if((sock=call_socket(hostname,PORTNUM)) != -1) break;
  }
  
  if(counter==10) {
    fprintf(stderr,"couldnot latch to self\n");
    exit(-1);
  }

}


mesg2op(opcode, mesg)
char opcode, mesg;
{
  char buffer[10];
  
  buffer[0]=opcode;
  buffer[1]=mesg;
  tell_op(buffer);


}

tell_op(message)
char message[];
{
  write_data(op_sock,message,10);
}
	
tell_all(message)
char message[];
{
  char buf[20];
  
  buf[0]=game_and_color;
  bcopy(message, buf+1, 9);
  write_data(sock,buf,10);
}

mesg2all(opcode, ptr)
char opcode, *ptr;
{
  write_data(sock, &opcode, 1);
  write_data(sock, ptr,9);
}

announce_end(i)
int i;
{
  char temp[50];
  
  temp[1] =  END_OF_GAME;
  strcpy(&(temp[2]), getenv("USER"));
  temp[0] = i;
  write_data(sock, temp, 10);
}

play_game(argc,argv)
int argc;
char *argv[];
{
  struct timeval tm;
  int serversock;
  fd_set fdclient,fdbackup;
  int upcount=0;
  char *geo;

  if((display = XOpenDisplay(NULL)) == NULL) {
    fprintf(stderr, "cannot connect to X server %s \n", XDisplayName(NULL));
    exit(-1);
  }


  mycolor=game_and_color & 1;
  opcolor = (mycolor == WHITE) ? BLACK:WHITE;
  color=mycolor; /*(mycolor==BLACK) ? WHITE:BLACK; */

  screen = DefaultScreen(display);
  planes = CellsOfScreen(DefaultScreenOfDisplay(display)) - 1 ;
  rootwindow = RootWindow(display,screen);
  preset_sizehints();
  window=XCreateSimpleWindow(display,rootwindow,size_hints.x,size_hints.y,500,760,3,
		 BlackPixel(display,screen), WhitePixel(display,screen));

  setgcs();

  if ((font=XLoadQueryFont(display, "-adobe-times-bold-i-normal--24-240-75-75-p-128-iso8859-1"))==NULL) {
    fprintf(stderr,"can't load 9x15 font\n");
    exit(-1);
  }
  gcvalues.font = font->fid;
  gc = XCreateGC(display, rootwindow, GCFont, &gcvalues);

  icon_pixmap = XCreateBitmapFromData(display, window, rook_out_bits, 
				      rook_out_width, rook_out_height);

  setcursor();
  setup_piece_pix();
  setsizehints(argc, argv);

  TableInit(display, window, &table , timelimit, mycolor);
  init_pieces(&table, mycolor);
  if(gametype == BUGCHESS) {
    InformClockOfNames();
    ResizeClock(TableClock(&table));
    CDrawBoard(TableClock(&table));
  }
  curmove = InitMove();

  XSelectInput(display, window, ExposureMask | ButtonPressMask
	       | Button1MotionMask | ButtonReleaseMask |  KeyPressMask );

  XMapWindow(display,window);

  FD_ZERO(&fdclient);

  FD_SET(sock,&fdclient); /* to daemon */
  FD_SET(op_sock, &fdclient); /* to opponent */
  FD_SET((serversock=ConnectionNumber(display)), &fdclient); /* To server */
  
  tm.tv_sec=0;
  tm.tv_usec=200000;
 
  while(1){
    XFlush(display);
    fdbackup=fdclient;
    if (((gametype == BUGCHESS ) || (gametype == SPEEDCHESS))  
	&& !(upcount = ++upcount % 10)) 
      if ((update_clock(TableClock(&table)) == -1) && (gametype == BUGCHESS) && 
	  (whoseturn == mycolor))
	announce_end(0);
    switch(select(FD_SETSIZE, &fdbackup,0, 0, &tm)) {
    case 0:
      if((gametype == SPEEDCHESS ) || ( gametype == BUGCHESS))
	if ((update_clock(TableClock(&table)) == -1) && (gametype == BUGCHESS) && 
	    (whoseturn == mycolor))
	  announce_end(0);
      upcount = 0;
      break;
      
    case -1:
      perror("select");
      break;
 
    default:
      if(FD_ISSET(serversock, &fdbackup)) {
	XNextEvent(display, &xevent);
	whosegrabbing = mycolor;
	serverevent();
      } else if (FD_ISSET(sock, &fdbackup)) {
	msg_from_daemon();
      } else if (FD_ISSET(op_sock, &fdbackup)) {
	msg_from_op();
      }
      break;
    }
  }
}

InformClockOfNames()
{
  char temp;
  char *n[4];
  char me[] = "*** ME ***";
  n[game_and_color] = me;
  switch(game_and_color) {
  case 0:
    n[1] = opponent;
    n[2] = partnerop;
    n[3] = partner;
    break; 
    
  case 1:
    n[0] = opponent;
    n[2] = partner;
    n[3] = partnerop;
    break;

  case 2:
    n[0] = partnerop;
    n[1] = partner;
    n[3] = opponent;
    break;

  case 3:
    n[0] = partner;
    n[1] = partnerop;
    n[2] = opponent;
    break;
  }
  FillNames(n[0],n[1],n[2],n[3],TableClock(&table));
}

msg_from_daemon()
{
  char buffer[20];
  static int counter=0; 
  int t, c, whichtray;

  eventfrom = DAEMON;

  if(read_data(sock,buffer, 10) == 0 ) {
    if( counter++ >10) {
      fprintf(stderr,"SOMEBODY KILLED DE WABBIT\n");
      exit(-1) ;
    }
  } else counter = 0;

  switch (buffer[1]) {

  case PIECE_TAKEN_ANNOUNCE_BECAUSE_KEN_IS_A_SCHMUCK: 
    switch (buffer[2]) {
    case NEWPIECE:
      if ((gametype == BUGCHESS) && (thisboard(buffer[0]))) {
	if ((buffer[3] == KING) && (buffer[4] == mycolor)) {
	  puts("GAME OVER DUDE!  King Taken.");
	  announce_end(1);
	}
	return ; 
      }
      t = ( buffer[3] == QMUTANT ) ? PAWN : buffer[3] ;
      c = buffer[4];  /* color */
      whichtray = (c == mycolor) ? INMYTRAY : INOPTRAY;
      ResurrectPiece (&table , t, whichtray , buffer[4]);
    }
    break;
  case YELL:
    if((buffer[2] > 1) && ((buffer[0] + game_and_color) == 3)) XBell(display, 25);
    NewMessage(TableClock(&table),buffer[0], buffer[2]);
    break;
    
  case END_OF_GAME:
    if (beeped) return; 
    beeped = 1;
    game_over_dude(buffer);
    break; 
  }
}

game_over_dude(buffer)
char buffer[];
{
  Window end_window;
  int width1, len;
  XEvent endevent;
  char temp[30];
  char str1[] = "Like... the game is over, ok?";
  char str[2][20] = { " ran out of time.", 
		      " Lost his king!" };
  
  strcpy(temp, &buffer[2]);
  temp[8] = '\0';
  strcat(temp, str[buffer[0]]);
  width1 = XTextWidth(font, temp, len = strlen(temp));

  end_window = XCreateSimpleWindow(display, window, (500 - width1)/2, 40, width1+10, 
				   30, 5, BlackPixel(display,screen), 
				   WhitePixel(display, screen));

  XSelectInput(display, end_window, ExposureMask);
  
  XMapWindow(display, end_window);
  while(!XCheckTypedWindowEvent(display, end_window, Expose, &endevent));

  XDrawString(display, end_window, gc, 5, 25, temp, len);

  XFlush(display);
  pause_game();
  XBell(display, 100); 
  XBell(display, 50); 
  XBell(display, 10); 
  XBell(display, 50); 
}


	
msg_from_op()
{
  char message[11];
  u_short temp, sx, sy, sx1, sy1;
  int x, y,x1,y1;
  static int counter = 0; 

  eventfrom = OPPONENT;

  whosegrabbing=opcolor;
  if (read_data(op_sock, message,10) == 0 ) {
    if(counter++ > 10) {
      fprintf(stderr,"Opponent closed connection");
      exit(-1);
    }
  } else counter = 0;

  switch(message[0]) {
  case BUTTONPRESS:
    getshort (sx, message+2);
    getshort (sy, message+4);
    x = 499-sx;
    y = 759-sy;

    switch (message[1]) {
    case 1:
      grabpiece(x,y);
      return;

    case 2:
      pause_game();
    case 3:
      if(setpiece() && gametype != BORING) be_humble_and_accept_my_fate();
      return; 
    }

    break;
  case BUTTONRELEASE: 
    fixpieces();
    break;
  case MOTIONNOTIFY:
    mouse_moved2(message);
    break;

  case STEALMOVE:
     if((gametype == SPEEDCHESS ) || (gametype == BUGCHESS))
      toggle_clock(TableClock(&table));
    whoseturn = opcolor;
    XDefineCursor(display, window, wait_cur);
    piecegrabbed = NOPIECE;
    break;

  case PAUSEGAME:
    pause_game();
    break;

  case CONFIRMMOVE:
  case DISAGREE:
    break;

  default:
    break;
  }
}


serverevent()
{
  char buf[10],buffer[10];
  int lookupstring;
  u_short temp; 
  static int button1down = 0;
  
  eventfrom = SERVER;
  switch(xevent.type){
    case Expose:
    if (xevent.xexpose.window == window)  refresh(); 
    else 
      if((gametype == SPEEDCHESS ) || (gametype == BUGCHESS))
	Crefresh(&xevent,TableClock(&table));
    break;
    
  case ButtonPress:
    if(whosegrabbing != whoseturn ) {
      XBell(display, 100);
      return;
    }
    buttonpressed=(XButtonPressedEvent *)&xevent;
    
    buf[0]=BUTTONPRESS;
    
    putshort (buf+2, xevent.xbutton.x);
    putshort (buf+4, xevent.xbutton.y);
      
    if(buttonpressed->button == 1) { 
      button1down = 1;
      buf[1]=1;
      tell_op(buf);
      grabpiece(xevent.xbutton.x,xevent.xbutton.y);
    } else if ((buttonpressed->button == 3 ) && (button1down != 1)) {
      buf[1]=3;
      tell_op(buf);
      if(setpiece() && gametype != BORING) assert_time();
    }
    break;
    
  case ButtonRelease:
    if(whosegrabbing != whoseturn ) return;
    buttonpressed=(XButtonPressedEvent *)&xevent;
    if(buttonpressed->button == 1) {
      button1down = 0;
      mesg2op(BUTTONRELEASE,0);
      fixpieces();
    }
    break;
    
  case MotionNotify:
    if((whosegrabbing != whoseturn) || ( MoveStatus(curmove) == NOTGRABBED)) return;
    mouse_moved();
    break;
    
  case KeyPress:
    lookupstring =  XLookupString((XKeyEvent *)&xevent, buffer,2,  NULL, NULL);
    if (lookupstring == 1) {
      switch(buffer[0]) {
      case 19:
	break;
	XDefineCursor(display, window, curse);
	piecegrabbed = NOPIECE;
	whoseturn = mycolor;
	buf[0] = STEALMOVE;
	tell_op(buf);
	break;
	
      case  9:
	buf[0] = PAUSEGAME;
	tell_op(buf);
	pause_game();
	break;
	
      case 27:
	if(!beeped) return;
	close(op_sock);
	close(sock);
	exit(0);

      default:
	if(gametype == BUGCHESS) LookupKeystrokeMessage(buffer[0]);
      }
    }
    break;
  }
}

LookupKeystrokeMessage(key)
char key;
{
  static char Lookup[][3] = {"  ", "\r\r", "jk", "kS","yw","rb",
			       "p\r","n\r", "k\r", "b\r", "r\r", "q\r", "K\r", 
			       "pc", "kc", "nc", "bc", "rc","qc","Kc", "su",
			       "! ","!\r","!!",
			       "mp","mk","mn","mb","mq", 
			       "os","ym","no","y\r","y ","ok",
			       "st","go","op","? ","?\r",
			       "qt","oS","th",
			       "!1","!2","!3","!4","!5",
			       {NULL, NULL, NULL}};
  static char x = 0;
  char i=0;
  char buffer[10];
  if(x == 0) {
    x = key;
    return; 
  }
  while( Lookup[i][0] != NULL) {
    if((x == Lookup[i][0] ) && (key == Lookup[i][1])) {
      buffer[0] = YELL;
      buffer[1] = i;
      tell_all(buffer);
      x = 0;
      return;
    }
    i++;
  }
  if(Lookup[i][0] == NULL) {
    x = key;
  }
}

getgametype()
{
  return gametype;
}

be_humble_and_accept_my_fate()
{
  char buf[10];
  u_long templ;
  time_t tm;

  read_data(op_sock, buf, 10);
  if (buf[0] != ASSERTTIME) return;
  getlong(tm, buf+1);
  *optime(TableClock(&table)) = tm;
}

assert_time()
{
  char buf[10];
  u_long templ;
  time_t tm; 
  
  buf[0] = ASSERTTIME;
  tm = *mytime(TableClock(&table));
  putlong(buf+1, tm);
  write_data(op_sock, buf, 10);
}

CoverPiece(x,y)
int x,y;
{
  Piece *p;
  p = BoardXYPiece(&(TableBoard(&table)), x,y);
  MovePieceTakenPtr(curmove) = p;
  MovePieceTaken(curmove) = *p;
  PieceWhere(p) = COVERED;
}

RemoveCoveredPiece() /* Handle QMutants! */
{
  if (PieceType((MovePieceTakenPtr(curmove))) == QMUTANT) 
    PieceType(MovePieceTakenPtr(curmove)) = PAWN;
  PieceWhere(MovePieceTakenPtr(curmove)) = OFFBOARD;
}


Move2Alt(m,x,y)
int x,y;   
Move *m;
{
  Piece *p;
  p = MovePiecePtr(m);
  PieceWhere(p) = ALTERNATE;
  PieceAltX(p) = x;
  PieceAltY(p) = y;

  PropagatePiece(p);
}

MoveFinalize() /* Set Move up */
{
  Piece *p;
  p = MovePiecePtr(curmove);
  switch(PieceWhere(&MovePiece(curmove))) {
  case INMYTRAY:
    TrayXYPiece(&(TableMyTray(&table)), PieceBaseX(p), PieceBaseY(p)) = 0;
    break;
  
  case INOPTRAY:
    TrayXYPiece(&(TableOpTray(&table)), PieceBaseX(p), PieceBaseY(p)) = 0;
    break;
  }
  PieceMoveStatus(p) = 1;  /* Need to reset this if ever an undo */
  PieceLocation(p) = MoveToLoc(curmove);
  curmove = NewMove(curmove);
}

pause_game()
{
  if((gametype == SPEEDCHESS ) || (gametype == BUGCHESS))
    pause_clock(TableClock(&table));
}

setpiece()
{ 
  char mesg[10];
  int offy;

  if ( MoveStatus(curmove) != FIXED ) return 0;

  if (MovePieceTakenPtr(curmove) != 0) {

    RemoveCoveredPiece();

    /* Send piece to other board*/

    if(eventfrom == SERVER) {
      mesg[0]=PIECE_TAKEN_ANNOUNCE_BECAUSE_KEN_IS_A_SCHMUCK;
      mesg[1]=NEWPIECE;
      mesg[2]=PieceType(MovePieceTakenPtr(curmove));
      mesg[3]=opcolor;
      tell_all(mesg );
    }
  }

  FinalizeSpecialCases();

  MoveFinalize();

  offy = (whoseturn == mycolor) ? 621 : 131 ;
  XClearArea(display, window, 9, offy, 483, 8, False );

  whosegrabbing=(whoseturn= (whoseturn==WHITE) ? BLACK:WHITE);
  
  if((gametype == SPEEDCHESS ) || (gametype == BUGCHESS))
    toggle_clock(TableClock(&table));

  offy = (whoseturn == mycolor) ? 621 : 130 ;
  XFillRectangle(display, window, gc, 9, offy, 482, 9);

  if(whoseturn != mycolor) XDefineCursor(display, window, wait_cur);
  else 
    XDefineCursor(display, window, curse);

  return 1;
}



fixpieces()
{
  int  x, y, whichboard, legalstat,a;
  u_short temp;
  char msg[10];
  
  if ( MoveStatus(curmove) != GRABBED ) {
    msg[0] = DISAGREE;
    tell_op(msg);
    return;
  }
  MovePieceTakenPtr(curmove) = 0 ;
  putmoving_piece();

  if((whichboard = 
      (pixel2grid(MoveMouseCoordX(curmove), MoveMouseCoordY(curmove), &x, &y)))
     != ONBOARD) {
    legalstat = ILLEGAL;
  } else {
    legalstat = check_for_legal_move(&table, &MovePiece(curmove),
				     PieceBaseX(MovePiecePtr(curmove)),
				     PieceBaseY(MovePiecePtr(curmove)),
				     x,y,mycolor,whoseturn,&MoveSpecial(curmove));
  }

  if((legalstat == MYPIECE) || (legalstat == ILLEGAL)) {
    msg[0] = DISAGREE;
    tell_op(msg);
  } else {
    msg[0] = CONFIRMMOVE;
    putshort(msg+1, PieceBaseX(MovePiecePtr(curmove)));
    putshort(msg+3, x);
    putshort(msg+5, y);
    tell_op(msg);

    read_data(op_sock,msg, 10);
    switch(msg[0]) {
    case DISAGREE:
      legalstat = ILLEGAL;
      break;
      
    case CONFIRMMOVE:
      getshort(temp, msg+1);
      a = 7 - temp;
      if(a != PieceBaseX(MovePiecePtr(curmove))) legalstat = ILLEGAL;
      getshort(temp, msg+3);
      a = 7 - temp;
      if(a != x) legalstat = ILLEGAL;
      getshort(temp, msg+5);
      a = 7 - temp;
      if(a != y) legalstat = ILLEGAL;
    }
  }
  
  switch(legalstat){
  case MYPIECE:
  case ILLEGAL:
    PopBackMove();
    MoveStatus(curmove) = NOTGRABBED;
    return;
      
  case OPPIECE:
    CoverPiece(x,y);
    clearpiece(&(MovePieceTaken(curmove)));

  case EMPTY:
    Move2Alt(curmove,x,y);
    LocationX(MoveToLoc(curmove)) = x;
    LocationY(MoveToLoc(curmove)) = y;
    LocationWhere(MoveToLoc(curmove)) = ONBOARD;
    putpiece(MovePiecePtr(curmove));
    MoveStatus(curmove) = FIXED;
    if(SpecialType(&MoveSpecial(curmove)) != DULL) DealWithSpecialCase();
    break;
  }
}


mouse_moved()
{
  Window root, child;
  int root_x, root_y, pos_x, pos_y;
  unsigned int keys_buttons;
  char buf[10];
  u_short temp;

  if(MoveStatus(curmove) != GRABBED) {
    return;
  }

  while(XCheckMaskEvent(display, Button1MotionMask, &xevent));
  if(!XQueryPointer(display, xevent.xmotion.window,&root, 
		    &child, &root_x, &root_y, &pos_x, &pos_y, &keys_buttons)) {
    puts("Returning on bad XQUERYPOINTER");
    return;
  }

  buf[0]=MOTIONNOTIFY;
  putshort (buf+1, pos_x);
  putshort (buf+3, pos_y);
  tell_op(buf);

  MoveGrabbedPiece(curmove, pos_x,pos_y);
}

MoveGrabbedPiece(m, x, y)
int x,y;
Move *m;
{
  putmoving_piece();
  MovePixelX(m) += (x - MoveMouseCoordX(m) );
  MovePixelY(m) += (y - MoveMouseCoordY(m) );
  putmoving_piece();
  MoveMouseCoordX(m) = x;
  MoveMouseCoordY(m) = y;
}

mouse_moved2(buf)
char buf[];
{

  int  pos_x, pos_y;
  u_short sx,sy,temp;

  if(MoveStatus(curmove) != GRABBED) return;

  getshort (sx, buf+1);
  getshort (sy, buf+3);
  
  pos_x=499-sx;
  pos_y= 759-sy;
  
  MoveGrabbedPiece(curmove, pos_x,pos_y);
}


ClearAlt()
{
  int pix_x, pix_y,x,y;
  if(LocationWhere(MoveToLoc(curmove)) == 0 ) return ;
  
  grid2pixel(x=LocationX(MoveToLoc(curmove)), 
	     y=LocationY(MoveToLoc(curmove)),
	     &pix_x, &pix_y);
  
  if(grid_color(x,y) == BLACK) {
    XClearArea(display, window, pix_x, pix_y, 60,60,False);
    XFillRectangle(display, window, gc_black, pix_x,pix_y,61,61);
  } else {
    XClearArea(display, window, pix_x, pix_y, 60,60,False);
  }
  BoardXYPiece(&(TableBoard(&table)) , x,y ) = 0;
}

PopBackMove()
{
  bzero(&(MoveToLoc(curmove)) , sizeof(Location));
  *(MovePiecePtr(curmove)) = MovePiece(curmove);
  putpiece(MovePiecePtr(curmove));
  PropagatePiece(MovePiecePtr(curmove));
  MovePiecePtr(curmove) = 0;
}


DealWithSpecialCase()
{
  switch(SpecialType(&MoveSpecial(curmove))) {
  case CASTLE:
    CastleMeBaby();
    break;
  case SOMEFRENCHWORD:
    break;
  case PROMOTION:
    SpecialOldPiecePtr(&MoveSpecial(curmove)) = MovePiecePtr(curmove);
    PieceType(MovePiecePtr(curmove)) = QMUTANT;
    clearpiece(MovePiecePtr(curmove));
    putpiece(MovePiecePtr(curmove));
    break;
  }
}

CastleMeBaby()
{
  Piece *p;
  p = SpecialOldPiecePtr(&MoveSpecial(curmove));
  BoardXYPiece(&(TableBoard(&table)),
	       PieceBaseX(p),
	       PieceBaseY(p)) = 0;

  putpiece(p);
  p = &SpecialNewPiece(&MoveSpecial(curmove));
  clearpiece(&SpecialOldPiece(&MoveSpecial(curmove)));
}

RestoreSpecial()
{
  switch(SpecialType(&MoveSpecial(curmove))) {
  case CASTLE:
    TakeBackCastle();
    break;
  case SOMEFRENCHWORD:
    break;
  case PROMOTION:
    PieceType(SpecialOldPiecePtr(&MoveSpecial(curmove))) = PAWN;
    break;
  }
  SpecialType(&MoveSpecial(curmove)) = DULL;
}

TakeBackCastle()
{
  int pix_x, pix_y, x,y;
  Piece *p;
  p = &SpecialNewPiece(&MoveSpecial(curmove));
  clearpiece(p);
  BoardXYPiece(&(TableBoard(&table)), PieceBaseX(p), PieceBaseY(p)) = 0;	
  p = SpecialOldPiecePtr(&MoveSpecial(curmove));
  *p = SpecialOldPiece(&MoveSpecial(curmove));
  putpiece(p);
  PropagatePiece(p);
}

grabpiece(pix_x, pix_y)
int pix_x, pix_y;
{
  int x,y;
  Piece *p;
  int where, samepiece=0;
  
  if((where = pixel2grid(pix_x,pix_y, &x, &y)) == OFFBOARD) {
    if (MoveStatus(curmove) == GRABBED) MoveStatus(curmove) = NOTGRABBED;
    return;
  }

  if((where != ONBOARD) && (gametype != BUGCHESS)) {
    if (MoveStatus(curmove) == GRABBED) MoveStatus(curmove) = NOTGRABBED;
    return;
  }

  if((p = XY2Piece(&table, x,y, where)) == 0 ) {
    if (MoveStatus(curmove) == GRABBED) MoveStatus(curmove) = NOTGRABBED;
    return;
  }
  if(PieceColor(p) != whoseturn) return;
  if(MoveStatus(curmove) == FIXED) {
    if(PieceWhere(p) != ALTERNATE) {
      ClearAlt(); 
      PopBackMove();
    } else  {
      samepiece = 1;
      BoardXYPiece(&(TableBoard(&table)) , x, y ) = 0;
    }
  }

  if(SpecialType(&MoveSpecial(curmove)) != DULL) {
    RestoreSpecial();  /*** and clear special case ***/
  }

  LiftPiece(curmove, p,pix_x, pix_y, samepiece);
}

LiftPiece(m, p, mousex, mousey, samepiece)  /* Assumes grab piece has legal turn */
int mousex, mousey, samepiece;
Move *m;
Piece *p;
{
  int savestat;
  
  if(samepiece) savestat = PieceWhere(&(MovePiece(m))); /* in case of repicked piece */
  MoveStatus(m) = GRABBED;
  MovePiece(m) = *p;
  MovePiecePtr(m) = p;
  if(samepiece) PieceWhere(&(MovePiece(m))) = savestat;
  MoveFromLoc(m) = PieceLocation(p);
  MoveMouseCoordX(m) = mousex ;
  MoveMouseCoordY(m) = mousey ;
  bzero(&(MoveToLoc(m)), sizeof(Location)); 
  
  clearpiece(p);
  piece2pixel(p,&(MovePixelX(m)),&(MovePixelY(m)));

  switch(PieceWhere(p)) { 
  case ONBOARD:
    BoardXYPiece(&TableBoard(PieceTable(p)), PieceX(p), PieceY(p)) = 0;
    break; 
  }
/*  case INMYTRAY:
    TrayXYPiece(&(TableMyTray(PieceTable(p))), PieceX(p), PieceY(p)) = 0;
    break;
   
  case INOPTRAY:
    TrayXYPiece(&(TableOpTray(PieceTable(p))), PieceX(p), PieceY(p)) = 0;
    break;
  } */
  PieceWhere(p) = INYOURHAND;

  if (MovePieceTakenPtr(m) != 0) {
    *(MovePieceTakenPtr(m)) = MovePieceTaken(m);
    putpiece(MovePieceTakenPtr(m));
    PropagatePiece(MovePieceTakenPtr(m));
    MovePieceTakenPtr(m) = 0;
  } 

  if((TableWindow(PieceTable(p))) == 0) return;
  putmoving_piece(); 
}


refresh()
{
  Region region;
  XRectangle rectangle;
  int offy;

  region=XCreateRegion();

  do{
    rectangle.x = (short)xevent.xexpose.x;
    rectangle.y = (short)xevent.xexpose.y;
    rectangle.width=(unsigned short) xevent.xexpose.width;
    rectangle.height=(unsigned short) xevent.xexpose.height;
    XUnionRectWithRegion(&rectangle, region, region);
    
  } while (XCheckTypedWindowEvent(display,window, Expose, &xevent));
  XSetRegion(display, gc, region);
  XSetRegion(display, gc_black, region);
  XSetRegion(display, gc_outline, region);
  XSetRegion(display, gc_piece[0], region);
  XSetRegion(display, gc_piece[1], region);
  
  make_grid();
  XDrawRectangle(display, window, gc, 9, 9, 481, 121);
  XDrawRectangle(display, window, gc, 9, 628, 481, 125);

  offy = (whoseturn == mycolor) ? 621 : 130 ;
  
  XFillRectangle(display, window, gc, 9, offy, 482, 9);

  if ( MoveStatus(curmove) == GRABBED ) 
    putmoving_piece();

  DrawTablePieces(&table);

  XDestroyRegion(region);
  
  region = XCreateRegion();
  rectangle.x = (short)0;
  rectangle.y = (short)0;
  rectangle.width=(unsigned short)500;
  rectangle.height=(unsigned short)760;

  XUnionRectWithRegion(&rectangle, region, region);
  
  XSetRegion(display, gc, region);
  XSetRegion(display, gc_black, region);
  XSetRegion(display, gc_outline, region);
  XSetRegion(display, gc_piece[0], region);
  XSetRegion(display, gc_piece[1], region);
  
}


check_row_clear (t,x,y,nx,ny, turn, retpiece)
Piece *retpiece;
Table *t;
int x,y,nx,ny;
{
  int dx=0, dy=0;
  if (( nx - x ) < 0) dx = -1;
  if (( nx - x ) > 0 ) dx = 1; 

  if (( ny - y ) < 0) dy = -1;
  if (( ny - y ) > 0 ) dy = 1; 

  for ( x += dx, y += dy; (x != nx) || (y != ny); x += dx, y +=dy) {
    *retpiece = *(XY2Piece(t,x,y,ONBOARD));
    switch(check_for_clear_space(t, x,y, turn )) {
    case ILLEGAL:
      return EMPTY;
      
    case MYPIECE:
    case OPPIECE:
      return ILLEGAL;
    }
  }

  *retpiece = *(XY2Piece(t,x,y,ONBOARD));
  switch(check_for_clear_space(t, x,y, turn )) {
  case ILLEGAL:
  case EMPTY:
    return EMPTY;
    
  case MYPIECE:
    return MYPIECE;
  case OPPIECE:
    return OPPIECE;
  }
}

check_di_clear (t, x,y,nx,ny,turn, retpiece)
Piece *retpiece;
char turn;
Table *t;
int x,y,nx,ny;
{
  int dx = 1, dy = 1;
  if ((nx - x) < 0) dx = -1;
  if ((ny - y ) < 0 ) dy = -1;

  for ( x += dx, y += dy; (x != nx) || (y != ny); x += dx, y +=dy) {
    if ((x == 8) || (x == -1) || (y == 8) || (y == -1)) return EMPTY;
    *retpiece = *(XY2Piece(t,x,y,ONBOARD));
    switch(check_for_clear_space(t, x,y, turn )) {
    case ILLEGAL:
      return EMPTY;
      
    case MYPIECE:
    case OPPIECE:
      return ILLEGAL;
    }
  }
  
  *retpiece = *(XY2Piece(t,x,y,ONBOARD));
  switch(check_for_clear_space(t, x,y, turn )) {
  case ILLEGAL:
  case EMPTY:
    return EMPTY;
    
  case MYPIECE:
    return MYPIECE;
  case OPPIECE:
    return OPPIECE;
  }
}

knightat(b,x,y)
Board *b;
int x,y;
{
  Piece *p;
  if(x < 0 || x > 7 || y < 0 || y > 7) return 0;
  if ((p = BoardXYPiece(b, x,y)) == 0) return 0;
  if ((PieceType(p) == KNIGHT) &&( PieceColor(p) != whoseturn))  {
    return 1;
  } 
  else return 0;
}

clearpiece(p)
Piece *p;
{
  int pix_x, pix_y;

  if((PieceWhere(p) == INOPTRAY) ||( PieceWhere(p) == INMYTRAY)) {
    tray2pixel(PieceWhere(p),PieceX(p),PieceY(p), &pix_x,&pix_y);
    XClearArea(display, window, pix_x, pix_y, 60, 60 , False);
    return;
  }

  grid2pixel(PieceX(p),PieceY(p),&pix_x, &pix_y);

  if(grid_color(PieceX(p),PieceY(p)) == BLACK) {
    XFillRectangle(display, window, gc_black, pix_x,pix_y,61,61);
  } else {
    XClearArea(display, window, pix_x, pix_y, 60,60,False);
  }
}

make_grid()
{
  int x, y, pix_x, pix_y;
  
  XDrawRectangle(display, window, gc, 9, 139,481, 481);
  for(x = 0; x < 8; x++) {
    for ( y = 0; y < 8; y++ ) {
      if(grid_color(x,y)==BLACK) {
	grid2pixel(x,y,&pix_x, &pix_y);
	XFillRectangle(display, window, gc_black, pix_x,pix_y,61,61);
      }
    }
  }
}


grid_color(x,y)
int x, y;
{
  if(( x < 0 ) || (x > 7) || ( y < 0 ) || ( y > 7) ) return (WHITE);
  if((x+y) & 1) {
    return(BLACK);
  } else {
    return(WHITE);
  }
}
preset_sizehints()
{
  int retval=0;
  XrmValue v;
  Bool resret;
  char strname[80], strclass[] = "XBugchess.Window.Geometry";
  char *strtype[20];

  strcpy(strname, name);
  strcat(strname, ".board.geometry");
  size_hints.x = size_hints.y = 0;
  if(resret = XrmGetResource(XrmGetStringDatabase(XResourceManagerString(display)), 
			     strname, strclass, strtype, &v)) {
    retval = XParseGeometry(v.addr, &size_hints.x, &size_hints.y, NULL, NULL);
    if (retval & XNegative) size_hints.x = DisplayWidth(display, 0) - size_hints.x - 500;
    if (retval & YNegative) size_hints.y = DisplayHeight(display, 0) - size_hints.y - 760;
  }

  size_hints.width = 500;
  size_hints.height = 760;
  size_hints.min_width = 500;
  size_hints.min_height = 760;
  size_hints.flags = USSize|PMinSize;

  if ((retval & XValue ) || (retval & YValue)) {
    size_hints.flags |= USPosition;
  }
}

setsizehints(argc, argv)
int argc;
char *argv[];
{

  static char n[] = "xbugchess", class[] = "XBugchess";

  class_hints.res_name = n;
  class_hints.res_class = class;

  XSetClassHint(display,window,&class_hints);
  XStoreName(display,window, "XBugChess");
  XSetIconName(display, window, "XBugChess");

  XSetStandardProperties(display, window, class, class, icon_pixmap, argv,argc, &size_hints);

}



setcursor()
{

  XColor foreground, background;

  foreground.pixel = BlackPixel(display,screen);
  background.pixel = WhitePixel(display,screen);
  XQueryColor(display, DefaultColormap(display, DefaultScreen(display)), &foreground);
  XQueryColor(display, DefaultColormap(display, DefaultScreen(display)), &background);

  cur_pix = XCreateBitmapFromData(display, window, cursor_bits, 
				  cursor_width, cursor_height);

  curse=XCreatePixmapCursor(display, cur_pix, cur_pix, 
			    &foreground,
			    &background,
			    (unsigned int)cursor_width/2,
			    (unsigned int)cursor_height/3);

#ifdef DEBUG
  puts("test1");
#endif
  wait_pix = XCreateBitmapFromData(display, window, wait_bits, 
				   wait_width, wait_height);
#ifdef DEBUG
  puts("test2");
#endif
  wait_cur = XCreatePixmapCursor(display, wait_pix, wait_pix, 
			     &foreground, &background,
			     (unsigned int)wait_width/2,
			     (unsigned int)wait_height/3);

  if(mycolor==BLACK) XDefineCursor(display, window, wait_cur);
  else XDefineCursor(display, window, curse);

}



setgcs()
{
  if((gcvals_black.stipple = XCreateBitmapFromData(display, window, blackstip_bits, 
						   blackstip_width, blackstip_height))
     == NULL)
    fprintf(stderr,"Couldn''t show internal pixmap\n");
  
  gcvals_black.fill_style=FillOpaqueStippled;
  gcvals_black.foreground=BlackPixel(display,screen);
  gcvals_black.background=WhitePixel(display,screen);
  gc_black = XCreateGC(display,  window, (GCFillStyle|GCStipple|GCForeground|GCBackground),
		       &gcvals_black);
  
  
  gcvals_b_piece.function = GXandInverted;
  gcvals_w_piece.function = GXor;
  gcvals_out.function = GXxor;

  gc_piece[BLACK] = XCreateGC(display, window, (GCFunction), &gcvals_b_piece);
  gc_piece[WHITE] = XCreateGC(display, window, (GCFunction), &gcvals_w_piece); 
  gc_outline = XCreateGC(display, window, (GCFunction), &gcvals_out);
  
}

setup_piece_pix()
{
  piece_pix[PAWN][0]=XCreateBitmapFromData(display, window, pawn_piece_bits,
					   pawn_piece_width, pawn_piece_height);
  piece_pix[ROOK][0]=XCreateBitmapFromData(display, window, rook_piece_bits,
					   rook_piece_width, rook_piece_height);
  piece_pix[KNIGHT][0]=XCreateBitmapFromData(display, window, knight_piece_bits,
					     knight_piece_width, knight_piece_height);
  piece_pix[BISHOP][0]=XCreateBitmapFromData(display, window, bishop_piece_bits,
					     bishop_piece_width, bishop_piece_height);
  piece_pix[QUEEN][0]=XCreateBitmapFromData(display, window, queen_piece_bits,
					    queen_piece_width, queen_piece_height);
  piece_pix[KING][0]=XCreateBitmapFromData(display, window, king_piece_bits,
					   king_piece_width, king_piece_height);
  piece_pix[QMUTANT][0]=XCreateBitmapFromData(display, window, qmutant_piece_bits,
					   qmutant_piece_width, qmutant_piece_height);

  piece_pix[PAWN][1]=XCreateBitmapFromData(display, window, pawn_out_bits,
					   pawn_out_width, pawn_out_height);
  piece_pix[ROOK][1]=XCreateBitmapFromData(display, window, rook_out_bits,
					   rook_out_width, rook_out_height);
  piece_pix[KNIGHT][1]=XCreateBitmapFromData(display, window, knight_out_bits,
					     knight_out_width, knight_out_height);
  piece_pix[BISHOP][1]=XCreateBitmapFromData(display, window, bishop_out_bits,
					     bishop_out_width, bishop_out_height);
  piece_pix[QUEEN][1]=XCreateBitmapFromData(display, window, queen_out_bits,
					    queen_out_width, queen_out_height);
  piece_pix[KING][1]=XCreateBitmapFromData(display, window, king_out_bits,
					   king_out_width, king_out_height);
  piece_pix[QMUTANT][1]=XCreateBitmapFromData(display, window, qmutant_out_bits,
					   qmutant_out_width, qmutant_out_height);
}


putpiece_onboard(p)
Piece *p;
{
  int x, y;

  grid2pixel(PieceX(p), PieceY(p), &x, &y);
#ifdef DEBUG
  puts("5");
#endif
  if(planes == 1) 
  XCopyArea(display, piece_pix[PieceType(p)][0],
	    window, gc_piece[PieceColor(p)], 0,0,50,50,x+5,5+y);
  else 
  XCopyPlane(display, piece_pix[PieceType(p)][0],
	    window, gc_piece[PieceColor(p)], 0,0,50,50,x+5,5+y,1);
#ifdef DEBUG
  puts("6");
#endif
  if(planes == 1) 
  XCopyArea(display, piece_pix[PieceType(p)][1],
	    window, gc_outline, 0,0,50,50,5+x,5+y);
  else 
  XCopyPlane(display, piece_pix[PieceType(p)][1],
	    window, gc_outline, 0,0,50,50,5+x,5+y,1);
}

putalt_onboard(p)
Piece *p;
{
  int x, y;

  grid2pixel(PieceAltX(p), PieceAltY(p), &x, &y);
#ifdef DEBUG
  puts("5");
#endif
  if(planes == 1) 
  XCopyArea(display, piece_pix[PieceType(p)][0],
	    window, gc_piece[PieceColor(p)], 0,0,50,50,x+5,5+y);
  else 
  XCopyPlane(display, piece_pix[PieceType(p)][0],
	    window, gc_piece[PieceColor(p)], 0,0,50,50,x+5,5+y,1);
#ifdef DEBUG
  puts("6");
#endif
  if(planes == 1) 
  XCopyArea(display, piece_pix[PieceType(p)][1],
	    window, gc_outline, 0,0,50,50,5+x,5+y);
  else 
  XCopyPlane(display, piece_pix[PieceType(p)][1],
	    window, gc_outline, 0,0,50,50,5+x,5+y,1);
}

putpiece_intray(p)
Piece *p;
{
  int x, y;

  tray2pixel(PieceWhere(p),PieceX(p), PieceY(p), &x, &y);
#ifdef DEBUG
  puts("7");
#endif
  if(planes == 1) 
  XCopyArea(display, piece_pix[PieceType(p)][0],
	    window, gc_piece[PieceColor(p)], 0,0,50,50,x+5,5+y);
  else 
  XCopyPlane(display, piece_pix[PieceType(p)][0],
	    window, gc_piece[PieceColor(p)], 0,0,50,50,x+5,5+y,1);
#ifdef DEBUG
  puts("8");
#endif
  if(planes == 1) 
  XCopyArea(display, piece_pix[PieceType(p)][1],
	    window, gc_outline, 0,0,50,50,5+x,5+y);
  else 
  XCopyPlane(display, piece_pix[PieceType(p)][1],
	    window, gc_outline, 0,0,50,50,5+x,5+y,1);

}

putmoving_piece()
{
  if (MoveStatus(curmove) == NOTGRABBED) return;
  if(planes == 1) 
  XCopyArea(display, piece_pix[PieceType(&(MovePiece(curmove)))][1], window, 
	    gc_outline, 0,0,50,50,MovePixelX(curmove)+5, MovePixelY(curmove)+5);
  else 
  XCopyPlane(display, piece_pix[PieceType(&(MovePiece(curmove)))][1], window, 
	    gc_outline, 0,0,50,50,MovePixelX(curmove)+5, MovePixelY(curmove)+5,1);
}

FinalizeSpecialCases()
{
  switch(  SpecialType(&MoveSpecial(curmove))) {
  case CASTLE:
    *SpecialOldPiecePtr(&MoveSpecial(curmove)) = SpecialNewPiece(&MoveSpecial(curmove));
    PropagatePiece(SpecialOldPiecePtr(&MoveSpecial(curmove)));
    break;
  case SOMEFRENCHWORD:
    break;
  case PROMOTION: 
    break;
  }
  SpecialType(&MoveSpecial(curmove)) = DULL;
}

dumppiece(p)
     Piece *p;
{
  printf("type = %d\n ", PieceType(p));
  printf("color = %d \n", PieceColor(p));
  printf("(x,y) = (%d,%d)\n", PieceX(p), PieceY(p));
} 

getplanes()
{
  return(planes);
}
