/* 
  Copyright 1991 Mario Goertzel and Matthew Sorrels
 
  Permission to use, copy, modify, distribute, and sell this software and its
  documentation for any purpose is hereby granted without fee, provided that
  the above copyright notice appear in all copies and that both that
  copyright notice and this permission notice appear in supporting
  documentation, and that the name of the author not be used in advertising or
  publicity pertaining to distribution of the software without specific,
  written prior permission.  The authors make no representations about the
  suitability of this software for any purpose.  It is provided "as is"
  without express or implied warranty.
 
  MARIO GOERTZEL AND MATTHEW SORRELS DISCLAIMS ALL WARRANTIES WITH 
  REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF 
  MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL MATTHEW SORRELS BE 
  LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY 
  DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 
  WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 
  ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
  Authors:  Mario Goertzel and Matthew Sorrels
*/
/*
 * Capture The Flag
 *
 * Mario Goertzel <mg2p+@andrew.cmu.edu>
 * Matthew Sorrels <ms90+@andrew.cmu.edu>
 *
 * May 11, 1991
 */
#include <stdio.h>
#include <strings.h>
#include <ctype.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/time.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/cursorfont.h>
#include "capture.h"
#include "CaptureIcon.xbm"

extern struct Board mainBoard;
extern struct Piece pieces1[15];
extern struct Piece pieces2[15];
extern char *pieceNames[];

#define PIECES 40
extern int pieceCount[];

extern int finalwinner;
extern int turnnum;
extern int turn;
extern int setup1;
extern int setup2;

extern char *StatusText[2];
extern char *Player1Text;
extern char *Player2Text;
extern int TextSize[2];

extern Display *Display1, *Display2;
extern int Screen1, Screen2;
extern int Depth1, Depth2;
extern Colormap Colormap1, Colormap2;
extern unsigned long BackColor1, BackColor2;
extern unsigned long ForeColor1, ForeColor2;
extern unsigned long PieceColor1, PieceColor2;
extern unsigned long OppColor1, OppColor2;

extern Window wind1, wind2;
extern Window board1, board2;
extern Window status1, status2;
extern Window talk1, talk2;
extern Window otherTalk1, otherTalk2;
extern GC draw1, draw2, erase1, erase2, xor1, xor2, invert1, invert2;  
extern XFontStruct *font1, *font2;
extern Cursor cursor1, cursor2;
extern char *BaseDir;
extern char *FontName;
extern int textwidth1, textwidth2;
extern int textheight1, textheight2;
extern int BorderWidth;

extern int Isinvert1, Isinvert2;
extern int InvertI1, InvertJ1;
extern int InvertI2, InvertJ2;

#define SLEEP 50000
#define EVENT_MASK (ButtonPressMask|ButtonReleaseMask|ExposureMask|KeyReleaseMask|StructureNotifyMask|SubstructureNotifyMask)

void uwait(seconds, useconds)
int seconds, 
useconds;
{
  struct timeval tv;
  tv.tv_sec = seconds;
  tv.tv_usec = useconds;

  select(NULL, NULL, NULL, NULL, &tv);
}

void MakeMove(player, i, j) 
int player, i, j; 
{
  int i1, j1;

  if (player == 1)  {
    i1 = InvertI1;
    j1 = InvertJ1;
    InvertPiece(player, i1, j1);
  } else {
    i1 = InvertI2;
    j1 = InvertJ2;
    InvertPiece(player, i1, j1);
  }
  switch (ValidateMove(player, i1, j1, i, j)) {
  case VALID:
    AnimatePiece(i1, j1, i, j);
    break;
  case STRIKE:
    Strike(i1, j1, i, j);
    if (finalwinner) {
      RedrawBoard(1);
      RedrawBoard(2);
      Victory(finalwinner);
    }
    break;
  default:
    return;
    break;
  }
  NextPlayerToMove();
}

void BoardClick(player, x, y)
int player, x, y;     
{
  x = x/60;
  y = y/60;
  if ((Isinvert1 && (player == 1)) || (Isinvert2 && (player == 2))) {
    if (turn) {
      MakeMove(player, x, y);
    } else {
      if (mainBoard.location[x][y].status != player) return;
      ExchangePieces(player, x, y);
    }
  } else {
    if (((player == 1) ? setup1 : setup2) || (player == turn))
      InvertPiece(player, x, y);
  }
}

