v04i030: xmahjongg - (yet another) Mahjongg Game, Part01/04
Dan Heller
argv at island.uu.net
Wed Jun 21 11:03:30 AEST 1989
Submitted-by: Jeff S. Young <jsy at cray.com>
Posting-number: Volume 4, Issue 30
Archive-name: xmahjongg/part01
[ This one doesn't work in color. --argv ]
#! /bin/sh
: This is a shar archive. Extract with sh, not csh.
mkdir Xmahjongg
cd Xmahjongg
mkdir tiles
echo x - ./Imakefile
cat > ./Imakefile << '7623!Funky!Stuff!'
#
# xmahjongg - Mahjongg game
#
# Copyright (c) 1989 by Jeff S. Young. All rights reserved under the
# copyright laws of the United States.
#
LOCAL_LIBRARIES = $(XLIB)
SRCS = xmahjongg.c draw.c event.c initial.c packet.c play.c random.c tiles.c
OBJS = xmahjongg.o draw.o event.o initial.o packet.o play.o random.o tiles.o
ComplexProgramTarget(xmahjongg)
7623!Funky!Stuff!
echo x - ./xmahjongg.h
cat > ./xmahjongg.h << '7623!Funky!Stuff!'
/*
******************************************************************************
* *
* Copyright (c) 1989 by Jeff S. Young. All rights reserved under the *
* copyright laws of the United States. *
* *
******************************************************************************
*/
/*
* Include file for xmahjongg
*/
typedef unsigned char Uchar;
#define TILES 144
#define ROWS 9
#define COLS 13
#define LEVS 6
#define TRUE 1
#define FALSE 0
#define FREE 0
#define USED 1
/*
* Dimensions for boxes, tiles and options
*/
#define TILE_WIDTH 64
#define TILE_HEIGHT 64
#define ICON_WIDTH 64
#define ICON_HEIGHT 64
#define SHADE_WIDTH 4
#define SHADE_HEIGHT 64
#define BOARD_WIDTH (COLS-1)*TILE_WIDTH
#define BOARD_HEIGHT (ROWS-1)*TILE_WIDTH
#define OPTION_WIDTH 48
#define OPTION_HEIGHT 32
#define CURSOR_WIDTH 16
#define CURSOR_HEIGHT 16
#define LETTER_WIDTH 64
#define LETTER_HEIGHT 99
#define WINDOW_WIDTH 1000
#define WINDOW_HEIGHT 800
#define BORDER_WIDTH 2
/*
* Upper left coordinates for items
*/
#define X_TILE 20
#define Y_TILE 181
#define X_DONE 800
#define Y_DONE 100
#define X_SAME 800
#define Y_SAME 30
#define X_QUIT 900
#define Y_QUIT 100
#define X_NEW 900
#define Y_NEW 30
#define X_COPY 800
#define Y_COPY 150
#define X_RIGHTS 800
#define Y_RIGHTS 162
#define X_BOARD 345
#define Y_BOARD 40
#define X_NAMES 260
#define Y_NAMES 55
#define X_SCORE 345
#define Y_SCORE 55
#define in_box(x0, y0, xlen, ylen) \
((x0 <= x_coor) && (x_coor <= x0+xlen) && \
(y0 <= y_coor) && (y_coor <= y0+ylen))
/*
* Tile structure
*/
typedef struct tile Tile;
struct tile {
int x;
int y;
int row;
int col;
int lev;
int state;
Uchar *data;
Uchar *type;
};
/*
* Tournament mode variables and structures
*/
#define XPORT 3857 /* port value for tournaments */
#define MAX_PLAYERS 5
#define MAX_BOARDS 7
typedef struct player Player;
struct player {
char name[12];
char machine[20];
long x;
long y;
long fd;
long type;
long port;
long done;
long quit;
long total;
long tiles[MAX_BOARDS];
long board[MAX_BOARDS];
};
typedef struct packet Packet;
struct packet {
short type;
short port;
short extra;
short tiles;
long board;
char name[12];
};
#define GAME_START 1
#define GAME_PLAY 2
#define GAME_DONE 3
#define GAME_QUIT 4
/*
* X Window stuff
*/
#define FONT "6x10"
#define XMahjonggEvents ButtonPressMask | ExposureMask
7623!Funky!Stuff!
echo x - ./xmahjongg.c
cat > ./xmahjongg.c << '7623!Funky!Stuff!'
/*
******************************************************************************
* *
* Copyright (c) 1989 by Jeff S. Young. All rights reserved under the *
* copyright laws of the United States. *
* *
******************************************************************************
*/
#include <pwd.h>
#include <stdio.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include "xmahjongg.h"
extern int optind;
extern int opterr;
extern char *optarg;
int maxfds = 0;
int playfds = 0;
int num_games = 0;
int done_count = 0;
int tourn_flag = 0;
int num_players = 0;
int keep_playing = 0;
int reverse_video = 0;
int tiles_remaining;
long seed = 0;
long mask[33];
long buffer[2048];
Uchar *tile_data[TILES];
char *display_name = NULL;
Tile *tile1p = NULL;
Tile *tile2p = NULL;
Tile tiles[ROWS][COLS][LEVS];
Player player[MAX_PLAYERS];
Player *mypp = NULL;
Player *pp = NULL;
int screen;
int xcopyright;
int ycopyright;
int fore_color;
int back_color;
int BorderColor;
Font font;
int XGameFD;
GC XGameGC0;
GC XGameGC1;
Cursor cursor;
Pixmap XGameIcon;
Window XGameWindow;
Display *XGameDisplay;
XSizeHints XGameHints;
XFontStruct *XGameFont;
XEvent XGameEvent;
main(argc, argv)
int argc;
char *argv[];
{
get_parameters(argc, argv);
while(1) {
initialize();
keep_playing = 1;
packet_send(GAME_START);
while(keep_playing != 0) {
event_wait();
};
};
}
get_parameters(argc, argv)
int argc;
char *argv[];
{
int i, j, c;
struct passwd *pwp;
char *cp, hostname[20];
Player tmp, *pp = player;
/*
* Parse the arguments.
*/
while ((c = getopt(argc, argv, "rb:d:n:p:")) != EOF) {
switch (c) {
case 'b':
seed = -atoi(optarg);
break;
case 'd':
display_name = optarg;
break;
case 'n':
num_games = atoi(optarg);
break;
case 'r':
reverse_video = 1;
break;
case 'p':
tourn_flag = 1;
if ((cp = strchr(optarg, '@')) == NULL) usage();
strncpy(pp->name, optarg, cp-optarg);
strcpy(pp->machine, cp+1);
num_players++;
pp++;
break;
default:
usage();
break;
};
};
/*
* Set up the tournament if requested.
*/
if (num_players == 0) return(0);
if (num_games == 0) num_games = 3;
if ((pwp = getpwuid(getuid())) == NULL) {
fprintf(stderr, "can't getpwuid\n");
exit(1);
};
gethostname(hostname, 20);
mypp = &player[num_players++];
strcpy(mypp->name, pwp->pw_name);
strcpy(mypp->machine, hostname);
for (i = 0; i < num_players-1; i++) {
for (j = i+1; j < num_players; j++) {
if (strcmp(player[i].name, player[j].name) > 0) {
tmp = player[i];
player[i] = player[j];
player[j] = tmp;
};
};
};
for (i = 0; i < num_players; i++) {
player[i].x = X_SCORE;
player[i].y = Y_SCORE+15*i;
player[i].port = XPORT+i;
player[i].done = -1;
player[i].total = 144*num_games;
for (j = 0; j < MAX_BOARDS; j++) {
player[i].tiles[j] = 2*TILES;
};
if (strcmp(player[i].name, pwp->pw_name) < 0) {
player[i].type = 'C';
} else if (strcmp(player[i].name, pwp->pw_name) > 0) {
player[i].type = 'A';
} else {
mypp = &player[i];
player[i].type = 'M';
};
};
return(0);
}
usage() {
fprintf(stderr, "usage: xmahjongg [-b #] [-n #] [-d display] [-r] ");
fprintf(stderr, "[-p n1 at m1] [...] [-p nx at mx]\n");
exit(1);
}
XError(string)
char *string;
{
fprintf(stderr, "%s\n", string);
exit(1);
}
7623!Funky!Stuff!
echo x - ./initial.c
cat > ./initial.c << '7623!Funky!Stuff!'
/*
******************************************************************************
* *
* Copyright (c) 1989 by Jeff S. Young. All rights reserved under the *
* copyright laws of the United States. *
* *
******************************************************************************
*/
#include <netdb.h>
#include <stdio.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/cursorfont.h>
#include "xmahjongg.h"
#include "tilenames.h"
extern int errno;
extern int maxfds;
extern int playfds;
extern int done_count;
extern int tourn_flag;
extern int num_players;
extern int reverse_video;
extern int tiles_remaining;
extern long seed;
extern long mask[];
extern long buffer[];
extern Uchar *tile_data[];
extern char *display_name;
extern Tile *tile1p, *tile2p;
extern Tile tiles[ROWS][COLS][LEVS];
extern Player player[MAX_PLAYERS];
extern Player *pp, *mypp;
extern Packet packet;
extern int screen;
extern int xcopyright;
extern int ycopyright;
extern int fore_color;
extern int back_color;
extern int BorderColor;
extern Font font;
extern int XGameFD;
extern GC XGameGC0;
extern GC XGameGC1;
extern Cursor cursor;
extern Pixmap XGameIcon;
extern Window XGameWindow;
extern Display *XGameDisplay;
extern XSizeHints XGameHints;
extern XEvent XGameEvent;
extern XFontStruct *XGameFont;
XWMHints XGameWMHints;
int initial_flag = 0;
char copy[] = " (c) 1989 by Jeff Young. ";
char rights[] = " All rights reserved. ";
char copyright[] = " Copyright (c) 1989 by Jeff Young (exceptions). All rights reserved. ";
initialize() {
initialize_data();
initialize_pool();
initialize_tiles();
initialize_socket();
initialize_window();
initialize_display();
return(0);
}
initialize_data() {
int i, j, k;
done_count = 0;
tiles_remaining = TILES;
if (initial_flag != 0) return(0);
/*
* Initialize the bitmap pointers for shuffling into the pool.
*/
tile_data[ 0] = number_0_bits;
tile_data[ 1] = number_1_bits;
tile_data[ 2] = number_2_bits;
tile_data[ 3] = number_3_bits;
tile_data[ 4] = number_4_bits;
tile_data[ 5] = number_5_bits;
tile_data[ 6] = number_6_bits;
tile_data[ 7] = number_7_bits;
tile_data[ 8] = number_8_bits;
tile_data[ 9] = number_9_bits;
tile_data[10] = dragon_green_bits;
tile_data[11] = dragon_white_bits;
tile_data[12] = dragon_red_bits;
tile_data[13] = season_spring_bits;
tile_data[14] = season_summer_bits;
tile_data[15] = season_autumn_bits;
tile_data[16] = season_winter_bits;
tile_data[17] = plant_bamboo_bits;
tile_data[18] = plant_orchid_bits;
tile_data[19] = plant_plum_bits;
tile_data[20] = plant_mum_bits;
tile_data[21] = direction_north_bits;
tile_data[22] = direction_south_bits;
tile_data[23] = direction_east_bits;
tile_data[24] = direction_west_bits;
tile_data[25] = circle_1_bits;
tile_data[26] = circle_2_bits;
tile_data[27] = circle_3_bits;
tile_data[28] = circle_4_bits;
tile_data[29] = circle_5_bits;
tile_data[30] = circle_6_bits;
tile_data[31] = circle_7_bits;
tile_data[32] = circle_8_bits;
tile_data[33] = circle_9_bits;
tile_data[34] = bamboo_1_bits;
tile_data[35] = bamboo_2_bits;
tile_data[36] = bamboo_3_bits;
tile_data[37] = bamboo_4_bits;
tile_data[38] = bamboo_5_bits;
tile_data[39] = bamboo_6_bits;
tile_data[40] = bamboo_7_bits;
tile_data[41] = bamboo_8_bits;
tile_data[42] = bamboo_9_bits;
tile_data[43] = ideograph_1_bits;
tile_data[44] = ideograph_2_bits;
tile_data[45] = ideograph_3_bits;
tile_data[46] = ideograph_4_bits;
tile_data[47] = ideograph_5_bits;
tile_data[48] = ideograph_6_bits;
tile_data[49] = ideograph_7_bits;
tile_data[50] = ideograph_8_bits;
tile_data[51] = ideograph_9_bits;
return(0);
}
initialize_pool() {
int i, j, k;
int seed1, seed2;
long save;
struct timeval tv;
struct timezone tz;
if (seed == 0) {
gettimeofday(&tv, &tz);
seed = 1 + (tv.tv_sec%100000);
} else if (seed < 0) {
seed = (-seed)%100000;
} else {
seed = 1 + (random_next(seed)%100000);
};
random_init(seed);
/*
* Place the circle, bamboo, and ideograph tiles in the pool
*/
for (j = 0, k = 0; j < 4; j++) {
for (i = 21; i <= 51; i++) {
buffer[k++] = i;
};
};
/*
* Place the dragon tiles in the pool
*/
for (j = 0; j < 4; j++) {
for (i = 10; i <= 12; i++) {
buffer[k++] = i;
};
};
/*
* Place the season and plant tiles in the pool
*/
for (i = 13; i <= 20; i++) {
buffer[k++] = i;
};
/*
* Shuffle the pool of tiles
*/
for (i = 0; i < 16384; i++) {
seed1 = (random_next() & 0xfffffff)%TILES;
seed2 = (random_next() & 0xfffffff)%TILES;
save = buffer[seed1];
buffer[seed1] = buffer[seed2];
buffer[seed2] = save;
};
return(0);
}
initialize_tiles() {
int i, j, k;
/*
* Mark the tiles as free
*/
for (i = 0; i < ROWS; i++) {
for (j = 0; j < COLS; j++) {
for (k = 0; k < LEVS; k++) {
tiles[i][j][k].state = FREE;
};
};
};
/*
* Mark the tiles on level 0 that are in use
*/
tiles[0][1][0].state = USED;
tiles[0][2][0].state = USED;
tiles[0][3][0].state = USED;
/*
* Mark the tiles on level 1 that are in use
*/
for (i = 3; i<= 6; i++) {
for (j = 2; j <= 11; j++) {
tiles[i][j][1].state = USED;
};
};
for (j = 1; j <= 12; j++) {
tiles[1][j][1].state = USED;
tiles[8][j][1].state = USED;
};
for (j = 3; j <= 10; j++) {
tiles[2][j][1].state = USED;
tiles[7][j][1].state = USED;
};
tiles[4][01][1].state = USED;
tiles[4][12][1].state = USED;
tiles[5][01][1].state = USED;
tiles[5][12][1].state = USED;
/*
* Mark the tiles on level 2 that are in use
*/
for (i = 2; i <= 7; i++) {
for (j = 4; j <= 9; j++) {
tiles[i][j][2].state = USED;
};
};
/*
* Mark the tiles on level 3 that are in use
*/
for (i = 3; i <= 6; i++) {
for (j = 5; j <= 8; j++) {
tiles[i][j][3].state = USED;
};
};
/*
* Mark the tiles on level 4 that are in use
*/
for (i = 4; i <= 5; i++) {
for (j = 6; j <= 7; j++) {
tiles[i][j][4].state = USED;
};
};
/*
* Mark the tiles on level 5 that are in use
*/
tiles[0][0][5].state = USED;
/*
* Setup the tiles by assigning them their various pictures.
*/
for (i = 0; i < ROWS; i++) {
for (j = 0; j < COLS; j++) {
for (k = 0; k < LEVS; k++) {
if (tiles[i][j][k].state == USED) {
setup_tile(i, j, k);
};
};
};
};
/*
* Set the tile pointers to NULL for starters.
*/
tile1p = NULL;
tile2p = NULL;
return(0);
}
initialize_socket() {
int i, s;
int namelen;
char on = 1;
struct sockaddr_in name;
struct hostent *hp, *gethostbyname();
if (tourn_flag != 1) return(0);
printf("attempting connections\n");
/*
* Attempt connects
*/
for (i = 0, pp = player; i < num_players; i++, pp++) {
if (pp->type != 'C') continue;
namelen = sizeof(name);
name.sin_family = AF_INET;
name.sin_port = htons(pp->port);
hp = gethostbyname(pp->machine);
bcopy(hp->h_addr, (char *)&name.sin_addr, hp->h_length);
while (1) {
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
sleep(1);
} else if (connect(s, (char *)&name, namelen) < 0) {
close(s);
sleep(1);
} else {
pp->fd = s;
break;
};
};
};
/*
* Attempt accepts
*/
name.sin_family = AF_INET;
name.sin_port = htons(mypp->port);
name.sin_addr.s_addr = 0;
namelen = sizeof(name);
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
fprintf(stderr, "can't open socket (%d)\n", errno);
exit(1);
} else if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, 1) < 0) {
fprintf(stderr, "can't reset socket (%d)\n", errno);
exit(1);
} else if (bind(s, (char *)&name, namelen) < 0) {
fprintf(stderr, "can't bind socket (%d)\n", errno);
exit(1);
} else if (listen(s, 5) < 0) {
fprintf(stderr, "can't listen socket (%d)\n", errno);
exit(1);
};
for (i = 0, pp = player; i < num_players; i++, pp++) {
if (pp->type != 'A') continue;
namelen = sizeof(name);
if ((pp->fd = accept(s, (char *)&name, &namelen)) < 0) {
sleep(1);
};
};
for (i = 0, pp = player; i < num_players; i++, pp++) {
if (pp->type != 'M') playfds |= (1 << pp->fd);
};
tourn_flag = 2;
printf("connections established\n");
return(0);
}
initialize_window() {
int init_x, init_y;
/*
* Only initialize the window if the initial_flag is zero
*/
if (initial_flag != 0) {
XClearWindow(XGameDisplay, XGameWindow);
return(0);
};
/*
* Open up the display.
*/
if ((XGameDisplay = XOpenDisplay(display_name)) == NULL) {
XError("no display");
};
screen = DefaultScreen(XGameDisplay);
XGameFD = ConnectionNumber(XGameDisplay);
if (reverse_video == 0) {
fore_color = WhitePixel(XGameDisplay, screen);
back_color = BlackPixel(XGameDisplay, screen);
} else {
fore_color = BlackPixel(XGameDisplay, screen);
back_color = WhitePixel(XGameDisplay, screen);
};
/*
* Get the font for text printing
*/
font = XLoadFont(XGameDisplay, FONT);
XGameFont = XQueryFont(XGameDisplay, font);
/*
* Define an icon for the game
*/
XGameIcon = XCreateBitmapFromData(
XGameDisplay, DefaultRootWindow(XGameDisplay),
icon_tiles_bits, ICON_WIDTH, ICON_HEIGHT);
/*
* Open the main window.
*/
init_x = (DisplayWidth(XGameDisplay, screen)-WINDOW_WIDTH)/2;
init_y = (DisplayHeight(XGameDisplay, screen)-WINDOW_HEIGHT)/2;
XGameWindow = XCreateSimpleWindow(
XGameDisplay, DefaultRootWindow(XGameDisplay),
init_x, init_y, WINDOW_WIDTH, WINDOW_HEIGHT,
BORDER_WIDTH, fore_color, back_color);
if (XGameWindow == 0) XError("no window");
XSetStandardProperties(
XGameDisplay, XGameWindow,
"XMahjongg", NULL,
XGameIcon, NULL, 0,
&XGameHints);
XGameGC0 = XCreateGC(XGameDisplay, XGameWindow, 0, 0);
XGameGC1 = XCreateGC(XGameDisplay, XGameWindow, 0, 0);
XSetForeground(XGameDisplay, XGameGC0, fore_color);
XSetBackground(XGameDisplay, XGameGC0, back_color);
XSetForeground(XGameDisplay, XGameGC1, back_color);
XSetBackground(XGameDisplay, XGameGC1, fore_color);
XSetFont(XGameDisplay, XGameGC0, font);
XSetFont(XGameDisplay, XGameGC1, font);
/*
* Select window exposure events to see if the contents of the window
* have been erased or altered.
*/
XSelectInput(XGameDisplay, XGameWindow, XMahjonggEvents);
XMapRaised(XGameDisplay, XGameWindow);
XNextEvent(XGameDisplay, &XGameEvent);
/*
* Define the cursor for the game
*/
cursor = XCreateFontCursor(XGameDisplay, XC_left_ptr);
XDefineCursor(XGameDisplay, XGameWindow, cursor);
/*
* Map game window to screen.
*/
XMapRaised(XGameDisplay, XGameWindow);
/*
* Display the game name and copyright notice
*/
draw_line(0, 200, 1000, 200);
draw_letter(letter_x_bits, 42, 50);
draw_letter(letter_m_bits, 148, 50);
draw_letter(letter_a_bits, 254, 50);
draw_letter(letter_h_bits, 360, 50);
draw_letter(letter_j_bits, 466, 50);
draw_letter(letter_o_bits, 572, 50);
draw_letter(letter_n_bits, 678, 50);
draw_letter(letter_g_bits, 784, 50);
draw_letter(letter_g_bits, 890, 50);
xcopyright = (1000 - strlen(copyright)*XGameFont->max_bounds.width)/2;
ycopyright = (200 - XGameFont->max_bounds.ascent - 10);
draw_string(copyright, xcopyright, ycopyright, XGameGC1);
/*
* Display the tiles on the screen before the start of the game. Order:
* dragons, seasons, plants, directions, circles, bamboos, ideographs
*
*/
draw_data();
XFlush(XGameDisplay);
sleep(5);
/*
* Blank out the screen prior to painting it with the game board.
*/
XClearWindow(XGameDisplay, XGameWindow);
XFlush(XGameDisplay);
/*
* Find the maximum file descriptor for the select system call and set
* the initialization flag.
*/
initial_flag++;
if ((maxfds = getdtablesize()) > 32) maxfds = 32;
return(0);
}
initialize_display() {
int x, y;
int i, j, k;
char ascii[80];
char string[80];
/*
* Set up the mask array for future tile drawing
*/
for (i = 1, mask[0] = 0; i < 33; i++) {
mask[i] = 2*mask[i-1] + 1;
};
/*
* Display the initial tile setup
*/
draw_tile(0, 3);
draw_tile(0, 2);
for (j = COLS-1; j >= 0; j--) {
for (i = 1; i < ROWS; i++) {
draw_tile(i, j);
};
};
draw_tile(0, 1);
draw_tile(0, 0);
/*
* Display the count of remaining tiles and the board number
*/
sprintf(string, "Board number : %d", seed);
draw_string(string, 55, 55, XGameGC0);
draw_count(number_0_bits);
/*
* Draw the option boxes
*/
draw_line(0, 200, 1000, 200);
draw_option(done_bits, X_DONE, Y_DONE, done_count);
draw_option(same_bits, X_SAME, Y_SAME, 0);
draw_option(quit_bits, X_QUIT, Y_QUIT, 0);
draw_option(new_bits, X_NEW, Y_NEW, 0);
/*
* Draw the small copyright notices
*/
ycopyright = XGameFont->ascent + XGameFont->descent + 1;
draw_string(copy, X_COPY, Y_COPY, XGameGC1);
draw_string(rights, X_COPY, Y_COPY+ycopyright, XGameGC1);
XFlush(XGameDisplay);
/*
* If in tournament mode, then reprint the current scores.
*/
if (tourn_flag != 0) {
for (i = 0, pp = player; i < num_players; i++, pp++) {
draw_user(pp, GAME_START);
};
};
return(0);
}
setup_tile(row, col, lev)
int row, col, lev;
{
Uchar *spring_tile = tile_data[13];
Uchar *winter_tile = tile_data[16];
Uchar *bamboo_tile = tile_data[17];
Uchar *mum_tile = tile_data[20];
Tile *tp = &tiles[row][col][lev];
/*
* Set up the values for positioning and tile picture
*/
tp->row = row;
tp->col = col;
tp->lev = lev;
tp->x = X_TILE + (col*TILE_WIDTH) + (lev*SHADE_WIDTH);
tp->y = Y_TILE + (row*TILE_WIDTH) - (lev*SHADE_WIDTH);
tp->data = tile_data[get_tile()];
if ((spring_tile <= tp->data) && (tp->data <= winter_tile)) {
tp->type = spring_tile;
} else if ((bamboo_tile <= tp->data) && (tp->data <= mum_tile)) {
tp->type = bamboo_tile;
} else {
tp->type = tp->data;
};
/*
* Special positioning for the end tiles and the top tile
*/
if (lev == 0) {
if (col == 1) {
tp->x = X_TILE + 4;
tp->y = Y_TILE + (04*TILE_WIDTH) + 32;
} else if (col == 2) {
tp->x = X_TILE + (13*TILE_WIDTH) + 4;
tp->y = Y_TILE + (04*TILE_WIDTH) + 32;
} else if (col == 3) {
tp->x = X_TILE + (14*TILE_WIDTH) + 4;
tp->y = Y_TILE + (04*TILE_WIDTH) + 32;
};
} else if (lev == 5) {
tp->x = X_TILE + (06*TILE_WIDTH) + 52;
tp->y = Y_TILE + (04*TILE_WIDTH) + 12;
};
return(0);
}
get_tile() {
int i, j;
i = random_next()%TILES;
j = ((random_next()%2) == 0) ? 1 : -1;
/*
* Walk through the tile pool looking for an unused tile
*/
while (buffer[i] == 0) {
i = (i+j)%TILES;
if (i < 0) i = TILES-1;
};
j = buffer[i];
buffer[i] = 0;
return(j);
}
7623!Funky!Stuff!
echo x - ./event.c
cat > ./event.c << '7623!Funky!Stuff!'
/*
******************************************************************************
* *
* Copyright (c) 1989 by Jeff S. Young. All rights reserved under the *
* copyright laws of the United States. *
* *
******************************************************************************
*/
#include <stdio.h>
#include <signal.h>
#include <sys/time.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include "xmahjongg.h"
#include "tilenames.h"
extern int seed;
extern int maxfds;
extern int playfds;
extern int num_games;
extern int done_count;
extern int tourn_flag;
extern int num_players;
extern int keep_playing;
extern int tiles_remaining;
extern long buffer[];
extern long game_board[];
extern Uchar *tile_data[];
extern Tile *tile1p, *tile2p;
extern Tile tiles[ROWS][COLS][LEVS];
extern Player player[MAX_PLAYERS];
extern Player *pp, *mypp;
extern int screen;
extern int fore_color;
extern int back_color;
extern int BorderColor;
extern Font font;
extern int XGameFD;
extern GC XGameGC0;
extern GC XGameGC1;
extern Window XGameWindow;
extern Display *XGameDisplay;
extern XSizeHints XGameHints;
extern XEvent XGameEvent;
extern XFontStruct *XGameFont;
int x_coor;
int y_coor;
event_wait() {
int readfds;
int events = 0;
int exposes = 0;
XEvent event;
int i;
/*
* If there are no events pending, then sleep until one occurs.
*/
wait_event:
if ((events = XEventsQueued(XGameDisplay, QueuedAfterReading)) == 0) {
readfds = (1 << XGameFD) | playfds;
i=select(maxfds, &readfds, NULL, NULL, NULL);
};
/*
* An event has occurred. Let's process it.
*/
if ((readfds & playfds) != 0) {
event_packet(readfds);
};
next_event:
if (events == 0) goto wait_event;
XNextEvent(XGameDisplay, &XGameEvent);
switch (XGameEvent.type) {
case Expose:
if (XGameEvent.xexpose.count != 0) goto next_event;
event_paint();
break;
case ButtonPress:
event_button();
break;
default:
break;
};
return(0);
}
event_packet(readfds)
int readfds;
{
int i;
for (i = 0, pp = player; i < num_players; i++, pp++) {
if (pp->type == 'M') continue;
if ((readfds & (1 << pp->fd)) != 0) {
packet_recv(pp->fd);
};
};
return(0);
}
event_paint() {
XClearWindow(XGameDisplay, XGameWindow);
initialize_display();
return(0);
}
event_button() {
int i, j, k;
i = XGameFont->ascent;
j = XGameFont->descent;
k = (200-(Y_COPY+i+j+1))/2 + (i+j+1)/2;
XClearArea(
XGameDisplay, XGameWindow,
800, 200-k-1, 199, k, False);
XFlush(XGameDisplay);
x_coor = XGameEvent.xbutton.x;
y_coor = XGameEvent.xbutton.y;
if (in_box(X_NEW, Y_NEW, OPTION_WIDTH, OPTION_HEIGHT)) {
event_new();
} else if (in_box(X_DONE, Y_DONE, OPTION_WIDTH, OPTION_HEIGHT)) {
event_done();
} else if (in_box(X_SAME, Y_SAME, OPTION_WIDTH, OPTION_HEIGHT)) {
event_same();
} else if (in_box(X_QUIT, Y_QUIT, OPTION_WIDTH, OPTION_HEIGHT)) {
event_quit();
} else {
event_tile();
};
return(0);
}
event_new() {
if (tourn_flag != 0) {
if (mypp->done < num_games-1) {
keep_playing = 0;
XClearWindow(XGameDisplay, XGameWindow);
} else {
XBell(XGameDisplay, 100);
XFlush(XGameDisplay);
};
} else {
keep_playing = 0;
XClearWindow(XGameDisplay, XGameWindow);
};
return(0);
}
event_same() {
if (num_games == 0) {
seed = -seed;
keep_playing = 0;
XClearWindow(XGameDisplay, XGameWindow);
} else {
XBell(XGameDisplay, 100);
XFlush(XGameDisplay);
};
return(0);
}
event_done() {
int i, j, k;
int matches = 0;
char string[80];
Tile *t1p, *t2p;
draw_option(done_bits, X_DONE, Y_DONE, done_count);
for(i = 0, t1p = &tiles[0][0][0]; i < ROWS*COLS*LEVS-1; i++, t1p++) {
if (t1p->state != USED) continue;
if (not_free(t1p->row, t1p->col, t1p->lev)) continue;
for(j = i+1, t2p = t1p+1; j < ROWS*COLS*LEVS; j++, t2p++) {
if (t2p->state != USED) continue;
if (not_free(t2p->row, t2p->col, t2p->lev)) continue;
if (t1p->type == t2p->type) matches++;
};
};
i = XGameFont->ascent;
j = XGameFont->descent;
k = (200-(Y_COPY+i+j+1))/2 - (i+j)/2;
sprintf(string, " Matches remaining = %3d ", matches);
draw_string(string, 800, 200-k, XGameGC1);
if (done_count == 0) {
done_count = tiles_remaining;
packet_send(GAME_DONE);
};
return(0);
}
event_quit() {
packet_send(GAME_QUIT);
exit(0);
}
event_tile() {
int i, j, k = -1;
Tile *tp;
Tile *t0p = &tiles[0][0][5];
Tile *t1p = &tiles[0][1][0];
Tile *t2p = &tiles[0][2][0];
Tile *t3p = &tiles[0][3][0];
if (in_box(X_TILE, Y_TILE, COLS*TILE_WIDTH, ROWS*TILE_HEIGHT)) {
for (k = LEVS-1; k >= 0; k--) {
i = (y_coor - Y_TILE + (4*k))/TILE_WIDTH;
j = (x_coor - X_TILE - (4*k))/TILE_WIDTH;
if ((i < 0) || (i >= ROWS)) continue;
if ((j < 0) || (j >= COLS)) continue;
if (tiles[i][j][k].state == USED) break;
};
};
if (in_box(t0p->x, t0p->y, TILE_WIDTH, TILE_HEIGHT)) {
if (tiles[0][0][5].state == USED) { i = 0; j = 0; k = 5; };
} else if (in_box(t1p->x, t1p->y, TILE_WIDTH, TILE_HEIGHT)) {
if (tiles[0][1][0].state == USED) { i = 0; j = 1; k = 0; };
} else if (in_box(t2p->x, t2p->y, TILE_WIDTH, TILE_HEIGHT)) {
if (tiles[0][2][0].state == USED) { i = 0; j = 2; k = 0; };
} else if (in_box(t3p->x, t3p->y, TILE_WIDTH, TILE_HEIGHT)) {
if (tiles[0][3][0].state == USED) { i = 0; j = 3; k = 0; };
};
if (k >= 0) {
play_tile(i, j, k);
} else {
XBell(XGameDisplay, 100);
XFlush(XGameDisplay);
};
return(0);
}
7623!Funky!Stuff!
echo x - ./xmahjongg.mk
cat > ./xmahjongg.mk << '7623!Funky!Stuff!'
#
#*****************************************************************************
# *
# Copyright (c) 1989 by Jeff S. Young. All rights reserved under the *
# copyright laws of the United States. *
# *
#*****************************************************************************
#
#
# makefile for xmahjongg
#
XINC = /usr/include
XLIB = /usr/lib/libX11.a
CFLAGS = -O -I$(XINC)
BIN = /usr/opus/jsy/bin
OBJS = xmahjongg.o draw.o event.o initial.o packet.o play.o random.o tiles.o
all: xmahjongg
xmahjongg: $(OBJS)
$(CC) $(CFLAGS) -o xmahjongg $(OBJS) $(XLIB)
install: all
cp xmahjongg $(BIN)
chmod 711 $(BIN)/xmahjongg
clean:
rm -f xmahjongg *.o
7623!Funky!Stuff!
echo x - ./draw.c
cat > ./draw.c << '7623!Funky!Stuff!'
/*
******************************************************************************
* *
* Copyright (c) 1989 by Jeff S. Young. All rights reserved under the *
* copyright laws of the United States. *
* *
******************************************************************************
*/
#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <sys/time.h>
#include "xmahjongg.h"
extern int num_games;
extern int done_count;
extern int tiles_remaining;
extern long seed;
extern long buffer[];
extern Uchar *tile_data[];
extern Tile *tile1p, *tile2p;
extern Tile tiles[ROWS][COLS][LEVS];
extern Player player[];
extern int BorderColor;
extern int fore_color;
extern int back_color;
extern int screen;
extern Font font;
extern int XGameFD;
extern GC XGameGC0;
extern GC XGameGC1;
extern Window XGameWindow;
extern Display *XGameDisplay;
extern XSizeHints XGameHints;
extern XEvent XGameEvent;
long *board_data;
long *digit_data;
XImage *XGameTileImage;
XImage *XGameBoardImage;
XImage *XGameCountImage;
XImage *XGameLetterImage;
XImage *XGameOptionImage;
#define DRAW_NAME(pp) { \
int xpos = X_NAMES; \
int ypos = Y_NAMES + 15*(pp-player); \
sprintf((char *)buffer, "%8.8s", pp->name); \
draw_string((char *)buffer, xpos, ypos, XGameGC0); \
}
#define DRAW_BOARD(pp, pos) { \
sprintf((char *)buffer, "%5.5d", pp->board[pos]); \
draw_string((char *)buffer, X_BOARD+50*pos, Y_BOARD, XGameGC0); \
}
#define DRAW_SCORE(pp, pos) { \
int score = pp->tiles[pos]; \
if (score < 0) score *= -1; \
userGC = (pp->tiles[pos] > 0) ? XGameGC0 : XGameGC1; \
sprintf((char *)buffer, " %3.3d ", score); \
draw_string((char *)buffer, pp->x+50*pos, pp->y, userGC); \
}
#define DRAW_TOTAL(pp, pos) { \
sprintf((char *)buffer, "TOTAL"); \
draw_string((char *)buffer, X_BOARD+50*pos, Y_BOARD, XGameGC0); \
userGC = (pp->quit == 0) ? XGameGC0 : XGameGC1; \
sprintf((char *)buffer, " %3.3d ", pp->total); \
draw_string((char *)buffer, pp->x+50*pos, pp->y, userGC); \
}
draw_user(pp, type)
Player *pp;
int type;
{
int i;
char buffer[20];
GC userGC;
if (type == GAME_START) {
DRAW_NAME(pp);
for (i = 0; i < MAX_BOARDS; i++) {
if (pp->tiles[i] > TILES) break;
DRAW_BOARD(pp, i);
DRAW_SCORE(pp, i);
};
DRAW_TOTAL(pp, num_games);
} else if (type == GAME_PLAY) {
DRAW_BOARD(pp, pp->done);
DRAW_SCORE(pp, pp->done);
DRAW_TOTAL(pp, num_games);
} else if (type == GAME_DONE) {
DRAW_BOARD(pp, pp->done);
DRAW_SCORE(pp, pp->done);
} else if (type == GAME_QUIT) {
DRAW_BOARD(pp, pp->done);
DRAW_SCORE(pp, pp->done);
DRAW_TOTAL(pp, num_games);
} else {
fprintf(stderr, "bad draw_user type (%d)\n", type);
exit(1);
};
return(0);
}
draw_line(x0, y0, x1, y1) {
XDrawLine(XGameDisplay, XGameWindow, XGameGC0, x0, y0, x1, y1);
return(0);
}
draw_data() {
int i, x, y;
int w = TILE_WIDTH;
int h = TILE_HEIGHT;
/*
* Set up the tile image holder
*/
XGameTileImage = XCreateImage(
XGameDisplay, DefaultVisual(XGameDisplay, screen),
1, XYBitmap, 0, 0, TILE_WIDTH, TILE_HEIGHT, 8, 0);
XGameTileImage->bitmap_bit_order = MSBFirst;
XGameTileImage->byte_order = MSBFirst;
/*
* Display the tiles on the screen before the start of the game. Order:
* dragons, seasons, plants, directions, circles, bamboos, ideographs.
* The 'if' statement below is just a way to figure out the x and y
* coordinates of the tiles.
*
*/
for (i = 10; i <= 51; i++) {
if ((10 <= i) && (i <= 12)) {
x = 2*(i%9);
y = 230;
} else if ((13 <= i) && (i <= 24)) {
x = (2*i + 7)%8;
y = 310 + 80*((i-13)/4);
} else if ((25 <= i) && (i <= 51)) {
x = (i+2)%9;
y = 310 + 80*((i+2)/9);
};
x = 42 + 106*x;
XGameTileImage->data = (char *)tile_data[i];
draw_image(XGameTileImage, x, y, w, h, XGameGC0);
};
return(0);
}
draw_tile(row, col)
int row, col;
{
int i, k;
GC imageGC;
Tile *tp = NULL;
Tile *up = NULL;
/*
* If this tile is already taken, don't draw it
*/
if ((row == 0) && (col == 0)) {
k = 5;
} else if ((row == 0) && (col == 1)) {
k = 0;
} else if ((row == 0) && (col == 2)) {
k = 0;
} else if ((row == 0) && (col == 3)) {
k = 0;
} else {
for (k = 1; k < LEVS-1; k++) {
tp = &tiles[row][col][k];
if (tp->state != USED) break;
};
if (k-- == 1) return(0);
};
tp = &tiles[row][col][k];
if (tp->state != USED) return(0);
imageGC = (tp != tile1p) ? XGameGC0 : XGameGC1;
/*
* Draw the tile face
*/
XGameTileImage->data = (char *)tp->data;
draw_image(XGameTileImage, tp->x, tp->y,
TILE_WIDTH, TILE_HEIGHT, imageGC);
if ((k == 0) || (k == 5)) k = 1;
for (i = 0; i < 4*k; i++) {
draw_line(tp->x-i-1,tp->y+i+1,tp->x-i-1,tp->y+i+64);
draw_line(tp->x-i-1,tp->y+i+64,tp->x-i+63,tp->y+i+64);
};
XFlush(XGameDisplay);
return(0);
}
draw_count(data)
long *data;
{
int digit, i, x, y;
int count = (done_count != 0) ? done_count : tiles_remaining;
if (XGameCountImage == 0) {
digit_data = data;
XGameCountImage = XCreateImage(
XGameDisplay, DefaultVisual(XGameDisplay, screen),
1, XYBitmap, 0, 0, TILE_WIDTH, TILE_HEIGHT, 8, 0);
XGameCountImage->bitmap_bit_order = MSBFirst;
XGameCountImage->byte_order = MSBFirst;
};
for (i = 0, x = 183, y = 100; i < 3; i++, x -= 64) {
digit = count%10;
/* adjust_data(buffer, digit_data+(128*digit), 128); */
XGameCountImage->data = (char *)(digit_data+(128*digit));
XPutImage(
XGameDisplay, XGameWindow, XGameGC0, XGameCountImage,
0, 0, x, y, TILE_WIDTH, TILE_HEIGHT);
count /= 10;
};
XFlush(XGameDisplay);
return(0);
}
draw_image(image, x, y, width, height, imageGC)
XImage *image;
int x, y;
int width, height;
GC imageGC;
{
XPutImage(
XGameDisplay, XGameWindow, imageGC,
image, 0, 0, x, y, width, height);
return(0);
}
draw_letter(data, x, y)
char *data;
int x, y;
{
if (XGameLetterImage == 0) {
XGameLetterImage = XCreateImage(
XGameDisplay, DefaultVisual(XGameDisplay, screen),
1, XYBitmap, 0, 0, LETTER_WIDTH, LETTER_HEIGHT, 8, 0);
XGameLetterImage->bitmap_bit_order = MSBFirst;
XGameLetterImage->byte_order = MSBFirst;
};
XGameLetterImage->data = data;
XPutImage(
XGameDisplay, XGameWindow, XGameGC1, XGameLetterImage,
0, 0, x, y, LETTER_WIDTH, LETTER_HEIGHT);
return(0);
}
draw_option(data, x, y, shade)
char *data;
int x, y, shade;
{
GC optGC = (shade == 0) ? XGameGC0 : XGameGC1;
if (XGameOptionImage == 0) {
XGameOptionImage = XCreateImage(
XGameDisplay, DefaultVisual(XGameDisplay, screen),
1, XYBitmap, 0, 0, OPTION_WIDTH, OPTION_HEIGHT, 8, 0);
XGameOptionImage->bitmap_bit_order = MSBFirst;
XGameOptionImage->byte_order = MSBFirst;
};
XGameOptionImage->data = data;
draw_image(XGameOptionImage, x, y, OPTION_WIDTH, OPTION_HEIGHT, optGC);
XFlush(XGameDisplay);
return(0);
}
draw_string(data, x, y, imageGC)
char *data;
int x, y;
GC imageGC;
{
XDrawImageString(
XGameDisplay, XGameWindow, imageGC,
x, y, data, strlen(data));
XFlush(XGameDisplay);
return(0);
}
7623!Funky!Stuff!
echo x - ./xmahjongg.6
cat > ./xmahjongg.6 << '7623!Funky!Stuff!'
.\" Copyright 1989 Jeff S. Young
.\"
.\" Permission is given to copy and distribute for non-profit purposes.
.\"
.TH XMAHJONGG 6 "07 June 1989"
.SH NAME
xmahjongg \- X11R3 verion of the solitaire mahjongg game
.SH SYNOPSIS
.B xmahjongg
[ \fB-b \fI###\fR ] [ \fB-n \fI###\fR ] [ \fB-r\fR ]
[ \fB-d \fIdisplay\fR ]
[ \fB-p \fIname at machine\fR ] [ \fI...\fR ] [ \fB-p \fIname at machine\fR ]
.SH DESCRIPTION
.I Mah jongg
is an ancient chinese game usually played by four players with tiles similar
to dominos. This is an X windows version for the solitaire game originally
seen on the PC and later ported to SunView. It also has a new tournament
option.
.SH THEORY OF PLAY
The object of the game is to remove all the tiles from the board. Tiles are
removed in by matching two identical tiles which have either an open left
edge or open right edge. The only exception to this rule is that any open
"flower" tile (bamboo, orchid, plum, or chrysanthemum) matches any other
open "flower" tile and any open "season" tile (spring, summer, autumn, or
winter) matches any other open "season" tile.
.PP
The display has two distinct areas: the playing field and the control field.
.PP
The bottom area is the playing field. To remove a pair of tiles, click a mouse
button on a tile (which will light up) and then click a mouse button on the
matching tile. At this point, both tiles will disappear from the board. If
after selecting the first tile, you decide that you don't wish to play that
tile, simply reclick the button on the tile.
.PP
The top area is the control field. The board number and the number of remaining
tiles are on the left side of the board. The right side has some options
for controlling the game. To select an option, click a mouse button on it.
\fI SAME \fR
Start the same game again. This option is disabled in tournament mode.
\fI NEW \fR
Start a new game.
\fI DONE \fR
Check to see if you missed any matches. When you think that you don't have any
more matches left, clicking "DONE" will tell you the number of matches which
you missed. If you missed some, you can continue play, but your score will
not change. The "DONE" field stays high-lighted to show that you have already
tried this option.
\fI QUIT \fR
Exit the game.
.SH OPTIONS
.IP \fB\-b \fR
Start the game with board number ###. Board numbers range from 1 to 99999.
.IP \fB\-d \fR
Use the given display name instead of the current default.
.IP \fB\-n \fR
Number of games to play in tournament mode. See below.
.IP \fB\-r\fR
Reverse video mode.
.IP \fB\-p \fR
Set up a tournament with the specified player on the specified machine.
.SH TOURNAMENT MODE
Using the [ \fI -p \fR ] parameter starts a tournament. In this mode
several players can compete on a series of boards. The players should agree
in advance on a starting board number. The default tournament is three games,
although this can be changed with the [ \fI -n \fR ] parameter. If another
player clicks "DONE" then, their score will be highlighted for that game.
The tournament winner is the player with the lowest total score over the series.
.br
.br
Example:
.br
Three users ('abc' on 'xyzzy', 'def' on 'plugh', and 'ghi' on 'plover') wish
to play a 5 game tournament starting with board 12345.
Here are their command lines:
.br
.br
'abc' types: xmahjongg -b 12345 -n 5 -p def at plugh -p ghi at plover
.br
'def' types: xmahjongg -b 12345 -n 5 -p abc at xyzzy -p ghi at plover
.br
'ghi' types: xmahjongg -b 12345 -n 5 -p def at plugh -p abc at xyzzy
.br
.br
Note that the players can be in any order on the command line and that the
user does not list his/her own name on the command line.
.SH FILES
/usr/games/xmahjongg executable
.SH AUTHOR
Copyright 1989 Jeff S. Young
.br
<jsy at cray.com>
.br
.br
The tiles themselves are copyright 1988 by Mark A. Holm
<tektronix!tessi!exc!markh>. His copyright notice is included in the
source code.
.SH BUGS
Doesn't use the Xdefault information.
.PP
No permanent score file.
.PP
You cannot have the same user name for two different players in a tournament.
.PP
Uses sockets for tournament mode.
.PP
No color xmahjongg (yet).
7623!Funky!Stuff!
echo x - ./play.c
cat > ./play.c << '7623!Funky!Stuff!'
/*
******************************************************************************
* *
* Copyright (c) 1989 by Jeff S. Young. All rights reserved under the *
* copyright laws of the United States. *
* *
******************************************************************************
*/
#include <stdio.h>
#include <sys/time.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include "xmahjongg.h"
#include "tilenames.h"
extern int done_count;
extern int tourn_flag;
extern int keep_playing;
extern int tiles_remaining;
extern long mask[];
extern long buffer[];
extern Uchar *tile_data[];
extern Tile tiles[ROWS][COLS][LEVS];
extern int screen;
extern int fore_color;
extern int back_color;
extern int BorderColor;
extern Font font;
extern int XGameFD;
extern GC XGameGC0;
extern GC XGameGC1;
extern Window XGameWindow;
extern Display *XGameDisplay;
extern XSizeHints XGameHints;
extern XEvent XGameEvent;
extern XFontStruct *XGameFont;
extern XImage *XGameTileImage;
extern Tile *tile1p;
extern Tile *tile2p;
long alinger;
Uchar filler[1024];
XImage *XGameTileImage0;
XImage *XGameTileImage1;
XImage *XGameTileImage2;
XImage *XGameTileImage3;
XImage *XGameTileImage4;
play_tile(row, col, lev)
int row, col, lev;
{
Tile *tp = &tiles[row][col][lev];
if (not_free(row, col, lev)) {
XBell(XGameDisplay, 100);
XFlush(XGameDisplay);
} else if (tile1p == NULL) {
invert_tile(tp, 1);
tile1p = tp;
} else if (tp == tile1p) {
invert_tile(tp, 0);
tile1p = NULL;
} else if (tp->type == tile1p->type) {
/* if (tiles_remaining == 2) keep_playing = 0; */
tiles_remaining -= 2;
remove_tile(tile1p);
tile1p = NULL;
remove_tile(tp);
tp = NULL;
draw_count(tiles_remaining);
if (done_count == 0) packet_send(GAME_PLAY);
} else {
XBell(XGameDisplay, 100);
XFlush(XGameDisplay);
};
return(0);
}
invert_tile(tp, type)
Tile *tp;
int type;
{
int i;
int w = TILE_WIDTH;
int h = TILE_HEIGHT;
GC imageGC = (type == 0) ? XGameGC0 : XGameGC1;
/*
* Do the special tiles here, else call the general purpose routine
*/
if (tp->row == 0) {
XGameTileImage->data = (char *)tp->data;
draw_image(XGameTileImage, tp->x, tp->y, w, h, imageGC);
XFlush(XGameDisplay);
} else {
redraw_tile(tp, type);
XFlush(XGameDisplay);
};
return(0);
}
remove_tile(tp)
Tile *tp;
{
int i;
int x, y;
char *cp;
long *bp;
long *lp1, *lp2, *lp3, *lp4;
/*
* Do the special tiles here, else call the general purpose routine
*/
if ((tp->row == 0) && (tp->col == 0)) { /* top tile */
for (i = 0; i < 2048; i++) {
buffer[i] = 0L;
};
if (XGameTileImage0 == 0) {
XGameTileImage0 = XCreateImage(
XGameDisplay,
DefaultVisual(XGameDisplay, screen),
1, XYBitmap, 0, 0,
2*TILE_WIDTH, 2*TILE_WIDTH, 8, 0);
XGameTileImage0->bitmap_bit_order = MSBFirst;
XGameTileImage0->byte_order = MSBFirst;
XGameTileImage0->data = (char *)buffer;
};
tp->state = FREE;
lp1 = (long *)tiles[4][6][4].data;
lp2 = (long *)tiles[4][7][4].data;
lp3 = (long *)tiles[5][6][4].data;
lp4 = (long *)tiles[5][7][4].data;
bp = buffer;
for (i = 0; i < 4*64; i += 4) {
*(bp+i+000) = *(lp1 + 0);
*(bp+i+001) = *(lp1 + 1);
*(bp+i+002) = *(lp2 + 0);
*(bp+i+003) = *(lp2 + 1);
*(bp+i+256) = *(lp3 + 0);
*(bp+i+257) = *(lp3 + 1);
*(bp+i+258) = *(lp4 + 0);
*(bp+i+259) = *(lp4 + 1);
lp1 += 2;
lp2 += 2;
lp3 += 2;
lp4 += 2;
};
draw_image(XGameTileImage0,
tiles[4][6][4].x, tiles[4][6][4].y,
2*TILE_WIDTH, 2*TILE_HEIGHT, XGameGC0);
} else if ((tp->row == 0) && (tp->col == 1)) { /* left tile */
for (i = 0; i < 2048; i++) {
buffer[i] = 0L;
};
if (XGameTileImage1 == 0) {
XGameTileImage1 = XCreateImage(
XGameDisplay,
DefaultVisual(XGameDisplay, screen),
1, XYBitmap, 0, 0,
TILE_WIDTH+16, TILE_WIDTH+4, 8, 0);
XGameTileImage1->bitmap_bit_order = MSBFirst;
XGameTileImage1->byte_order = MSBFirst;
XGameTileImage1->data = (char *)buffer;
};
tp->state = FREE;
draw_image(XGameTileImage1,
tp->x-16, tp->y,
TILE_WIDTH+16, TILE_HEIGHT+4, XGameGC0);
for (i = 60; i < 64; i++) {
draw_line(tp->x + i, tp->y, tp->x + i, tp->y + 68);
};
} else if ((tp->row == 0) && (tp->col == 2)) { /* middle tile */
for (i = 0; i < 2048; i++) {
buffer[i] = 0L;
};
if (XGameTileImage2 == 0) {
XGameTileImage2 = XCreateImage(
XGameDisplay,
DefaultVisual(XGameDisplay, screen),
1, XYBitmap, 0, 0,
TILE_WIDTH, TILE_WIDTH+4, 8, 0);
XGameTileImage2->bitmap_bit_order = MSBFirst;
XGameTileImage2->byte_order = MSBFirst;
XGameTileImage2->data = (char *)buffer;
};
tp->state = FREE;
draw_image(XGameTileImage2,
tp->x, tp->y,
TILE_WIDTH, TILE_HEIGHT+4, XGameGC0);
} else if ((tp->row == 0) && (tp->col == 3)) { /* right tile */
for (i = 0; i < 2048; i++) {
buffer[i] = 0L;
};
if (XGameTileImage3 == 0) {
XGameTileImage3 = XCreateImage(
XGameDisplay,
DefaultVisual(XGameDisplay, screen),
1, XYBitmap, 0, 0,
TILE_WIDTH, TILE_WIDTH+4, 8, 0);
XGameTileImage3->bitmap_bit_order = MSBFirst;
XGameTileImage3->byte_order = MSBFirst;
XGameTileImage3->data = (char *)buffer;
};
tp->state = FREE;
draw_image(XGameTileImage3,
tp->x, tp->y,
TILE_WIDTH, TILE_HEIGHT+4, XGameGC0);
XClearArea(XGameDisplay, XGameWindow,
tp->x - 4, tp->y + 64, 4, 4, False);
x = tp->x;
y = tp->y + 63;
for (i = 1; i <= 4; i++) {
draw_line(x-4, y+i, x-i, y+i);
};
} else {
tp->state = FREE;
redraw_tile(tp, 0);
};
XFlush(XGameDisplay);
return(0);
}
redraw_tile(tp, type)
Tile *tp;
int type;
{
int i, j, k;
int row = tp->row;
int col = tp->col;
int lev = tp->lev;
int bl = 16+4*lev;
int br = 32 - bl;
int save0, save1, save2;
int save3, save4, save5;
int w_off = 641 - 32*lev;
long *bp = &buffer[w_off];
Uchar *cp;
/*
* Set up the tile image
*/
if (XGameTileImage4 == 0) {
XGameTileImage4 = XCreateImage(
XGameDisplay, DefaultVisual(XGameDisplay, screen),
1, XYBitmap, 0, 0, TILE_WIDTH+32, TILE_WIDTH+4, 8, 0);
XGameTileImage4->bitmap_bit_order = MSBFirst;
XGameTileImage4->byte_order = MSBFirst;
XGameTileImage4->data = (char *)filler;
};
/*
* Zero out the buffer before putting the data in it.
*/
for (i = 0; i < 2048; i++) {
buffer[i] = 0;
};
/*
* Loop over all tiles in the area. Redraw the screen area with the
* image of the tile. If this is the tile in the middle, then the
* option type has the following effect:
* 0) draw the tile normally
* 1) draw the tile inverted
*/
for (j = col+1; j >= col-1; j--) {
for (i = row-1; i <= row+1; i++) {
place_image(row, col, i, j, type);
};
};
/*
* Justify the data in the buffer for display purposes
*/
for (i = 0, j = 0; i < 68; i++, bp += 8) {
buffer[j++] = (*(bp+0) << bl) | ((*(bp+1) >> br) & mask[bl]);
buffer[j++] = (*(bp+1) << bl) | ((*(bp+2) >> br) & mask[bl]);
buffer[j++] = (*(bp+2) << bl) | ((*(bp+3) >> br) & mask[bl]);
};
for (j = 0, cp = filler; j < 3*68; j++) {
*cp++ = (buffer[j] >> 24) & 0xff;
*cp++ = (buffer[j] >> 16) & 0xff;
*cp++ = (buffer[j] >> 8) & 0xff;
*cp++ = (buffer[j] >> 0) & 0xff;
};
/*
* Display the data
*/
draw_image(XGameTileImage4, tp->x - 16, tp->y,
TILE_WIDTH+32, TILE_HEIGHT+4, XGameGC0);
XFlush(XGameDisplay);
return(0);
}
place_image(base_row, base_col, row, col, type)
int base_row, base_col, row, col, type;
{
int k;
if ((row == 0) || (row == ROWS)) return(0);
if ((col == 0) || (col == COLS)) return(0);
for (k = LEVS-2; k > 0; k--) {
if (tiles[row][col][k].state ==USED) break;
};
if (type == 2) k--;
if (k > 0) copy_image(&tiles[row][col][k], base_row, base_col, type);
return(0);
}
copy_image(tp, x, y, type)
Tile *tp;
int x, y;
int type;
{
int i, j;
int m_off = 0;
int b_off = 4*tp->lev;
int w_off = 642 + 512*(tp->row - x) + 2*(tp->col - y) - 32*tp->lev;
int s1 = b_off;
int s2 = 32 - b_off;
int m0 = mask[32];
int m1 = mask[s2];
int m2 = mask[s1] << s2;
int lines = 4*tp->lev;
unsigned char *cp = tp->data;
long long0, long1;
long *bp = &buffer[w_off];
/*
* Copy the tile into the buffer. The following kludge is to get around
* an anomaly in some of the 'C' compilers.
*/
for (i = 0, j = 0; i < 64; i++) {
long0 = ((*(cp+0) << 24) & 0xff000000) |
((*(cp+1) << 16) & 0x00ff0000) |
((*(cp+2) << 8) & 0x0000ff00) |
((*(cp+3) << 0) & 0x000000ff);
long1 = ((*(cp+4) << 24) & 0xff000000) |
((*(cp+5) << 16) & 0x00ff0000) |
((*(cp+6) << 8) & 0x0000ff00) |
((*(cp+7) << 0) & 0x000000ff);
cp += 8;
*(bp+j+0) = (*(bp+j+0) & m2) | ((long0 >> s1) & m1);
*(bp+j+1) = ((long0 << s2) & m2) | ((long1 >> s1) & m1);
*(bp+j+2) = (*(bp+j+2) & m1) | ((long1 << s2) & m2);
j += 8;
};
/*
* If this is the center tile, then invert it if type=1
*/
if ((tp->row == x) && (tp->col == y) && (type == 1)) {
for (i = 0, j = 0, bp = &buffer[w_off]; i < 64; i++) {
*(bp+j+0) ^= m1;
*(bp+j+1) ^= m0;
*(bp+j+2) ^= m2;
j += 8;
};
};
/*
* Copy the border into the buffer
*/
for (i = 1; i <= lines; i++) {
b_off--; w_off += 8; m_off = 1 << (31-b_off);
for (j = w_off; j < w_off+512; j += 8) {
buffer[j] |= m_off;
};
buffer[w_off+504] = mask[32-b_off];
buffer[w_off+505] = 0xffffffff;
buffer[w_off+506] |= mask[b_off] << (32-b_off);
};
return(0);
}
not_free(row, col, lev)
int row, col, lev;
{
int rc = 0;
if (lev == 4) {
if (tiles[0][0][5].state == USED) rc = 1;
} else if ((row == 0) && (col == 2) && (lev == 0)) {
if (tiles[0][3][0].state == USED) rc = 1;
} else if ((row == 4) && (col == 1) && (lev == 1)) {
if (tiles[0][1][0].state == USED) rc = 1;
} else if ((row == 5) && (col == 1) && (lev == 1)) {
if (tiles[0][1][0].state == USED) rc = 1;
} else if ((row == 4) && (col == 12) && (lev == 1)) {
if (tiles[0][2][0].state == USED) rc = 1;
} else if ((row == 5) && (col == 12) && (lev == 1)) {
if (tiles[0][2][0].state == USED) rc = 1;
} else if (row == 0) {
rc = 0;
} else if ((col == 1) || (col == 12)) {
rc = 0;
} else if ((1 < col) && (col < 12)) {
if (tiles[row][col][lev+1].state == USED) {
rc = 1;
} else if (tiles[row][col-1][lev].state != USED) {
rc = 0;
} else if (tiles[row][col+1][lev].state != USED) {
rc = 0;
} else {
rc = 1;
};
};
return(rc);
}
7623!Funky!Stuff!
echo x - ./packet.c
cat > ./packet.c << '7623!Funky!Stuff!'
/*
******************************************************************************
* *
* Copyright (c) 1989 by Jeff S. Young. All rights reserved under the *
* copyright laws of the United States. *
* *
******************************************************************************
*/
#include <stdio.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <netinet/in.h>
#include "xmahjongg.h"
extern int errno;
extern int maxfds;
extern int playfds;
extern int done_count;
extern int tourn_flag;
extern int num_games;
extern int num_players;
extern int tiles_remaining;
extern long seed;
extern long buffer[];
extern long game_board[];
extern Uchar *tile_data[];
extern Tile *tile1p, *tile2p;
extern Tile tiles[ROWS][COLS][LEVS];
extern Player player[MAX_PLAYERS];
extern Player *pp, *mypp;
extern int screen;
extern int fore_color;
extern int back_color;
extern int BorderColor;
extern Font font;
extern int XGameFD;
extern GC XGameGC0;
extern GC XGameGC1;
extern Window XGameWindow;
extern Display *XGameDisplay;
extern XSizeHints XGameHints;
extern XEvent XGameEvent;
extern XFontStruct *XGameFont;
int x_coor;
int y_coor;
Packet packet;
packet_send(type)
int type;
{
int i;
int packetlen = sizeof(Packet);
char ascii[24];
if (tourn_flag == 0) return(0);
i = mypp->done;
/*
* Update the information on my board
*/
if (type == GAME_START) {
mypp->done++;
mypp->tiles[mypp->done] = TILES;
mypp->board[mypp->done] = seed;
if ((i >= 0) && (mypp->tiles[i] > 0)) mypp->tiles[i] *= -1;
draw_user(mypp, GAME_START);
} else if (type == GAME_PLAY) {
mypp->total -= 2;
mypp->tiles[i] = tiles_remaining;
draw_user(mypp, GAME_PLAY);
} else if (type == GAME_DONE) {
if (mypp->tiles[i] > 0) mypp->tiles[i] *= -1;
draw_user(mypp, GAME_DONE);
} else if (type == GAME_QUIT) {
draw_user(mypp, GAME_QUIT);
} else {
fprintf(stderr, "bad packet type = %d\n", type);
exit(1);
};
/*
* Send the information to the other players
*/
packet.type = htons(type);
packet.port = htons(mypp->port);
packet.tiles = htons(tiles_remaining);
packet.board = htonl(seed);
strcpy(packet.name, mypp->name);
for (i = 0, pp = player; i < num_players; i++, pp++) {
if ((pp->fd < 0) || (pp->type == 'M')) continue;
if (write(pp->fd, (char *)&packet, packetlen) != packetlen) {
playfds ^= (1 << pp->fd);
close(pp->fd);
pp->fd = -1;
};
};
return(0);
}
packet_recv(fd)
int fd;
{
int i;
int readfds = 1 << fd;
int packetlen = sizeof(Packet);
struct timeval timeout;
char ascii[32];
char *cp;
/*
* Read in the packet which is waiting for us.
*/
errno = 0;
timeout.tv_sec = 0L;
timeout.tv_usec = 0L;
if (select(maxfds, &readfds, NULL, NULL, &timeout) <= 0) {
return(0);
} else if (read(fd, (char *)&packet, packetlen) != packetlen) {
playfds ^= (1 << pp->fd);
close(pp->fd);
pp->fd = -1;
return(0);
};
/*
* Find this players structure.
*/
packet.type = ntohs(packet.type);
packet.port = ntohs(packet.port);
packet.tiles = ntohs(packet.tiles);
packet.board = ntohl(packet.board);
for (i = 0, pp = player; i < num_players; i++, pp++) {
if (pp->port == packet.port) break;
};
if (i == num_players) {
fprintf(stderr, "****** BAD PACKET ******\n");
fprintf(stderr, "packet name = %s port=%d\n",
packet.name, packet.port);
return(0);
};
i = pp->done;
switch (packet.type) {
case GAME_START:
pp->done++;
pp->board[i+1] = packet.board;
pp->tiles[i+1] = packet.tiles;
if ((i >= 0) && (pp->tiles[i] > 0)) pp->tiles[i] *= -1;
draw_user(pp, GAME_START);
break;
case GAME_PLAY:
pp->total -= 2;
pp->tiles[i] = packet.tiles;
draw_user(pp, GAME_PLAY);
break;
case GAME_DONE:
if (pp->tiles[i] > 0) pp->tiles[i] *= -1;
draw_user(pp, GAME_DONE);
break;
case GAME_QUIT:
pp->tiles[i] = -packet.tiles;
pp->quit = 1;
draw_user(pp, GAME_QUIT);
playfds ^= (1 << pp->fd);
close(pp->fd);
pp->fd = -1;
break;
default:
fprintf(stderr, "bad switch (%d)\n", packet.type);
exit(1);
break;
};
return(0);
}
7623!Funky!Stuff!
More information about the Comp.sources.x
mailing list