home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 January
/
usenetsourcesnewsgroupsinfomagicjanuary1994.iso
/
sources
/
games
/
volume13
/
x4war2
/
part02
/
x4war.c
Wrap
C/C++ Source or Header
|
1992-08-03
|
45KB
|
1,819 lines
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/X.h>
#include <X11/Xos.h>
#include <X11/Xatom.h>
#include <X11/Intrinsic.h>
#include <X11/keysym.h>
#include <stdio.h>
#include "war.h"
#include "bitmaps/war_background.xbm"
#include "bitmaps/war_logo.xbm"
#ifdef CHINESE
#include "bitmaps/chinese_piece/colours.xbm"
#include "bitmaps/chinese_piece/marshal.xbm"
#include "bitmaps/chinese_piece/general.xbm"
#include "bitmaps/chinese_piece/m_general.xbm"
#include "bitmaps/chinese_piece/brigadier.xbm"
#include "bitmaps/chinese_piece/colonel.xbm"
#include "bitmaps/chinese_piece/major.xbm"
#include "bitmaps/chinese_piece/captain.xbm"
#include "bitmaps/chinese_piece/f_lieutenant.xbm"
#include "bitmaps/chinese_piece/sapper.xbm"
#include "bitmaps/chinese_piece/mine.xbm"
#include "bitmaps/chinese_piece/bomb.xbm"
#else
#include "bitmaps/image_piece/colours.xbm"
#include "bitmaps/image_piece/marshal.xbm"
#include "bitmaps/image_piece/general.xbm"
#include "bitmaps/image_piece/m_general.xbm"
#include "bitmaps/image_piece/brigadier.xbm"
#include "bitmaps/image_piece/colonel.xbm"
#include "bitmaps/image_piece/major.xbm"
#include "bitmaps/image_piece/captain.xbm"
#include "bitmaps/image_piece/f_lieutenant.xbm"
#include "bitmaps/image_piece/sapper.xbm"
#include "bitmaps/image_piece/mine.xbm"
#include "bitmaps/image_piece/bomb.xbm"
#endif
#include "bitmaps/back0.xbm"
#include "bitmaps/back1.xbm"
#include "bitmaps/back2.xbm"
#include "bitmaps/back3.xbm"
#include "bitmaps/cursor.xbm"
#include "bitmaps/cursormask.xbm"
#include "bitmaps/nodemask.xbm"
#include "bitmaps/go.xbm"
#include "bitmaps/stop.xbm"
#include "bitmaps/pillar.xbm"
struct Player {
Display *dis;
int scr; /* screen number of display *dis */
Window win, confirm;
Pixmap node[16]; /* 0-11 for faces of nodes, 12-15 for back and cursor */
Pixmap cursormask_pixmap,nodemask_pixmap,icon_pixmap,stop_pixmap,go_pixmap;
unsigned long fg[4]; /* foreground of nodes */
XColor fg_color, bg_color;
GC gc;
Cursor cursor, tmp_cursor;
char *display_name;
char player_name[10];
char color_name[20];
int rip[5][5];
int rip_index;
int state; /* 0--dead, 1--deploy, 2--play, 3--quit */
int num_movable;
int popup; /* 0--no popup, 1--Peace Request, 2--Quit,
3--continue message*/
/* if confirm window is poped up, input is grabed */
/* this structure tells if a node is picked up by pressing a button, it
records the array and subscripts of the node.
*/
struct {
int arr;
int x, y;
int value;
Boolean picked;
} pick;
Boolean marshal_dead;
char talk_msg[3][30];
int talk_col;
int talk_x, talk_y;
};
XtAppContext app_context;
Arr arr[4][6][5], mid[3][3]; /* array to remember the state of the
war */
struct Player p[4];
Sapper_path sap[21];
Pixmap pillar[2];
Boolean two;
unsigned int global_argc;
char ** global_argv;
char *progname;
char msg1[30], msg2[30];
char confirm_msg[30];
int mode; /* game mode */
/* 0 -- new game and deploy phase */
/* 1 -- play phase */
/* 2 -- peace request phase */
/* 3 -- one game finished */
/* 4 -- during a move */
int num_player; /* when one is defeated, this var decrease by 1 */
int count; /* to calculate the flashing when node moved */
/* values and meanings
8--clear source;
7--show source;
6--clear source;
5--show source;
4--clear source;
3--show destination;
2--clear destination;
1--show destination;
0--clear destination;
*/
int turn; /* 0-3, specifies who's turn to move */
int round;
int sf, si, sj, sw, sv, df, di, dj, dw, dv; /* record one move */
Boolean debug;
static void refresh_board();
/*******************************************************************
*
* Synopsis
* parse_arguments(argc, argv)
* int argc;
* char **argv;
*
* Description
* parses arguments in command line and set appropriate properties,
* exit if illegal argument present.
*
********************************************************************/
static void
parse_arguments(argc, argv)
int argc;
char **argv;
{
int i;
i = 1;
while (i<argc) {
if (!strcmp(argv[i], "-p0"))
strncpy(p[0].player_name, argv[++i], 9);
else if (!strcmp(argv[i], "-d0"))
p[0].display_name = argv[++i];
else if (!strcmp(argv[i], "-c0"))
strncpy(p[0].color_name, argv[++i], 19);
else if (!strcmp(argv[i], "-p1"))
strncpy(p[1].player_name, argv[++i], 9);
else if (!strcmp(argv[i], "-d1"))
p[1].display_name = argv[++i];
else if (!strcmp(argv[i], "-c1"))
strncpy(p[1].color_name, argv[++i], 19);
else if (!strcmp(argv[i], "-p2"))
strncpy(p[2].player_name, argv[++i], 9);
else if (!strcmp(argv[i], "-d2"))
p[2].display_name = argv[++i];
else if (!strcmp(argv[i], "-c2"))
strncpy(p[2].color_name, argv[++i], 19);
else if (!strcmp(argv[i], "-p3"))
strncpy(p[3].player_name, argv[++i], 9);
else if (!strcmp(argv[i], "-d3"))
p[3].display_name = argv[++i];
else if (!strcmp(argv[i], "-c3"))
strncpy(p[3].color_name, argv[++i], 19);
else if (!strcmp(argv[i], "-usage") || !strcmp(argv[i], "-help")) {
syntax(argv[0]);
exit(0);
}
else if (!strcmp(argv[i], "-two"))
two = True;
else if (!strcmp(argv[i], "-debug"))
debug = True;
else {
syntax(argv[0]);
exit(-1);
}
i++;
}
}
/*****************************************************************************
*
* Synopsis
* Boolean LookUpColor(display, name, col, color_index)
* Display *display;
* char *name;
* XColor *col;
* unsigned long *color_index; return
*
* Arguments
* display specifies a connection to an X server;
* name a string for color;
* col returns XColor structure of the named color;
* color_index returns the pixel value representing the named color,
* which is actually an index to the colormap;
*
* Return values
* True on success
* False on failing to allocate the named color
*
****************************************************************************/
Boolean LookUpColor(display, name, col, color_index)
Display *display;
char *name;
XColor *col;
unsigned long *color_index;
{
XColor xcolor;
if(XAllocNamedColor(display, DefaultColormap(display, DefaultScreen(display)),
name, col, &xcolor) == 0) {
printf("LookUpColor: could not allocate %s.\n", name);
return(False);
}
*color_index = col->pixel;
return(True);
}
/*********************************************************************
*
* Synopsis
* connect_display()
*
* Description
* connect to displays and create windows.
*
**********************************************************************/
static void
connect_display()
{
Display *dpy;
Pixmap background;
int i, j;
char err_msg[100];
XSetWindowAttributes attr;
unsigned long fg, bg;
XSizeHints size_hints;
char *win_name, *icon_name;
XGCValues values;
XColor color;
XtToolkitInitialize();
app_context = XtCreateApplicationContext();
values.foreground = 0;
values.background = 1;
win_name = (char *)malloc(40);
for (i=0; i<4; i++) {
if (two && i%2 != 0) continue; /*for two players, connect only twice*/
if (!(p[i].dis=XtOpenDisplay(app_context, p[i].display_name, "x4war",
"x4war", 0, 0, &global_argc, global_argv))) {
sprintf(err_msg, "can not open display %s",
XDisplayName(p[i].display_name));
fatal_error(err_msg);
}
dpy = p[i].dis;
p[i].scr = DefaultScreen(dpy);
attr.border_pixel = BlackPixel(dpy, p[i].scr);
p[i].win = XCreateWindow(dpy, RootWindow(dpy,p[i].scr),
i*40, 0, DIMENSION, DIMENSION, 4, CopyFromParent,
InputOutput, CopyFromParent, CWBorderPixel, &attr);
if (!LookUpColor(dpy, DEFAULT_BOARD_BG, &color, &bg))
bg = WhitePixel(dpy, p[i].scr);
if (!LookUpColor(dpy, DEFAULT_BOARD_FG, &color, &fg))
fg = BlackPixel(dpy, p[i].scr);
background = XCreatePixmapFromBitmapData(dpy, p[i].win,
war_background_bits, war_background_width,
war_background_height, fg, bg,
DefaultDepth(dpy, p[i].scr));
XSetWindowBackgroundPixmap(dpy, p[i].win, background);
XFreePixmap(dpy, background);
sprintf(win_name, "x4war player %s", p[i].player_name);
icon_name = p[i].player_name;
p[i].icon_pixmap = XCreateBitmapFromData(dpy, p[i].win, war_logo_bits,
war_logo_width, war_logo_height);
size_hints.flags = PPosition | PSize | PMinSize;
size_hints.min_width = DIMENSION;
size_hints.min_height = DIMENSION;
{
XWMHints wm_hints;
XClassHint class_hints;
XTextProperty windowName, iconName;
if (XStringListToTextProperty(&win_name, 1, &windowName) == 0)
fatal_error("structure allocation for windowName failed.");
if (XStringListToTextProperty(&icon_name, 1, &iconName) == 0)
fatal_error("structure allocation for iconName failed.");
wm_hints.initial_state = NormalState;
wm_hints.input = True;
wm_hints.icon_pixmap = p[i].icon_pixmap;
wm_hints.flags = StateHint | IconPixmapHint | InputHint;
class_hints.res_name = progname;
class_hints.res_class = "X4war";
XSetWMProperties(dpy, p[i].win, &windowName, &iconName,
global_argv, global_argc, &size_hints, &wm_hints,
&class_hints);
}
XSelectInput(dpy, p[i].win, ExposureMask | KeyPressMask |
ButtonPressMask | ButtonReleaseMask);
if (!LookUpColor(dpy, p[i].color_name, &(p[i].fg_color), &(p[i].fg[i])))
p[i].fg[i] = BlackPixel(dpy, p[i].scr);
for (j=0; j<4; j++) {
if ((two && j%2 != 0) || j==i) continue;
if (!LookUpColor(dpy, p[j].color_name, &color, &(p[i].fg[j])))
p[i].fg[j] = BlackPixel(dpy, p[i].scr);
}
p[i].gc = XCreateGC(dpy, p[i].win, 0, NULL);
XSetBackground(dpy, p[i].gc, WhitePixel(dpy, p[i].scr));
XSetFont(dpy, p[i].gc, XLoadFont(dpy, "9x15bold"));
XSetLineAttributes(dpy, p[i].gc, 2, LineSolid, CapButt, JoinRound);
p[i].node[0] = XCreateBitmapFromData(dpy, p[i].win, colours_bits,
colours_width, colours_height);
p[i].node[1] = XCreateBitmapFromData(dpy, p[i].win, sapper_bits,
sapper_width, sapper_height);
p[i].node[2] = XCreateBitmapFromData(dpy, p[i].win, f_lieutenant_bits,
f_lieutenant_width, f_lieutenant_height);
p[i].node[3] = XCreateBitmapFromData(dpy, p[i].win, captain_bits,
captain_width, captain_height);
p[i].node[4] = XCreateBitmapFromData(dpy, p[i].win, major_bits,
major_width, major_height);
p[i].node[5] = XCreateBitmapFromData(dpy, p[i].win, colonel_bits,
colonel_width, colonel_height);
p[i].node[6] = XCreateBitmapFromData(dpy, p[i].win, brigadier_bits,
brigadier_width, brigadier_height);
p[i].node[7] = XCreateBitmapFromData(dpy, p[i].win, m_general_bits,
m_general_width, m_general_height);
p[i].node[8] = XCreateBitmapFromData(dpy, p[i].win, general_bits,
general_width, general_height);
p[i].node[9] = XCreateBitmapFromData(dpy, p[i].win, marshal_bits,
marshal_width, marshal_height);
p[i].node[10] = XCreateBitmapFromData(dpy, p[i].win, mine_bits,
mine_width, mine_height);
p[i].node[11] = XCreateBitmapFromData(dpy, p[i].win, bomb_bits,
bomb_width, bomb_height);
if (i != 0)
p[i].node[12] = XCreateBitmapFromData(dpy, p[i].win,
back0_bits, back0_width, back0_height);
if (i != 1)
p[i].node[13] = XCreateBitmapFromData(dpy, p[i].win,
back1_bits, back1_width, back1_height);
if (i != 2)
p[i].node[14] = XCreateBitmapFromData(dpy, p[i].win,
back2_bits, back2_width, back2_height);
if (i != 3)
p[i].node[15] = XCreateBitmapFromData(dpy, p[i].win,
back3_bits, back3_width, back3_height);
p[i].node[12+i] = XCreateBitmapFromData(dpy, p[i].win,
cursor_bits, cursor_width, cursor_height);
p[i].cursormask_pixmap = XCreateBitmapFromData(dpy, p[i].win,
cursormask_bits, cursormask_width, cursormask_height);
LookUpColor(dpy, "White", &(p[i].bg_color), &bg);
p[i].cursor = XCreatePixmapCursor(dpy, p[i].node[i+12],
p[i].cursormask_pixmap, &(p[i].fg_color), &(p[i].bg_color),
cursor_x_hot, cursor_y_hot);
XDefineCursor(dpy, p[i].win, p[i].cursor);
p[i].confirm = XCreateSimpleWindow(dpy, p[i].win, 400, 400, 300, 120, 4,
BlackPixel(dpy, p[i].scr), WhitePixel(dpy, p[i].scr));
XSelectInput(dpy, p[i].confirm, ExposureMask | ButtonPressMask);
p[i].nodemask_pixmap = XCreateBitmapFromData(dpy, p[i].win,
nodemask_bits, nodemask_width, nodemask_height);
p[i].stop_pixmap = XCreateBitmapFromData(dpy, p[i].win, stop_bits,
stop_width, stop_height);
p[i].go_pixmap = XCreateBitmapFromData(dpy, p[i].win, go_bits,
go_width, go_height);
}
if (two) {
pillar[0] = XCreateBitmapFromData(p[0].dis, p[0].win, pillar_bits,
pillar_width, pillar_height);
pillar[1] = XCreateBitmapFromData(p[2].dis, p[2].win, pillar_bits,
pillar_width, pillar_height);
}
}
/************************************************************************
*
* Synopsis
* initial_board()
*
* Description
* set for a new game
*
************************************************************************/
static void
initial_board()
{
int i, j, k;
for (i=0; i<4; i++)
for (j=0; j<6; j++)
for (k=0; k<5; k++) {
arr[i][j][k].value = EMPTY;
arr[i][j][k].id = i;
}
for (i=0; i<3; i++)
for (j=0; j<3; j++)
mid[i][j].value = EMPTY;
for (i=0; i<4; i++) {
p[i].rip_index = 0;
p[i].state = 1;
p[i].num_movable = 21;
p[i].popup = 0;
p[i].pick.picked = False;
p[i].marshal_dead = False;
p[i].talk_msg[0][0] = p[i].talk_msg[1][0] = p[i].talk_msg[2][0] = '\0';
p[i].talk_col = 0;
if (debug && (!two || i%2==0)) {
arr[i][0][0].value = MARSHAL;
arr[i][0][1].value = GENERAL;
arr[i][0][2].value = M_GENERAL;
arr[i][0][3].value = M_GENERAL;
arr[i][0][4].value = BRIGADIER;
arr[i][1][0].value = BRIGADIER;
arr[i][1][2].value = COLONEL;
arr[i][1][4].value = COLONEL;
arr[i][2][0].value = MAJOR;
arr[i][2][1].value = MAJOR;
arr[i][2][3].value = CAPTAIN;
arr[i][2][4].value = CAPTAIN;
arr[i][3][0].value = CAPTAIN;
arr[i][3][2].value = F_LIEUTENANT;
arr[i][3][4].value = F_LIEUTENANT;
arr[i][4][0].value = F_LIEUTENANT;
arr[i][4][1].value = SAPPER;
arr[i][4][2].value = SAPPER;
arr[i][4][3].value = SAPPER;
arr[i][4][4].value = BOMB;
arr[i][5][0].value = BOMB;
arr[i][5][1].value = COLOURS;
arr[i][5][2].value = MINE;
arr[i][5][3].value = MINE;
arr[i][5][4].value = MINE;
for (j=0; j<5; j++)
for (k=0; k<5; k++)
p[i].rip[j][k] = EMPTY;
}
else {
p[i].rip[0][0] = COLOURS;
p[i].rip[0][1] = MARSHAL;
p[i].rip[0][2] = GENERAL;
p[i].rip[0][3] = M_GENERAL;
p[i].rip[0][4] = M_GENERAL;
p[i].rip[1][0] = BRIGADIER;
p[i].rip[1][1] = BRIGADIER;
p[i].rip[1][2] = COLONEL;
p[i].rip[1][3] = COLONEL;
p[i].rip[1][4] = MAJOR;
p[i].rip[2][0] = MAJOR;
p[i].rip[2][1] = CAPTAIN;
p[i].rip[2][2] = CAPTAIN;
p[i].rip[2][3] = CAPTAIN;
p[i].rip[2][4] = F_LIEUTENANT;
p[i].rip[3][0] = F_LIEUTENANT;
p[i].rip[3][1] = F_LIEUTENANT;
p[i].rip[3][2] = SAPPER;
p[i].rip[3][3] = SAPPER;
p[i].rip[3][4] = SAPPER;
p[i].rip[4][0] = MINE;
p[i].rip[4][1] = MINE;
p[i].rip[4][2] = MINE;
p[i].rip[4][3] = BOMB;
p[i].rip[4][4] = BOMB;
}
}
if (two) {
num_player = 2;
arr[1][0][0].value = arr[1][0][2].value = arr[1][0][4].value =
arr[3][0][0].value = arr[3][0][2].value = arr[3][0][4].value = PILLAR;
p[1].state = p[3].state = 3;
}
else num_player = 4;
mode = 0;
}
/*********************************************************************
*
* Synopsis
* int whichplayer(display)
* Display *display;
*
* Return values
* 0 - 4 according to whom the display belongs
* -1 if nobody
*
**********************************************************************/
int whichplayer(display)
Display *display;
{
int i;
for (i=0; i<4; i++) {
if (two && i%2 != 0) continue;
if (p[i].state != 3 && display == p[i].dis) return(i);
}
return(-1);
}
/**********************************************************************
*
* Synopsis
* put_msg(s1, s2)
* char *s1, *s2;
*
* Description
* put the two strings into the global msg1 and msg2, and draw them
* on the board.
*
***********************************************************************/
static void
put_msg(s1, s2)
char *s1, *s2;
{
int i;
strncpy(msg1, s1, MAX_MSG);
strncpy(msg2, s2, MAX_MSG);
for (i=0; i<4; i++)
if (p[i].state != 3) {
XClearArea(p[i].dis, p[i].win, MSG_BOX_X, MSG_BOX_Y,
MSG_WIDTH, MSG_HEIGHT, False);
XSetForeground(p[i].dis, p[i].gc, p[i].fg[i]);
XDrawString(p[i].dis, p[i].win, p[i].gc, MSG_X, MSG_Y,
msg1, strlen(msg1));
XDrawString(p[i].dis, p[i].win, p[i].gc, MSG_X, MSG_Y+25,
msg2, strlen(msg2));
}
}
/*********************************************************************
*
* Synopsis
* send_expose_event()
*
* Description
* send an expose event to all active players
*
*********************************************************************/
static void
send_expose_event()
{
XEvent event;
int n;
event.xexpose.x = event.xexpose.y = 0;
event.xexpose.width = event.xexpose.height = DIMENSION;
for (n=0; n<4; n++)
if (p[n].state != 3)
refresh_board(n, &event);
}
/**********************************************************************
*
* Synopsis
* redraw_confirm(i)
* int i;
*
* Argument
* i specifies which player;
*
* Description
* redraws the confirmation window, with confirm_msg displayed.
*
***********************************************************************/
static void
redraw_confirm(i)
int i;
{
XSetForeground(p[i].dis, p[i].gc, BlackPixel(p[i].dis, p[i].scr));
XDrawRectangle(p[i].dis, p[i].confirm, p[i].gc, 3, 3, 293, 113);
if (p[i].popup == 3)
XDrawRectangle(p[i].dis, p[i].confirm, p[i].gc, 100, 75, 99, 19);
else {
XDrawRectangle(p[i].dis, p[i].confirm, p[i].gc, 80, 75, 39, 19);
XDrawRectangle(p[i].dis, p[i].confirm, p[i].gc, 180, 75, 39, 19);
}
XSetForeground(p[i].dis, p[i].gc, p[i].fg[i]);
if (p[i].popup == 3)
XDrawString(p[i].dis, p[i].confirm, p[i].gc, 110, 90, "CONTINUE", 8);
else {
XDrawString(p[i].dis, p[i].confirm, p[i].gc, 90, 90, "OK", 2);
XDrawString(p[i].dis, p[i].confirm, p[i].gc, 190, 90, "NO", 2);
}
XDrawString(p[i].dis, p[i].confirm, p[i].gc, 30, 40, confirm_msg,
strlen(confirm_msg));
}
/**********************************************************************
*
* Synopsis
* Boolean valid_deploy(i)
* int i;
*
* Description
* check if player i's initial deploy is valid.
*
***********************************************************************/
Boolean valid_deploy(i)
int i;
{
int m, n, k;
if (arr[i][5][1].value != COLOURS && arr[i][5][3].value != COLOURS)
return(False);
if (arr[i][1][1].value != EMPTY || arr[i][1][3].value != EMPTY ||
arr[i][2][2].value != EMPTY || arr[i][3][1].value != EMPTY ||
arr[i][3][3].value != EMPTY)
return(False);
k = 0;
for (m=4; m<6; m++)
for (n=0; n<5; n++)
if (arr[i][m][n].value == MINE) k++;
if (k<3) return(False);
for (m=0; m<5; m++)
for (n=0; n<5; n++)
if (p[i].rip[m][n] != EMPTY) return(False);
if (arr[i][5][1].value != MINE && arr[i][5][3].value != MINE)
p[i].num_movable--;
return(True);
}
/***********************************************************************
*
* Synopsis
* peace_request(i)
* int i;
*
* Description
* player i request for peace, this can only happen in play mode 1.
*
************************************************************************/
static void
peace_request(i)
int i;
{
int n;
mode = 2;
for (n=0; n<4; n++)
if (n != i && p[n].state == 2) {
p[n].popup = 1;
sprintf(confirm_msg, "%s requesting peace", p[i].player_name);
XMapWindow(p[n].dis, p[n].confirm);
}
}
/********************************************************************
*
* Synopsis
* lost_war(i)
* int i;
*
* Description
* player i lost the war, if he/she's partner has lost too, change
* mode to 3; else, just update the playing array and send an expose
* event.
*
**********************************************************************/
static void
lost_war(i)
int i;
{
int n, j, k;
p[i].state = 0;
num_player--;
if (two || p[(i+2)%4].state != 2) {
if (!two)
put_msg(p[i].player_name, "and my ally lost!");
if (two)
sprintf(confirm_msg, "%s lost the war", p[i].player_name);
else
sprintf(confirm_msg, "%s and %s lost!", p[i].player_name,
p[(i+2)%4].player_name);
for (n=0; n<4; n++)
if (p[n].state != 3) {
XBell(p[n].dis, 0);
p[n].popup = 3;
XMapWindow(p[n].dis, p[n].confirm);
p[n].state = 0;
}
mode = 3;
send_expose_event();
}
else {
for (n=0; n<4; n++)
for (j=0; j<6; j++)
for (k=0; k<5; k++)
if (arr[n][j][k].value != EMPTY && arr[n][j][k].id == i) {
p[i].rip[p[i].rip_index/5][p[i].rip_index%5] =
arr[n][j][k].value;
p[i].rip_index++;
arr[n][j][k].value = EMPTY;
}
for (n=0; n<3; n++)
for (j=0; j<3; j++)
if (mid[n][j].value != EMPTY && mid[n][j].id == i) {
p[i].rip[p[i].rip_index/5][p[i].rip_index%5] = mid[n][j].value;
p[i].rip_index++;
mid[n][j].value = EMPTY;
}
send_expose_event();
}
}
/***********************************************************************
*
* Synopsis
* new_game()
*
* Description
* it clears the board and starts a new game, or quit if someone has gone.
*
************************************************************************/
static void
new_game()
{
int i, j, k;
if (!two)
for (i=0; i<4; i++)
if (p[i].state == 3) { /* someone has already quit */
for (k=0; k<4; k++) {
XFreeCursor(p[k].dis, p[k].cursor);
XFreeGC(p[k].dis, p[k].gc);
for (j=0; j<16; j++)
XFreePixmap(p[k].dis, p[k].node[j]);
XFreePixmap(p[k].dis, p[k].cursormask_pixmap);
XFreePixmap(p[k].dis, p[k].icon_pixmap);
XFreePixmap(p[k].dis, p[k].go_pixmap);
XFreePixmap(p[k].dis, p[k].stop_pixmap);
}
exit(0);
}
for (i=0; i<4; i++) {
if (two && i%2 !=0) continue;
if (p[i].popup != 0) {
p[i].popup = 0;
XUnmapWindow(p[i].dis, p[i].confirm);
}
XClearArea(p[i].dis, p[i].win, 0, 0, DIMENSION, DIMENSION, False);
}
initial_board();
put_msg("New War", "deploy first");
send_expose_event();
}
/************************************************************************
*
* Synopsis
* putsign(i, flag)
* int i, flag;
*
* Arguments
* i specifies which player's board;
* flag 0 or 1, 0 to put stop sign, and 1 to put go ahead sign
*
* Description
* it puts stop or go-ahead signs in the sign box.
*
*************************************************************************/
static void
putsign(i, flag)
int i, flag;
{
XSetForeground(p[i].dis, p[i].gc, p[i].fg[i]);
if (flag)
XCopyPlane(p[i].dis, p[i].go_pixmap, p[i].win, p[i].gc, 0, 0,
SIGN_DIMENSION, SIGN_DIMENSION, P1+2, P1+2, 1);
else
XCopyPlane(p[i].dis, p[i].stop_pixmap, p[i].win, p[i].gc, 0, 0,
SIGN_DIMENSION, SIGN_DIMENSION, P1+2, P1+2, 1);
}
/***********************************************************************
*
* Synopsis
* putnode(i, value, x, y)
* int i, value, x, y;
*
* Arguments
* i specifies player i's board;
* value -2 -- 15, means clear or an index to the node image;
* x, y coordinates of the center of the node on the board;
*
* Description
* it draws the image indicated by value at position (x,y) on
* player i's board.
* if value is EMPTY, it clear the positioned area.
* the foreground of the gc should be set before hand.
* the image is drawn at (x-20, y-20) with width and height of
* both 40.
*
************************************************************************/
static void
putnode(i, value, x, y)
int i, value, x, y;
{
if (value == EMPTY)
XClearArea(p[i].dis, p[i].win, x-20, y-20, 40, 40, False);
else
if (value != PILLAR)
XCopyPlane(p[i].dis, p[i].node[value], p[i].win, p[i].gc, 0, 0,
40, 40, x-20, y-20, 1);
else
XCopyPlane(p[i].dis, pillar[i/2], p[i].win, p[i].gc, 0, 0,
40, 40, x-20, y-20, 1);
}
/************************************************************************
*
* Synopsis
* putarea(i, x1, y1, x2, y2)
* int i, x1, y1, x2, y2)
*
* Description
* redraw an area of (x1, y1), (x2, y2) on player i's board.
* the coordinates are for the board but within the area of F0-F3
* and MIDFIELD.
*
*************************************************************************/
putarea(i, x1, y1, x2, y2)
int i, x1, y1, x2, y2;
{
int f, k, l, m, n, a1, b1, a2, b2, c, d;
boardtoarr(i, x1, y1, &a1, &b1);
f = boardtoarr(i, x2, y2, &a2, &b2);
if (a1 > a2) {
k = a1; a1 = a2; a2 = k;
}
if (b1 > b2) {
k = b1; b1 = b2; b2 = k;
}
for (m=a1; m<=a2; m++)
for (n=b1; n<=b2; n++) {
if (f == MIDFIELD) {
k = mid[m][n].value;
l = mid[m][n].id;
}
else {
k = arr[f][m][n].value;
l = arr[f][m][n].id;
}
if (k == PILLAR)
XSetForeground(p[i].dis, p[i].gc, BlackPixel(p[i].dis, p[i].scr));
else
XSetForeground(p[i].dis, p[i].gc, p[i].fg[l]);
if (k > EMPTY && l != i && p[i].state != 0 &&
!(k==COLOURS && p[f].marshal_dead) ) k = l + 12;
arrtoboard(i, f, m, n, &c, &d);
putnode(i, k, c, d);
}
}
/************************************************************************
*
* Synopsis
* refresh_board(i, event)
* int i;
* XEvent *event;
*
* Description
* refresh player i's board according to the expose event.
*
**************************************************************************/
static void
refresh_board(i, event)
int i;
XEvent *event;
{
int x1, y1, x2, y2;
int a1, b1, a2, b2;
int c1, d1, c2, d2;
int flag, m, n;
char s[35];
x1 = event->xexpose.x;
y1 = event->xexpose.y;
x2 = x1 + event->xexpose.width;
y2 = y1 + event->xexpose.height;
flag = area_intersection(P1, P1, P2, P2, x1,y1, x2,y2, &a1, &b1, &a2, &b2);
if (flag) {
XSetForeground(p[i].dis, p[i].gc, p[i].fg[i]);
if (mode == 0 || mode == 3 || turn != i)
putsign(i, 0);
else putsign(i, 1);
XClearArea(p[i].dis, p[i].win, TALK_L_X, TALK_Y, TALK_WIDTH, 150,False);
XSetForeground(p[i].dis, p[i].gc, p[i].fg[0]);
sprintf(s, "PLAYER 0 (%s)", p[0].player_name);
XDrawString(p[i].dis, p[i].win,p[i].gc, TALK0_X, TALK_Y-5, s,strlen(s));
n = TALK0_Y;
for (m=0; m<3; m++) {
XDrawString(p[i].dis, p[i].win, p[i].gc, TALK0_X, n,
p[0].talk_msg[m], strlen(p[0].talk_msg[m]));
n += TALK_Y_INC;
}
XSetForeground(p[i].dis, p[i].gc, p[i].fg[2]);
sprintf(s, "PLAYER 2 (%s)", p[2].player_name);
XDrawString(p[i].dis, p[i].win,p[i].gc, TALK2_X,TALK_Y+85, s,strlen(s));
n = TALK2_Y;
for (m=0; m<3; m++) {
XDrawString(p[i].dis, p[i].win, p[i].gc, TALK2_X, n,
p[2].talk_msg[m], strlen(p[2].talk_msg[m]));
n += TALK_Y_INC;
}
}
flag = area_intersection(P5, P1, P6, P2, x1,y1, x2,y2, &a1, &b1, &a2, &b2);
if (flag) {
XSetForeground(p[i].dis, p[i].gc, p[i].fg[i]);
XClearArea(p[i].dis, p[i].win, MSG_BOX_X, MSG_BOX_Y,
MSG_WIDTH, MSG_HEIGHT, False);
XDrawString(p[i].dis, p[i].win, p[i].gc, MSG_X, MSG_Y,
msg1, strlen(msg1));
XDrawString(p[i].dis, p[i].win, p[i].gc, MSG_X, MSG_Y+25,
msg2, strlen(msg2));
XSetForeground(p[i].dis, p[i].gc, p[i].fg[1]);
sprintf(s, "PLAYER 1 (%s)", p[1].player_name);
XDrawString(p[i].dis, p[i].win,p[i].gc, TALK1_X, TALK_Y-5, s,strlen(s));
n = TALK1_Y;
for (m=0; m<3; m++) {
XDrawString(p[i].dis, p[i].win, p[i].gc, TALK1_X, n,
p[1].talk_msg[m], strlen(p[1].talk_msg[m]));
n += TALK_Y_INC;
}
XSetForeground(p[i].dis, p[i].gc, p[i].fg[3]);
sprintf(s, "PLAYER 3 (%s)", p[3].player_name);
XDrawString(p[i].dis, p[i].win,p[i].gc, TALK3_X,TALK_Y+85, s,strlen(s));
n = TALK3_Y;
for (m=0; m<3; m++) {
XDrawString(p[i].dis, p[i].win, p[i].gc, TALK3_X, n,
p[3].talk_msg[m], strlen(p[3].talk_msg[m]));
n += TALK_Y_INC;
}
}
flag = area_intersection(P1+5, RIP_Y+5, P1+RIP_DIMENSION-5,
RIP_Y+RIP_DIMENSION-5, x1, y1, x2, y2, &a1, &b1, &a2, &b2);
if (flag) {
boardtofield(a1, b1, &c1, &d1);
boardtofield(a2, b2, &c2, &d2);
XSetForeground(p[i].dis, p[i].gc, p[i].fg[i]);
for (m=c1; m<=c2; m++)
for (n=d1; n<=d2; n++) {
fieldtoboard(RIP, m, n, &a1, &b1);
putnode(i, p[i].rip[m][n], a1, b1);
}
}
/* refresh field 0 */
flag = area_intersection(P3-20, P5-20, P4+20, P6+20,
x1, y1, x2, y2, &a1, &b1, &a2, &b2);
if (flag)
putarea(i, a1, b1, a2, b2);
if (mode > 0) {
/* refresh field 1 */
flag = area_intersection(P5-20, P3-20, P6+20, P4+20,
x1, y1, x2, y2, &a1, &b1, &a2, &b2);
if (flag)
putarea(i, a1, b1, a2, b2);
/* refresh field 2 */
flag = area_intersection(P3-20, P1-20, P4+20, P2+20,
x1, y1, x2, y2, &a1, &b1, &a2, &b2);
if (flag)
putarea(i, a1, b1, a2, b2);
/* refresh field 3 */
flag = area_intersection(P1-20, P3-20, P2+20, P4+20,
x1, y1, x2, y2, &a1, &b1, &a2, &b2);
if (flag)
putarea(i, a1, b1, a2, b2);
/* refresh midfield */
flag = area_intersection(P3-20, P3-20, P4+20, P4+20,
x1, y1, x2, y2, &a1, &b1, &a2, &b2);
if (flag)
putarea(i, a1, b1, a2, b2);
}
}
/**********************************************************************
*
* Synopsis
* talk(i, flag, k)
* int i, flag;
* char k;
*
* Arguments
* i player i pressed a key;
* flag 0 - a printable key; 1 - a backspace; 2 - a Return key;
* k the char if printable;
*
* Description
* player i has pressed a key 'k', this function draws the character
* in the corresponding talking box.
*
************************************************************************/
static void
talk(i, flag, k)
int i, flag;
char k;
{
int m;
static char s[] = {' ', '\0'};
if (flag == 1) {
if (p[i].talk_col == 0) return;
s[0] = ' ';
p[i].talk_msg[2][p[i].talk_col] = '\0';
p[i].talk_col--;
for (m=0; m<4; m++)
if (p[m].state != 3)
XDrawImageString(p[m].dis, p[m].win, p[m].gc,
p[i].talk_x+p[i].talk_col*TALK_X_INC, p[i].talk_y,
s, 1);
return;
}
for (m=0; m<4; m++)
if (p[m].state != 3)
XSetForeground(p[m].dis, p[m].gc, p[m].fg[i]);
if (flag == 2 || p[i].talk_col >= MAX_MSG) {
strcpy(p[i].talk_msg[0], p[i].talk_msg[1]);
strcpy(p[i].talk_msg[1], p[i].talk_msg[2]);
p[i].talk_msg[2][0] = '\0';
p[i].talk_col = 0;
for (m=0; m<4; m++)
if (p[m].state != 3) {
XClearArea(p[m].dis, p[m].win, p[i].talk_x-5,
p[i].talk_y-2*TALK_Y_INC-15, TALK_WIDTH, TALK_HEIGHT,
False);
XDrawImageString(p[m].dis, p[m].win, p[m].gc,
p[i].talk_x, p[i].talk_y-2*TALK_Y_INC,
p[i].talk_msg[0], strlen(p[i].talk_msg[0]));
XDrawImageString(p[m].dis, p[m].win, p[m].gc,
p[i].talk_x, p[i].talk_y-TALK_Y_INC,
p[i].talk_msg[1], strlen(p[i].talk_msg[1]));
}
}
if (flag == 0) {
s[0] = k;
for (m=0; m<4; m++)
if (p[m].state != 3)
XDrawImageString(p[m].dis, p[m].win, p[m].gc,
p[i].talk_x+TALK_X_INC*p[i].talk_col,
p[i].talk_y, s, 1);
p[i].talk_msg[2][p[i].talk_col++] = k;
p[i].talk_msg[2][p[i].talk_col] = '\0';
}
}
/**********************************************************************
*
* Synopsis
* int move(i, f, x, y)
* int i, f, x, y;
*
* Argument
* i 0-3, specifies a move from p[i].pick;
* f F0 -- RIP, the destination array;
* x, y subscripts in the destination array;
*
* Return values
* 0 invalid move;
* 1 no fight, just a move;
* 2 source loses;
* 3 tie;
* 4 source win;
*
***********************************************************************/
int move(i, f, x, y)
int i, f, x, y;
{
int m;
if (f == RIP) return(0);
if (two && (f==1 || f==3)) return(0);
if (f == MIDFIELD) {
m = mid[x][y].value;
if (m != EMPTY && (mid[x][y].id==i || (!two && mid[x][y].id==(i+2)%4)))
return(0);
}
else {
m = arr[f][x][y].value;
if (m != EMPTY && (arr[f][x][y].id==i ||
(!two && arr[f][x][y].id==(i+2)%4)))
return(0);
if (m != EMPTY && ((x==1 && y==1) || (x==1 && y==3) || (x==2 && y==2)
|| (x==3 && y==1) || (x==3 && y==3)))
return(0);
}
if (!valid_move(p[i].pick.arr, p[i].pick.x, p[i].pick.y, f, x, y))
return(0);
if (x==5 && (y==1 || y==3))
return ((m==COLOURS) ? 3 : 2);
if (m == EMPTY) return(1);
return(fight(p[i].pick.value, m));
}
/************************************************************************
*
* Synopsis
* Boolean lose_check(i, v)
* int i, v;
*
* Return values
* True if defeated;
* False otherwise;
*
* Description
* player i has just lost a node valued v, this function checks if:
* it is the COLOURS, then declares defeated;
* it is the MARSHAL, then its COLOURS is showed face up on all
* boards;
* the player has no moving nodes avaliable, then declares defeated.
* the last case is not implemented.
*
***************************************************************************/
Boolean lose_check(i, v)
int i, v;
{
int m, k, b, c;
if (v == COLOURS)
return(True);
if (v == MARSHAL) {
p[i].marshal_dead = True;
m = (arr[i][5][1].value == COLOURS) ? 1 : 3;
for (k=0; k<4; k++)
if (p[k].state != 3) {
XSetForeground(p[k].dis, p[k].gc, p[k].fg[i]);
arrtoboard(k, i, 5, m, &b, &c);
putnode(k, COLOURS, b, c);
}
}
if ((--p[i].num_movable)==0) return(True);
return(False);
}
/***********************************************************************
*
* Synopsis
* return_rip(i, v)
* int i, v;
*
* Description
* returns player i's node valued v to rip.
*
************************************************************************/
static void
return_rip(i, v)
int i, v;
{
int m, n, x, y;
m = p[i].rip_index/5;
n = p[i].rip_index%5;
p[i].rip[m][n] = v;
p[i].rip_index++;
arrtoboard(i, RIP, m, n, &x, &y);
XSetForeground(p[i].dis, p[i].gc, p[i].fg[i]);
putnode(i, v, x, y);
}
/************************************************************************
*
* Synopsis
* show_move(m)
* int m;
*
* Argument
* m the moving result from move();
*
* Description
* it takes the values from the global arguments (sf,si,sj) and
* (df,di,dj) and show the move on the board.
* Then, it update the state to implement the move.
*
************************************************************************/
static void
show_move(m)
int m;
{
int a, b, c, v, w, x;
char s1[40], s2[40];
if (count >= 0) {
for (c=0; c<4; c++)
if (p[c].state != 3) {
if (count>3)
arrtoboard(c, sf, si, sj, &a, &b);
else
arrtoboard(c, df, di, dj, &a, &b);
if (count%2 == 0)
putnode(c, -1, a, b);
else {
XSetForeground(p[c].dis, p[c].gc, p[c].fg[sw]);
x = sv;
if (c!=sw && p[c].state!=0)
x = 12 + sw;
putnode(c, x, a, b);
}
}
count--;
XtAppAddTimeOut(app_context, 300, show_move, m);
}
else {
sprintf(s1, "%s (%d,%d,%d)=>(%d,%d,%d)", p[sw].player_name,
sf, si, sj, df, di, dj);
if (m == 2)
sprintf(s2, "%s lost to %s", p[sw].player_name, p[dw].player_name);
else if (m == 3)
sprintf(s2, "%s and %s tied", p[sw].player_name, p[dw].player_name);
else
sprintf(s2, "%s is marching on", p[sw].player_name);
put_msg(s1, s2);
if (m == 3)
if (df == MIDFIELD) mid[di][dj].value = EMPTY;
else arr[df][di][dj].value = EMPTY;
if (m == 4 || m == 1)
if (df == MIDFIELD) {
mid[di][dj].value = sv;
mid[di][dj].id = sw;
}
else {
arr[df][di][dj].value = sv;
arr[df][di][dj].id = sw;
}
if (df == MIDFIELD) {
w = mid[di][dj].id;
v = mid[di][dj].value;
}
else {
w = arr[df][di][dj].id;
v = arr[df][di][dj].value;
}
for (c=0; c<4; c++)
if (p[c].state != 3) {
arrtoboard(c, df, di, dj, &a, &b);
XSetForeground(p[c].dis, p[c].gc, p[c].fg[w]);
x = v;
if (c!=w && p[c].state!=0 && v!=EMPTY)
x = 12 + w;
putnode(c, x, a, b);
}
mode = 1; /* because lost_war could change mode if lost */
if (m == 3 || m == 4) {
return_rip(dw, dv);
if (lose_check(dw, dv)) lost_war(dw);
}
if ((mode==1) && (m==2 || m==3)) {
return_rip(sw, sv);
if (lose_check(sw, sv)) lost_war(sw);
}
if (mode == 1) {
if (two) turn = (turn + 2) % 4;
else
do {
turn = (turn+1)%4;
} while (p[turn].state != 2);
putsign(sw, 0);
putsign(turn, 1);
XBell(p[turn].dis, 0);
}
}
}
main(argc, argv)
int argc;
char **argv;
{
int i, j, who, x, y, f, m, n;
int agree_to_peace;
XEvent event;
char buffer, s[40];
KeySym keysym;
XComposeStatus compose;
progname = argv[0];
global_argc = argc;
global_argv = argv;
for (i=0; i<4; i++) {
p[i].display_name = NULL;
sprintf(p[i].player_name, "PLAYER %d", i);
}
strcpy(p[0].color_name, PLAYER0_COLOR);
strcpy(p[1].color_name, PLAYER1_COLOR);
strcpy(p[2].color_name, PLAYER2_COLOR);
strcpy(p[3].color_name, PLAYER3_COLOR);
p[0].talk_x = p[2].talk_x = TALK0_X;
p[1].talk_x = p[3].talk_x = TALK1_X;
p[0].talk_y = p[1].talk_y = TALK0_Y+2*TALK_Y_INC;
p[2].talk_y = p[3].talk_y = TALK2_Y+2*TALK_Y_INC;
debug = False;
two = False;
parse_arguments(argc, argv);
connect_display();
initial_sapper();
initial_board();
turn = 0;
for (i=0; i<4; i++) {
if (two && i%2 != 0) continue;
XMapWindow(p[i].dis, p[i].win);
}
while (1) {
XtAppNextEvent(app_context, &event);
switch(event.type) {
case Expose:
who = whichplayer(event.xexpose.display);
if (who == -1) break;
if (p[who].confirm == event.xexpose.window)
redraw_confirm(who);
else refresh_board(who, &event);
break;
case ButtonPress:
who = whichplayer(event.xbutton.display);
if (who == -1) break;
if (p[who].popup) {
if (event.xbutton.window != p[who].confirm) {
XBell(p[who].dis, 0);
break;
}
x = event.xbutton.x;
y = event.xbutton.y;
if (p[who].popup != 3)
if (x>80 && x<120 && y>75 && y<95) f = 1;
else if (x>180 && x<220 && y>75 && y<95) f = 0;
else {
XBell(p[who].dis, 0);
break;
}
XUnmapWindow(p[who].dis, p[who].confirm);
if (p[who].popup == 3) {
p[who].popup = 0;
break;
}
if (p[who].popup == 2) { /* QUIT popup */
if (f) { /* yes to quit */
XUnmapWindow(p[who].dis, p[who].win);
if (p[who].state || mode==3 || two) {
for (i=0; i<4; i++) {
if (two && i%2 != 0) continue;
XFreeCursor(p[i].dis, p[i].cursor);
XFreeGC(p[i].dis, p[i].gc);
for (j=0; j<16; j++)
XFreePixmap(p[i].dis, p[i].node[j]);
XFreePixmap(p[i].dis, p[i].cursormask_pixmap);
XFreePixmap(p[i].dis, p[i].icon_pixmap);
XFreePixmap(p[i].dis, p[i].go_pixmap);
XFreePixmap(p[i].dis, p[i].stop_pixmap);
XFreePixmap(p[i].dis, p[i].nodemask_pixmap);
}
exit(0);
}
else p[who].state = 3;
}
p[who].popup = 0;
}
else /* PEACE popup */
if (f) {
agree_to_peace++;
p[who].popup = 0;
if (agree_to_peace >= num_player) {
strcpy(confirm_msg, "peace arrived!");
for (i=0; i<4; i++)
if (p[i].state != 3) {
p[i].popup = 3;
XMapWindow(p[i].dis, p[i].confirm);
}
mode = 3;
}
}
else {
strcpy(confirm_msg, "Absolutely no peace!");
for (i=0; i<4; i++)
if (p[i].state != 3) {
if (p[i].popup)
XUnmapWindow(p[i].dis, p[i].confirm);
p[i].popup = 3;
XMapWindow(p[i].dis, p[i].confirm);
}
mode = 1;
}
break;
}
f = boardtofield(event.xbutton.x, event.xbutton.y, &x, &y);
if (f == QUIT) {
if (mode!=1 || p[who].state!=2 || who==turn) {
strcpy(confirm_msg, "Confirm quit!");
p[who].popup = 2;
XMapWindow(p[who].dis, p[who].confirm);
}
else XBell(p[who].dis, 0);
break;
}
if (f == SURRENDER) {
if (mode==1 && p[who].state==2 && turn==who) {
put_msg(p[who].player_name, "I surrender, spare me!");
if (two) turn = (turn + 2) % 4;
else
do {
turn = (turn+1)%4;
} while (p[turn].state != 2);
XBell(p[turn].dis, 0);
lost_war(who);
}
else XBell(p[who].dis, 0);
break;
}
if (f == PEACE) {
if (mode == 1 && p[who].state == 2 && turn == who) {
for (i=0; i<4; i++)
if (p[i].popup != 0) break;
if (i == 4) {
agree_to_peace = 1;
peace_request(who);
break;
}
}
XBell(p[who].dis, 0);
break;
}
if (f == REDEPLOY) {
if (mode == 0) p[who].state = 1;
else XBell(p[who].dis, 0);
break;
}
if (f == READY) {
if (mode == 0)
if (!valid_deploy(who)) {
strcpy(confirm_msg,"Invalid deploy");
p[who].popup = 3;
XMapWindow(p[who].dis, p[who].confirm);
XBell(p[who].dis, 0);
}
else {
p[who].state = 2;
if (two)
if (p[(who+2)%4].state == 2) i = 4;
else i = 0;
else
for (i=0; i<4; i++)
if (p[i].state != 2) break;
if (i == 4) {
mode = 1;
sprintf(s, "%s moves first", p[turn].player_name);
put_msg("WAR started", s);
send_expose_event();
XBell(p[turn].dis, 0);
}
}
else XBell(p[who].dis, 0);
break;
}
if (f == NEW) {
if (mode == 3) new_game();
else XBell(p[who].dis, 0);
break;
}
/*from now on the button event happened on the board for picking up a node */
if (p[who].state==0 || mode>1) {
XBell(p[who].dis, 0);
break;
}
f = boardtoarr(who, event.xbutton.x, event.xbutton.y, &x, &y);
if (f == -1) {
XBell(p[who].dis, 0);
break;
}
p[who].pick.arr = f;
p[who].pick.x = x;
p[who].pick.y = y;
if (mode == 0)
if (p[who].state == 1)
if (f == RIP && p[who].rip[x][y] != EMPTY)
p[who].pick.value = p[who].rip[x][y];
else if (f == who && arr[f][x][y].value != EMPTY)
p[who].pick.value = arr[f][x][y].value;
else {
XBell(p[who].dis, 0);
break;
}
else {
XBell(p[who].dis, 0);
break;
}
else {
if (turn != who) {
XBell(p[who].dis, 0);
break;
}
if (f==MIDFIELD && mid[x][y].id==who && mid[x][y].value!=EMPTY)
p[who].pick.value = mid[x][y].value;
else if (f>=F0 && f<=F3 && arr[f][x][y].id == who &&
arr[f][x][y].value!=EMPTY && arr[f][x][y].value!=MINE &&
(x!=5 || (y!=1 && y!=3)) )
p[who].pick.value = arr[f][x][y].value;
else {
XBell(p[who].dis, 0);
break;
}
}
p[who].pick.picked = True;
arrtoboard(who, f, x, y, &m, &n);
putnode(who, -1, m, n);
p[who].tmp_cursor = XCreatePixmapCursor(p[who].dis,
p[who].node[p[who].pick.value], p[who].nodemask_pixmap,
&(p[who].fg_color), &(p[who].bg_color),
nodemask_x_hot, nodemask_y_hot);
XDefineCursor(p[who].dis, p[who].win, p[who].tmp_cursor);
break;
case ButtonRelease:
who = whichplayer(event.xbutton.display);
if (who == -1) break;
if (p[who].pick.picked) {
XSetForeground(p[who].dis, p[who].gc, p[who].fg[who]);
p[who].pick.picked = False;
XFreeCursor(p[who].dis, p[who].tmp_cursor);
XDefineCursor(p[who].dis, p[who].win, p[who].cursor);
f = boardtoarr(who, event.xbutton.x, event.xbutton.y, &x, &y);
if (f != -1)
if (mode == 0) {
if (f == RIP && p[who].rip[x][y] == EMPTY)
p[who].rip[x][y] = p[who].pick.value;
else if (f == who && arr[f][x][y].value == EMPTY)
arr[f][x][y].value = p[who].pick.value;
else {
arrtoboard(who, p[who].pick.arr, p[who].pick.x,
p[who].pick.y, &m, &n);
putnode(who, p[who].pick.value, m, n);
XBell(p[who].dis, 0);
break;
}
m = p[who].pick.x;
n = p[who].pick.y;
if (p[who].pick.arr==RIP)
p[who].rip[m][n] = EMPTY;
else arr[who][m][n].value = EMPTY;
arrtoboard(who, f, x, y, &m, &n);
putnode(who, p[who].pick.value, m, n);
}
else {
m = move(who, f, x, y);
if (m == 0) { /* invalid move */
arrtoboard(who, p[who].pick.arr, p[who].pick.x,
p[who].pick.y, &m, &n);
putnode(who, p[who].pick.value, m, n);
XBell(p[who].dis, 0);
}
else {
mode = 4;
sf = p[who].pick.arr;
si = p[who].pick.x;
sj = p[who].pick.y;
df = f;
di = x;
dj = y;
if (sf == MIDFIELD) {
sw = mid[si][sj].id;
sv = mid[si][sj].value;
mid[si][sj].value = EMPTY;
}
else {
sw = arr[sf][si][sj].id;
sv = arr[sf][si][sj].value;
arr[sf][si][sj].value = EMPTY;
}
if (df == MIDFIELD) {
dw = mid[di][dj].id;
dv = mid[di][dj].value;
}
else {
dw = arr[df][di][dj].id;
dv = arr[df][di][dj].value;
}
count = 8;
show_move(m);
}
}
else {
arrtoboard(who, p[who].pick.arr, p[who].pick.x,
p[who].pick.y, &m, &n);
putnode(who, p[who].pick.value, m, n);
XBell(p[who].dis, 0);
}
} /* if (picked == True) */
break;
case KeyPress:
who = whichplayer(event.xkey.display);
if (who == -1) break;
f = XLookupString(&event, &buffer, 1, &keysym, &compose);
if (keysym==XK_Return || keysym==XK_Linefeed) {
talk(who, 2, '_');
break;
}
if (keysym==XK_BackSpace || keysym==XK_Delete) {
talk(who, 1, '_');
break;
}
if (keysym>=XK_space && keysym<=XK_asciitilde)
talk(who, 0, buffer);
break;
case MappingNotify:
XRefreshKeyboardMapping(&event);
break;
default:
break;
} /* switch */
} /* while(1) */
}