NextPlayerToMove()
{
  turnnum++;
  if (turn == 1) {
    turn = 2;
    sprintf(StatusText[0],
	    "Your opponent's generals are planning an attack!        <Turn %d>",turnnum);
    sprintf(StatusText[1],
	   "Select your next deadly move!                            <Turn %d>",turnnum);
    DrawTextBox(0,1);
  } else {
    turn = 1;
    sprintf(StatusText[1],
	    "Your opponent's generals are planning an attack!        <Turn %d>",turnnum);
    sprintf(StatusText[0],
	   "Select your next deadly move!                            <Turn %d>",turnnum);
    DrawTextBox(0,1);
  }
  if (NoMoves(turn)) {
    finalwinner = (turn == 1) ? 2 : 1;
    RedrawBoard(1);
    RedrawBoard(2);
    Victory(finalwinner);
  }
}

SetupDone(player)
int player;
{
  if (setup1 || setup2) {
    if (player == 2) {
      strcpy(StatusText[0], "Your opponent is ready for battle!            <Click here when done>");
      strcpy(StatusText[1], "Waiting for your opponents generals to get out of the shower!");
    } else {
      strcpy(StatusText[1], "Your opponent is ready for battle!            <Click here when done>");      
      strcpy(StatusText[0], "Waiting for your opponents generals to get out of the shower!");
    }
    DrawTextBox(0,1);
  } else {
    XBell(Display1, 25);
    if (Isinvert1) InvertPiece(1, InvertI1, InvertJ1);
    XBell(Display2, 25);
    if (Isinvert2) InvertPiece(2, InvertI2, InvertJ2);
    turn = 2; /* Player to move flips it */
    NextPlayerToMove();
  }
}

void HandleKeyPress(win, player, buf, n)
Window win;
int player;
char *buf;
int n;
{
  int box;
  int i;
  int clear = 1;
  char *tmp;
  if (n == 0) return;

  if (player == 1) {
    box = 1;
    tmp = Player1Text;
  } else {
    box = 2;
    tmp = Player2Text;
  }
  if ((buf[n-1] == '\012') || (buf[n-1] == '\015') || (buf[n-1] == '\025')) { 
    /* new line */
    *tmp = '\0';
  } else if ((buf[n-1] == '\177') || (buf[n-1] == '\010')) {
    /* delete */
    i = strlen(tmp);
    i--;
    if (i >= 0) tmp[i] = '\0';
  } else if (isprint(buf[n-1])) {
    if (strlen(tmp)+n > TextSize[box-1]) return;
    strcat(tmp,buf);
    clear = 0;
  } else return;

  DrawTextBox(box, clear);
  return;
}

void NewGame() 
{
  setup1 = 1;
  setup2 = 1;
  turn = 0;
  turnnum = 0;
  finalwinner = 0;
  Isinvert1 = 0;
  Isinvert2 = 0;
  strcpy(StatusText[0], "Player 1 prepare your army for battle!        <Click here when done>");
  strcpy(StatusText[1], "Player 2 prepare your army for battle!        <Click here when done>");
  DrawTextBox(0,1);
  InitBoard();
  XClearWindow(Display1, board1);
  XClearWindow(Display1, status1);
  XClearWindow(Display1, talk1);
  XClearWindow(Display1, otherTalk1);
  XClearWindow(Display2, board2);
  XClearWindow(Display2, status2);
  XClearWindow(Display2, talk2);
  XClearWindow(Display2, otherTalk2);
  RedrawBoard(1);
  RedrawBoard(2);
}

DoEvents()
{
  int i, done = 0;
  XEvent event;
  XButtonEvent *bevent;
  XKeyReleasedEvent *kevent;
  int player;
  Display *disp;
  KeySym key;
  extern RedrawBoard(), InitBoard();
  char buf[10];

  XSelectInput(Display1, wind1, EVENT_MASK);
  XSelectInput(Display1, board1, EVENT_MASK);
  XSelectInput(Display1, status1, EVENT_MASK);
  XSelectInput(Display1, talk1, EVENT_MASK);
  XSelectInput(Display1, otherTalk1, EVENT_MASK);
  XSelectInput(Display2, wind2, EVENT_MASK);
  XSelectInput(Display2, board2, EVENT_MASK);
  XSelectInput(Display2, status2, EVENT_MASK);
  XSelectInput(Display2, talk2, EVENT_MASK);
  XSelectInput(Display2, otherTalk2, EVENT_MASK);

  NewGame();

  while(!done)
    {
      if (XPending(Display1)) {
	XNextEvent(Display1, &event);
	player = 1;
	disp = Display1;
      } else if (XPending(Display2)) {
	XNextEvent(Display2, &event);
	player = 2;
	disp = Display2;
      } else {
	uwait(0,SLEEP);
	continue;
      }
      switch(event.type) {
      case Expose:
	while(XCheckTypedEvent(disp, Expose, &event))
	  ;
	RedrawBoard(player);
	break;
      case DestroyNotify:
	done=1;
	break;
      case ConfigureNotify:
	break;
      case KeyRelease:
	kevent = (XKeyReleasedEvent *)&event;
	i = XLookupString(kevent, buf, 10, &key, 0);
	if (((kevent->window == board1) || (kevent->window == board2)) && i == 1 && buf[0] == '\021') {
	  done = 1;
	  break;
	}
	if (((kevent->window == board1) || (kevent->window == board2)) && i == 1 && buf[0] == '\016') {
	  NewGame();
	  break;
	}
	if ((kevent->window == board1) && i == 1 && buf[0] == '\014') {
	  XClearWindow(Display1, board1);
	  XClearWindow(Display1, status1);
	  XClearWindow(Display1, talk1);
	  XClearWindow(Display1, otherTalk1);
	  RedrawBoard(1);
	  break;
	}
	if ((kevent->window == board2) && i == 1 && buf[0] == '\014') {
	  XClearWindow(Display2, board2);
	  XClearWindow(Display2, status2);
	  XClearWindow(Display2, talk2);
	  XClearWindow(Display2, otherTalk2);
	  RedrawBoard(2);
	  break;
	}
	HandleKeyPress(kevent->window, player, buf, i);
	break;
      case ButtonPress:
	if (finalwinner) break;
	bevent = (XButtonEvent *)&event;
	if (player == 1) {
	  if (bevent->window == board1) {
	    BoardClick(player, bevent->x, bevent->y);
	  }
	  if ((bevent->window == status1) && setup1) {
	    setup1 = 0;
	    SetupDone(1);
	  }
	}
	if (player == 2) {
	  if (bevent->window == board2) {
	    BoardClick(player, bevent->x, bevent->y);
	  }
	  if ((bevent->window == status2) && setup2) {
	    setup2 = 0;
	    SetupDone(2);
	  }
	}
	break;
      case ButtonRelease:
	break;
      default:
	break;
      }
    }

  XUnmapSubwindows(Display1, wind1);
  XUnmapWindow(Display1, wind1);  
  XFreeGC(Display1, draw1);
  XFreeGC(Display1, erase1);
  XFreeGC(Display1, xor1);
  XFreeGC(Display1, invert1);
  XFreeGC(Display2, draw2);
  XFreeGC(Display2, erase2);
  XFreeGC(Display2, xor2);
  XFreeGC(Display2, invert2);
  XFreeCursor(Display1, cursor1);
  XFreeCursor(Display2, cursor2);
  XFreeFont(Display1, font1);
  XFreeFont(Display2, font2);
  XFreeColormap(Display1, Colormap1);
  XFreeColormap(Display2, Colormap2);
  for(i = 0; i < 15; i++) {
    XFreePixmap(Display1, pieces1[i].icon);
    XFreePixmap(Display2, pieces2[i].icon);
  }
  XDestroyWindow(Display1, wind1);
  XDestroyWindow(Display2, wind2);
  XCloseDisplay(Display1);
  XCloseDisplay(Display2);
  printf("Thank you for playing Capture the Flag\n");
}
