[comp.sources.sun] v01i002: Sunview/X Mazewar, Part05/06

mcgrew@aramis.rutgers.edu (Charles Mcgrew) (05/06/89)

Submitted-by: kent@wsl.dec.com
Posting-number: Volume 1, Issue 2
Archive-name: mazewar/part05

#!/bin/sh
sed 's/^X//' >./winSunView.c << 'xxFUNNYxx'
X/* $Header$ */
X
X/* 
X * window_sunview.c - Window-system specific routines
X * 
X * Author:	Bob Brown
X * 		RIACS
X *	 	NASA Ames Research Center
X * Date:	Thu Dec 5 1986
X * Copyright (c) 1986 Robert L. Brown
X *
X * Revised by:	Malcolm Slaney (@ Schlumberger Palo Alto Research)
X *		August 1987 and January 1988
X *
X */
X
X/* 
X * It is intended that this file presents a window system-independent
X * set of routines to MazeWar; that is, if you want to run MW under
X * another window system, this is the only file that needs to be
X * changed. It isn't yet clear how well I've succeeded, but it's a start.
X * 
X * Routines that are presented to the outside are capitalized; local
X * routines are not.
X *
X * This file is for Sun 3.1 Sunview.  It has also been tested under Sun 3.4.
X */
X
X/*
X * $Log$
X */
X
X#ifndef	lint
Xstatic char rcs_ident[] = "$Header$";
X#endif
X
X#include <sys/types.h>			/* I hate programs that do this... */
X#include <sys/socket.h>			/* ... but sometimes
you just gotta */
X#include <netinet/in.h>
X#include <suntool/sunview.h>
X#include <suntool/canvas.h>
X#include <stdio.h>
X#include "mazewar.h"
X
X#include <errno.h>
X
X/*
X** These constants define where in the main pixwin the subregions lie
X*/ 
X#define	VIEW_X_DIM	400
X#define	VIEW_Y_DIM	400
X#define	VIEW_X_ORIGIN	100
X#define	VIEW_Y_ORIGIN	50
X#define	MAZE_X_DIM	(MAZEXMAX*16)
X#define	MAZE_Y_DIM	(MAZEYMAX*16)
X#define	MAZE_X_ORIGIN	48
X#define	MAZE_Y_ORIGIN	451
X#define	SCORE_X_DIM	192
X#define	SCORE_Y_DIM	(mwFontHeight * MAXRATS)
X#define	SCORE_X_ORIGIN	208
X#define	SCORE_Y_ORIGIN	708
X#define	MIN_X_DIM	608		/* see comments for InitWindow() */
X#define	MIN_Y_DIM	SCORE_Y_ORIGIN	/* see InitWindow() */
X#define MAX_X_DIM	MIN_X_DIM
X#define	MAX_Y_DIM	(MIN_Y_DIM + SCORE_Y_DIM)
X
Xshort	mazeBits[MAZEXMAX*MAZEYMAX*16]; /* shorts better be 16 bits! */
XFrame	BaseFrame;			/* parent frame */
XCanvas	BaseCanvas;			/* Base canvas */
XPixwin	*mwPixwin;			/* parent pixel window */
XPixwin	*viewPixwin;			/* view subwindow */
XPixwin	*mazePixwin;			/* maze subwindow */
XPixwin	*scorePixwin;			/* score subwindow */
Xstruct pixrect *mazePixrect;		/* Pixrect that has the maze */
Xstruct pixrect *ratsPixrect;		/* Pixrect that has the rats */
Xstruct pixfont *mwFont;			/* Font being used */
Xint	mwFontHeight;			/* Height of the font */
XBoolean	inverted = FALSE;		/* user warned of window exit */
Xint	displayFD;			/* fd of display for events */
Xint	frameFD;			/* for handling frame events */
Xint	RastOp = PIX_SRC;
Xint	MaxOffset;			/* max vertical font offset from 
X					 * baseline */
Xint	flashIcon = FALSE;		/* Should icon be flashing ? */
X
Xstatic short grayBits[16] = {
X    0xaaaa, 0x5555, 0xaaaa, 0x5555,
X    0xaaaa, 0x5555, 0xaaaa, 0x5555,
X    0xaaaa, 0x5555, 0xaaaa, 0x5555,
X    0xaaaa, 0x5555, 0xaaaa, 0x5555
X};
X
Xstatic short ratBits[] = {
X	0x0000,0x0000,0x07C0,0x0FE8,0x0FFC,0x7FFA,0x8FFF,0x8842,
X	0x4000,0x3F00,0x0080,0x0100,0x0200,0x0100,0x0000,0x0000
X};
Xmpr_static(ratPixrect, 16, 16, 1, ratBits);
X
Xstatic short deadRatBits[] = {
X    0x0000, 0x2088, 0x1045, 0x0082,
X    0x0000, 0x1000, 0x2000, 0x4100,
X    0x8220, 0x87ff, 0x8ffa, 0x7ffc,
X    0x0fe8, 0x07c0, 0x0000, 0x0000
X};
Xmpr_static(deadRatPixrect, 16, 16, 1, deadRatBits);
X
Xstatic short coffeeCupBits[] = {
X    0x0080, 0x0700, 0x0800, 0x07c0,
X    0x0020, 0x07f0, 0x3c48, 0x47f8,
X    0x5808, 0x4008, 0x3c08, 0x0818,
X    0x37f6, 0x2002, 0x17fc, 0x0000
X};
Xmpr_static(coffeeCupPixrect, 16, 16, 1, coffeeCupBits);
X
Xstatic short ToolIconBits[] = {
X/* Format_version=1, Width=64, Height=64, Depth=1, Valid_bits_per_item=16
X */
X	0x8888,0x8888,0x8888,0x8888,0x8800,0x0000,0x0000,0x0008,
X	0x2200,0x0000,0x0000,0x0022,0x2284,0x0000,0x0820,0x0022,
X	0x8884,0x0000,0x0820,0x0008,0x88CC,0x71F1,0xC827,0x1608,
X	0x22CC,0x8812,0x2928,0x9922,0x22B4,0x0822,0x2540,0x9022,
X	0x88B4,0x7843,0xE547,0x9008,0x8884,0x8882,0x0548,0x9008,
X	0x2284,0x8902,0x2288,0x9022,0x2284,0x79F1,0xC287,0x9022,
X	0x8800,0x0000,0x0000,0x0008,0x8800,0x0000,0x0000,0x0008,
X	0x2200,0x0000,0x0000,0x0022,0x2222,0x2222,0x2222,0x2222,
X	0x8888,0x8888,0x8888,0x8888,0x9FFF,0xFFFF,0xFFFF,0xFFFC,
X	0x3800,0x0000,0x0000,0x0006,0x3400,0x0000,0x0000,0x0006,
X	0x9200,0x0000,0x0000,0x0004,0x9100,0x0000,0x0000,0x0004,
X	0x3080,0x0000,0x0000,0x0006,0x3040,0x0000,0x0000,0x01FE,
X	0x9020,0x0000,0x0000,0x0304,0x9010,0x0000,0x0000,0x0504,
X	0x3008,0x0000,0x0000,0x0906,0x3004,0x0000,0x0000,0x1106,
X	0x9002,0x0000,0x0000,0x2104,0x9001,0x0000,0x0000,0x4104,
X	0x3000,0x8000,0x0000,0x8106,0x3000,0x4000,0x0001,0x0106,
X	0x9000,0x3FFF,0xFFFE,0x0104,0x9000,0x2000,0x0002,0x0104,
X	0x3000,0x2000,0x0002,0x0106,0x3000,0x2000,0x0002,0x0106,
X	0x9000,0x2000,0x0002,0x0104,0x9000,0x2000,0x0002,0x0104,
X	0x3000,0x2000,0x0002,0x0106,0x3000,0x2000,0x0002,0x0106,
X	0x9000,0x2000,0x0002,0x0104,0x9000,0x2000,0x0002,0x0104,
X	0x3000,0x2000,0x0002,0x0106,0x3000,0x3FFF,0xFFFE,0x0106,
X	0x9000,0x4000,0x0001,0x0104,0x9000,0x8000,0x0000,0x8104,
X	0x3001,0x0000,0x0000,0x4106,0x3002,0x0000,0x0000,0x2106,
X	0x9004,0x0000,0x0000,0x1104,0x9008,0x0001,0xF000,0x0904,
X	0x3010,0x000B,0xF800,0x0506,0x3020,0x001F,0xF800,0x0306,
X	0x9040,0x002F,0xFF00,0x01FC,0x9080,0x007F,0xF880,0x0004,
X	0x3100,0x0021,0x0880,0x0006,0x3200,0x0000,0x0100,0x0006,
X	0x9400,0x0000,0x7E00,0x0004,0x9800,0x0000,0x8000,0x0004,
X	0x3000,0x0000,0x4000,0x0006,0x3000,0x0000,0x2000,0x0006,
X	0x9FFF,0xFFFF,0xFFFF,0xFFFC,0x8888,0x8888,0x8888,0x8888,
X	0x2222,0x2222,0x2222,0x2222,0x2222,0x2222,0x2222,0x2222
X};
XDEFINE_ICON_FROM_IMAGE(ToolIcon, ToolIconBits);
X
Xstatic Cursor	ratCursor, deadRatCursor, hourGlassCursor;
X
Xextern char	*getenv();
Xextern int	errno;
X
X/* state between InitWindow() and StartWindow() */
Xstatic char	*progName;
X
X/* 
X * ALL COORDINATES ASSUME ORIGIN (0,0) AT UPPER LEFT!
X */
X
X/* 
X * Initialize the window. The overall window must be at least 608x by
X * 808y (the size of the Alto screen). There are three distinct
X * subregions:
X *	A 400x by 400y area for the view, beginning at (100,50)
X *	A 512x by 256y area for the maze, beginning at (48, 451)
X *	A 192x by 96y area for the score lines, at (208, 706)
X *
X *	Actually, the y dimension of both the whole window and the score
X *	subwindow must be enough to accommodate MAXRATS lines of the
X *	height of the scoreFont.
X */
X
X/* parse arguments and set up window state */
X
XInitWindow(argc, argv)
Xchar	**argv;
X{
X	int i;
X
X	progName = argv[0];
X
X	BaseFrame = window_create(NULL, FRAME, 
X		FRAME_ARGC_PTR_ARGV, &argc, argv,
X		FRAME_LABEL, "Maze War",
X		FRAME_ICON, &ToolIcon,
X		0);
X	mwFont = (struct pixfont *)window_get(BaseFrame, WIN_FONT);
X	mwFontHeight = mwFont->pf_defaultsize.y;
X	MaxOffset = 999;
X	for(i=0;i<256;i++) {
X		if(MaxOffset > mwFont->pf_char[i].pc_home.y)
X			MaxOffset = mwFont->pf_char[i].pc_home.y;
X	}
X/*	printf("maxoffset = %d\n", MaxOffset);				*/
X	frameFD = (int)window_get(BaseFrame,  WIN_FD);
X}
X
X/* 
X * actually start the display up, after all the user interaction has
X * been done.
X */
X
XStartWindow(ratBits, ratWidth, ratHeight)
Xshort	*ratBits;
X{
X	int repaintWindow();
X
X	initCursors();
X
X	HourGlassCursor();
X
X	initMaze();
X/*	FlipBitmaps();			/* bit-reverse all the bitmaps */
X	initRats(ratBits, ratWidth, ratHeight);
X
X	BaseCanvas = window_create(BaseFrame, CANVAS,
X		WIN_X, 0,
X		WIN_Y, 0,
X		WIN_WIDTH, MAX_X_DIM,
X		WIN_HEIGHT, MAX_Y_DIM,
X		0);
X	window_fit(BaseFrame);
X	window_set(BaseFrame, WIN_SHOW, TRUE, 0);
X	window_set(BaseCanvas,
X		   WIN_CONSUME_KBD_EVENTS, WIN_NO_EVENTS, 
X		    WIN_ASCII_EVENTS, KBD_USE, KBD_DONE, 0, 
X		   WIN_CONSUME_PICK_EVENTS, WIN_NO_EVENTS, WIN_MOUSE_BUTTONS,
X		     LOC_WINENTER, LOC_WINEXIT, 0, 
X		0);
X	mwPixwin = (Pixwin *)window_get(BaseCanvas, CANVAS_PIXWIN);
X	notify_dispatch();
X	displayFD = (int)window_get(BaseCanvas, WIN_FD);
X	viewPixwin = (Pixwin *)pw_region(mwPixwin,
X		VIEW_X_ORIGIN, VIEW_Y_ORIGIN, VIEW_X_DIM, VIEW_Y_DIM);
X	mazePixwin = (Pixwin *)pw_region(mwPixwin,
X		MAZE_X_ORIGIN, MAZE_Y_ORIGIN, MAZE_X_DIM, MAZE_Y_DIM);
X	scorePixwin = (Pixwin *)pw_region(mwPixwin,
X		SCORE_X_ORIGIN, SCORE_Y_ORIGIN, SCORE_X_DIM, SCORE_Y_DIM);
X	window_set(BaseCanvas, 
X		CANVAS_REPAINT_PROC, repaintWindow, 
X		CANVAS_RESIZE_PROC, repaintWindow,
X		CANVAS_RETAINED, TRUE,
X		CANVAS_AUTO_CLEAR, TRUE,
X		0);
X	repaintWindow();
X}
X
X/*
X * Shut down the window system, resetting any terminal modes or what
X * have you that may have been altered. No-op for Sun View
X */
X
XStopWindow()
X{
X	
X}
X
X/* 
X * Clear out the view subwindow. If possible, delay the visible effect
X * until all the lines have been drawn (since this is only called by
X * ShowView(), which is about to draw a bunch of lines).
X */
X
XClearView()
X{
X	pw_writebackground(viewPixwin, 0, 0, VIEW_X_DIM, VIEW_Y_DIM,
X	    RastOp);
X}
X
X/*
X * Flash the view window to indicate a hit on an opponent.
X */
X
XFlashTop()
X{
X	pw_rop(viewPixwin, 0, 0, VIEW_X_DIM, VIEW_Y_DIM,
X	    PIX_NOT(PIX_SRC), viewPixwin, 0, 0);
X
X	/* might want some delay here */
X
X	pw_rop(viewPixwin, 0, 0, VIEW_X_DIM, VIEW_Y_DIM,
X	    PIX_NOT(PIX_SRC), viewPixwin, 0, 0);
X}
X
X/*
X * Flash the whole window to indicate we were hit.
X */
X
XFlashScreen()
X{
X	pw_rop(mwPixwin, 0, 0, window_get(BaseCanvas, WIN_WIDTH),
X	    window_get(BaseCanvas, WIN_HEIGHT), PIX_NOT(PIX_SRC),
X	    mwPixwin, 0, 0);
X
X	/* might want some delay here */
X
X	pw_rop(mwPixwin, 0, 0, window_get(BaseCanvas, WIN_WIDTH),
X	    window_get(BaseCanvas, WIN_HEIGHT), PIX_NOT(PIX_SRC),
X	    mwPixwin, 0, 0);
X}
X
X/* 
X * Draw a line in the view subwindow. Don't show it right away if possible.
X */
X
XDrawViewLine(x1, y1, x2, y2)
X{
X	pw_vector(viewPixwin, x1, y1, x2, y2, RastOp, 1);
X}
X
X/* 
X * Event handling. Presents a uniform event interface to the game, and
X * handles all other events in here. The game only sees the events
X * that affect it directly, as defined in mazewar.h. They are:
X *
X *	keypresses that affect the game
X *	mouse button clicks
X *	incoming network packets
X *	timeouts (there's a "heartbeat" to drive the shot clock)
X *
X * All other events should be swallowed by this routine. Also, since
X * keyboard focus is dependent on the mouse being in the game window,
X * try to let the user know that he's wandered outside the window
X * by inverting the window (should make it obvious) and is now vulnerable
X * and defenseless.
X */
X
Xvoid
XNextEvent(event)
XMWEvent	*event;
X{
X	int	fdmask;
X	Event	sunEvent;
X	struct timeval timeout;
X	int	ret;
X	static	int	LastWinEnterExit = 0;
X
X    while (1) {
X	if (flashIcon == TRUE){
X		if (window_get(BaseFrame, FRAME_CLOSED)){
X			InvertIcon();
X		} else {
X			flashIcon = FALSE;
X			window_set(BaseFrame, FRAME_ICON, &ToolIcon, 0);
X		}
X	}
X
X	/* must do this every time, since M.theSocket may change! */
X	fdmask = (1 << displayFD) | (1 << frameFD) | (1 << M.theSocket);
X	timeout.tv_sec = 0;
X	timeout.tv_usec = 250000;
X	while ((ret = select(32, &fdmask, NULL, NULL, &timeout)) == -1){
X						/* EINTR implies interrupts
X						 * which we don't care about.
X						 * EBADF implies that things
X						 * are probably being shut down
X						 * so we should exit.
X						 */
X		if (errno == EBADF){
X			event->eventType = EVENT_INT;
X			return;
X		}
X		if (errno != EINTR)
X			MWError("select error on events");
X	}
X	if (ret == 0) {
X		event->eventType = EVENT_TIMEOUT;
X		(void) notify_dispatch();
X		return;
X	}
X	if (fdmask & (1 <<displayFD)) {
X		window_read_event(BaseCanvas, &sunEvent);
X		event->eventType = 0;
X		switch (sunEvent.ie_code) {
X		case 'a':
X			event->eventType = EVENT_A;
X			return;
X
X		case 's':
X			event->eventType = EVENT_S;
X			return;
X
X		case 'd':
X			event->eventType = EVENT_D;
X			return;
X
X		case 'f':
X			event->eventType = EVENT_F;
X			return;
X
X		case ' ':
X			event->eventType = EVENT_BAR;
X			return;
X
X		case 'i':
X			event->eventType = EVENT_I;
X			return;
X
X		case 'k':
X			event->eventType = EVENT_K;
X			return;
X
X		case 'o':
X			event->eventType = EVENT_O;
X			return;
X
X		case 'l':
X			event->eventType = EVENT_L;
X			return;
X
X		case 'q':
X		case 077:
X			/* should also deal with Interrupt char */
X			event->eventType = EVENT_INT;
X			return;
X
X		case MS_RIGHT:
X			event->eventType = event_is_down(&sunEvent) ?
X				EVENT_RIGHT_D : EVENT_RIGHT_U;
X			return;
X
X		case MS_MIDDLE:
X			event->eventType = event_is_down(&sunEvent) ?
X				EVENT_MIDDLE_D : 0;
X			return;
X
X		case MS_LEFT:
X			event->eventType = event_is_down(&sunEvent) ?
X				EVENT_LEFT_D : EVENT_LEFT_U;
X			return;
X
X		case KBD_USE:
X#ifdef	DEBUG			
X			printf("Have keyboard focus again.....\n");
X#endif	DEBUG			
X			if (RastOp != PIX_SRC) {
X				invertDisplay();
X			}
X			RastOp = PIX_SRC;
X			break;
X
X		case KBD_DONE:
X#ifdef	DEBUG			
X			printf("Lost keyboard focus.....\n");
X#endif	DEBUG			
X			if (RastOp != PIX_NOT(PIX_SRC)) {
X				invertDisplay();
X			}
X			RastOp = PIX_NOT(PIX_SRC);
X			break;
X		case WIN_REPAINT:
X			repaintWindow();
X			break;
X		default:
X/*			printf("Window event %d\n", sunEvent.ie_code);	*/
X			break;
X		}
X		continue;
X	}
X	if (fdmask & (1 << M.theSocket)) {
X		int fromLen = sizeof(event->eventSource);
X		int cc;
X
X		event->eventType = EVENT_NETWORK;
X		cc = recvfrom(M.theSocket, event->eventDetail,
X			sizeof(RatPacket), 0, &event->eventSource, &fromLen);
X		ConvertIncoming(event->eventDetail);
X		if (cc <= 0) {
X			if (cc < 0 && errno != EINTR)
X				perror("event recvfrom");
X			continue;
X		}
X		if (fromLen != sizeof(struct sockaddr_in))
X			continue;
X		return;
X	}
X	if ( fdmask & (1 << frameFD)) {
X		notify_dispatch();
X	}
X    }
X}
X
X/* Please stand by ... */
X
XHourGlassCursor()
X{
X	window_set(BaseCanvas, WIN_CURSOR, hourGlassCursor, 0);
X}
X
X/* Let the games begin! */
XRatCursor()
X{
X	window_set(BaseCanvas, WIN_CURSOR, ratCursor, 0);
X}
X
X/* He's dead, Jim ... or might be */
XDeadRatCursor()
X{
X	window_set(BaseCanvas, WIN_CURSOR, deadRatCursor, 0);
X}
X
X/* update the displayed bitmap */
X
Xmpr_static(Hack_pr, 16, 16, 1, NULL);
X
XHackMazeBitmap(x, y, newBits)
XBitCell *newBits;
X{
X	Hack_pr_data.md_image = newBits->bits;
X	pw_rop(mazePixwin, x*16, y*16, 16, 16, RastOp, &Hack_pr, 0, 0);
X}
X
X/*
X * Display a rat. Width, height, srcX and srcY describe the subbitmap
X * in the rats bitmap that is the desired view of the opponent.
X */
X
XDisplayRatBitmap(screenX, screenY, width, height, srcX, srcY)
X{
X	pw_rop(viewPixwin, screenX, screenY, width, height, PIX_SRC^PIX_DST, 
X		ratsPixrect, srcX, srcY);
X}
X
X/* 
X * Display the score line for the indicated player. Name is left
X * justified, score is right justified within the score window.
X */
X
XWriteScoreString(rat)
XRatId	rat;
X{
X	char	buf[64];
X	int	leftEdge;
X	struct pr_size size;
X
X	pw_text(scorePixwin, 0, (rat+1)*mwFontHeight, RastOp, mwFont, 
X		M.ratcb.rats[rat].name);
X	sprintf(buf, "%d", (unsigned int)M.ratcb.rats[rat].score);
X	size = pf_textwidth(strlen(buf), mwFont, buf);
X	leftEdge = SCORE_X_DIM - size.x;
X	pw_text(scorePixwin, leftEdge, (rat+1)*mwFontHeight, RastOp, mwFont,
X		buf);
X}
X
X/* 
X * Clear out the score line for a player that's left the game.
X */
X
XClearScoreLine(rat)
XRatId	rat;
X{
X	pw_writebackground(scorePixwin, 0, (rat+1)*mwFontHeight+MaxOffset, 
X		SCORE_X_DIM, mwFontHeight, RastOp);
X}
X
X/* 
X * Pretty obvious, eh? Means the guy's in sight.
X */
X
XInvertScoreLine(rat)
XRatId	rat;
X{
X	pw_writebackground(scorePixwin, 0, (rat+1)*mwFontHeight+MaxOffset, 
X		SCORE_X_DIM, mwFontHeight, PIX_NOT(PIX_DST));
X}
X
X/*
X * END PUBLIC ROUTINES
X */
X
X/* set up needed bitmaps in the server */
X
XinitCursors()
X{
X	ratCursor = cursor_create(CURSOR_IMAGE, &ratPixrect, 
X		CURSOR_OP, PIX_SRC^PIX_DST, 
X		0);
X	deadRatCursor = cursor_create(CURSOR_IMAGE, &deadRatPixrect, 
X		CURSOR_OP, PIX_SRC^PIX_DST, 
X		0);
X	hourGlassCursor = cursor_create(CURSOR_IMAGE, &coffeeCupPixrect, 
X		CURSOR_OP, PIX_SRC^PIX_DST, 
X		0);
X}
X
X/*
X * construct a Pixmap of the maze, and store it in the server.
X */
X
XinitMaze()
X{
X	register int	i, j, k, line, index;
X
X	for (i = 0; i < MAZEYMAX; i++) {
X		line = i * MAZEXMAX * MAZEYMAX;
X		for (j = 0; j < MAZEXMAX; j++) {
X			index = line + j;
X			for (k = 0; k < 16; k++) {
X				if (M.maze[j].y[i])
X					mazeBits[index] = 0177777;
X				else
X					mazeBits[index] = 0;
X				index += 32;
X			}
X					
X		}
X	}
X	mazePixrect = mem_point(MAZE_X_DIM, MAZE_Y_DIM, 1, mazeBits);
X}
X
X/*
X * actually put the maze Pixmap on the screen
X */
X
XdrawMaze()
X{
X	pw_rop(mazePixwin, 0, 0, MAZE_X_DIM, MAZE_Y_DIM, RastOp, 
X		mazePixrect, 0, 0);
X}
X
X/* 
X * Create a memory pixrect of the rats so we can do arbitrary
X * bitblts on them later.
X */
X
XinitRats(bits, width, height)
Xshort *bits;
X{
X	ratsPixrect = mem_point(width, height, 1, bits);
X}
X
Xusage()
X{
X	fprintf(stderr,"usage: mazewar\n");
X	exit(1);
X	
X}
X
XrepaintWindow()
X{
X#ifdef	DEBUG
X	printf("repaint window called\n");
X	if (RastOp == PIX_SRC)
X		printf("repaintWindow called with RastOp = PIX_SRC.\n");
X	else
X		printf(
X		     "repaintWindow called with RastOp = PIX_NOT(PIX_SRC).\n");
X#endif	DEBUG	
X	if (RastOp != PIX_SRC)
X		pw_rop(mwPixwin, 0, 0, (int)window_get(BaseCanvas, WIN_WIDTH), 
X		       (int)window_get(BaseCanvas, WIN_HEIGHT),
X		       PIX_NOT(PIX_CLR), 
X		       mwPixwin, 0, 0);
X	drawMaze();
X	ShowPosition(M.xloc, M.yloc, M.invincible, M.dir);
X	ShowView(M.xloc, M.yloc, M.dir);
X	ShowAllPositions();
X
X	NewScoreCard();
X}
X/* 
X * Invert the whole display. Used to let the user know the mouse has
X * strayed outside the window. 
X */
X
XinvertDisplay()
X{
X	pw_rop(mwPixwin, 0, 0, (int)window_get(BaseCanvas, WIN_WIDTH), 
X		(int)window_get(BaseCanvas, WIN_HEIGHT), PIX_NOT(PIX_SRC), 
X		mwPixwin, 0, 0);
X}
X
X/*
X* Peek to see if there's a keyboard event waiting, in case the
X* program wants to short-circuit some code. If your system won't let
X* you implement this feature easily, just always return FALSE.
X*/
X
XBoolean
XKBEventPending()
X{
X	    return (FALSE);
X}
X
X/*
X* Let the user know that a new player joined. This really should only
X* take effect if the window is iconic, so you can keep a game around
X* all day, close it up when there's no activity, and know when
X* someone else is also out to kill some time.
X*/
X
XNotifyPlayer()
X{
X	flashIcon = TRUE;
X}
X
X
XInvertIcon(){
X	Icon	icon;
X	Pixrect	*pr;
X
X	icon = (Icon) window_get(BaseFrame, FRAME_ICON);
X	pr = (Pixrect *) icon_get(icon, ICON_IMAGE);
X
X	pr_rop(pr, 0, 0, 64, 64, PIX_NOT(PIX_DST), pr, 0, 0);
X
X	icon_set(icon, ICON_IMAGE, pr, 0);
X	window_set(BaseFrame, FRAME_ICON, icon, 0);
X}
xxFUNNYxx
sed 's/^X//' >./winX10.c << 'xxFUNNYxx'
X/* $Header: winX10.c,v 1.14 89/02/24 16:59:12 kent Exp $ */
X
X/* 
X * window_X10.c - Window-system specific routines
X * 
X * Author:	Christopher A. Kent
X * 		Western Research Laboratory
X *	 	Digital Equipment Corporation
X * Date:	Thu Oct  2 1986
X */
X
X/***********************************************************
XCopyright 1986 by Digital Equipment Corporation, Maynard, Massachusetts,
X
X                        All Rights Reserved
X
XPermission to use, copy, modify, and distribute this software and its 
Xdocumentation for any purpose and without fee is hereby granted, 
Xprovided that the above copyright notice appear in all copies and that
Xboth that copyright notice and this permission notice appear in 
Xsupporting documentation, and that the names of Digital not be
Xused in advertising or publicity pertaining to disstribution of the
Xsoftware without specific, written prior permission.  
X
XDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
XALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
XDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
XANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
XWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
XARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
XSOFTWARE.
X
X******************************************************************/
X
X/* 
X * It is intended that this file presents a window system-independent
X * set of routines to MazeWar; that is, if you want to run MW under
X * another window system, this is the only file that needs to be
X * changed. It isn't yet clear how well I've succeeded, but it's a start.
X * 
X * Routines that are presented to the outside are capitalized; local
X * routines are not.
X *
X * This file is for X version 10.
X */
X
X/*
X * $Log:	winX10.c,v $
X * Revision 1.14  89/02/24  16:59:12  kent
X * moved bitmaps into a subdirectory, because they're different than
X * the X11 ones now.
X * 
X * Revision 1.13  88/08/25  09:59:12  kent
X * Copyright and filename changes for system V compatability.
X * 
X * Revision 1.12  88/08/09  14:46:28  kent
X * Moved the bitmaps.
X * 
X * Revision 1.11  87/08/21  15:49:57  kent
X * Fixed things for monochrome displays. Since the rat images are a pixmap,
X * not a bitmap, XORing the foreground color does funny things. Now
X * a little more careful in how the pixmap is set up, and all is copacetic.
X * 
X * Revision 1.10  87/08/21  11:46:34  kent
X * Changed to use cursor masks and GXcopy; too many displays don't 
X * support XOR cursors, so the cursor disappears into the background at times.
X * 
X * Revision 1.9  87/03/31  14:42:38  kent
X * Portability considerations, especially byteswapping to/from the net.
X * 
X * Revision 1.8  86/12/04  17:46:58  kent
X * Make sure colors are always right when creating the iconic version.
X * 
X * Revision 1.7  86/12/04  14:36:56  kent
X * Changes to try to notify the user when a new player joins the game.
X * 
X * Revision 1.6  86/12/04  11:20:37  kent
X * Added some error return checks, so the program doesn't die with
X * a mysterious X runtime error when the server runs out of resources.
X * 
X * Revision 1.5  86/12/03  13:30:57  kent
X * 
X * 
X * Revision 1.4  86/12/03  10:00:58  kent
X * Changes to allow multiple players per machine.
X * 
X * Revision 1.3  86/12/01  23:45:19  kent
X * Housecleaning and documentation pass.
X * 
X * Revision 1.2  86/12/01  14:49:11  kent
X * Changes for a realistic implementation of shooting.
X * 
X * Revision 1.1  86/11/26  16:58:31  kent
X * Initial revision
X */
X
X#ifndef	lint
Xstatic char rcs_ident[] = "$Header: winX10.c,v 1.14 89/02/24 16:59:12 kent Exp $";
X#endif
X
X#include <X/Xlib.h>
X#include <X/Xkeyboard.h>
X
X#include <sys/types.h>
X#include <sys/time.h>
X
X#include <netinet/in.h>
X
X#include <errno.h>
X#include <stdio.h>
X#include <strings.h>
X
X#include "mazewar.h"
X#include "bitmaps/X10/icon.ic"
X#include "bitmaps/X10/iconMask.ic"
X
X#define	VIEW_X_DIM	400
X#define	VIEW_Y_DIM	400
X#define	VIEW_X_ORIGIN	100
X#define	VIEW_Y_ORIGIN	50
X#define	MAZE_X_DIM	(MAZEXMAX*16)
X#define	MAZE_Y_DIM	(MAZEYMAX*16)
X#define	MAZE_X_ORIGIN	48
X#define	MAZE_Y_ORIGIN	451
X#define	SCORE_X_DIM	192
X#define	SCORE_Y_DIM	(scoreFontInfo.height * MAXRATS)
X#define	SCORE_X_ORIGIN	208
X#define	SCORE_Y_ORIGIN	708
X#define	MIN_X_DIM	608		/* see comments for InitWindow() */
X#define	MIN_Y_DIM	SCORE_Y_ORIGIN	/* see InitWindow() */
X
X#define DEFAULT_BORDER_WIDTH 3
X#define DEFAULT_FONT "helv10b"
X#define DEFAULT_POSITION "=%dx%d+0+0"	/* upper left hand corner */
X
X#define	KC_A	0302			/* interesting letter keycodes */
X#define	KC_D	0315
X#define	KC_F	0322
X#define	KC_I	0346
X#define	KC_K	0347
X#define	KC_S	0307
X#define	KC_Q	0301
X#define	KC_O	0353
X#define	KC_L	0354
X#define	KC_DEL	0274
X#define	KC_BAR	0324
X
Xshort	mazeBits[MAZEXMAX*MAZEYMAX*16]; /* shorts better be 16 bits! */
XWindow	mwWindow;			/* parent window */
XOpaqueFrame	mwWin;			/* frame for the window */
XWindow	viewWindow;			/* view subwindow */
XWindow	mazeWindow;			/* maze subwindow */
XWindow	scoreWindow;			/* score subwindow */
XWindow	iconWindow;			/* icon window */
XPixmap	mazePixmap;			/* Pixmap that has the maze */
XPixmap	ratsPixmap;			/* Pixmap that has the rats */
XBitmap	iconMask;			/* mask for icon outline */
Xint	background;			/* color of background */
Xint	foreground;			/* color of lines and such */
Xint	iconFore;			/* icon foreground */
Xint	iconBack;			/* icon background */
Xint	mouseground;			/* mouse cursor color */
Xint	highlight;			/* flash colors */
XFont	scoreFont;			/* font for printing scores */
Xchar	*fontName =	DEFAULT_FONT;	/* font for scores */
XFontInfo	scoreFontInfo;
XBoolean	mapped =	FALSE;		/* should really display? */
XBoolean	inverted =	FALSE;		/* user warned of window exit */
XBoolean	flashIcon =	FALSE;		/* should icon be flashing? */
XBoolean	iconMapped =	FALSE;		/* is icon on screen? */
Xint	displayFD;			/* fd of display for events */
X
Xstatic short grayBits[16] = {
X    0xaaaa, 0x5555, 0xaaaa, 0x5555,
X    0xaaaa, 0x5555, 0xaaaa, 0x5555,
X    0xaaaa, 0x5555, 0xaaaa, 0x5555,
X    0xaaaa, 0x5555, 0xaaaa, 0x5555
X};
X
X#include "bitmaps/X10/rat.cur"
X#include "bitmaps/X10/ratMask.cur"
X#include "bitmaps/X10/dRat.cur"
X#include "bitmaps/X10/dRatMask.cur"
X#include "bitmaps/X10/cup.cur"
X
Xstatic Cursor	ratCursor, deadRatCursor, hourGlassCursor;
Xstatic int	planeMask, planePixels;
X
Xextern char	*getenv();
Xextern int	errno;
X
X/* state between InitWindow() and StartWindow() */
Xstatic char	*geometry = NULL;
Xstatic int	borderPixmap;
Xstatic int	borderWidth = DEFAULT_BORDER_WIDTH;
Xstatic char	def[128];
Xstatic char	*progName;
X
X/* 
X * ALL COORDINATES ASSUME ORIGIN (0,0) AT UPPER LEFT!
X */
X
X/* 
X * Initialize the window. The overall window must be at least 608x by
X * 808y (the size of the Alto screen). There are three distinct
X * subregions:
X *	A 400x by 400y area for the view, beginning at (100,50)
X *	A 512x by 256y area for the maze, beginning at (48, 451)
X *	A 192x by 96y area for the score lines, at (208, 706)
X *
X *	Actually, the y dimension of both the whole window and the score
X *	subwindow must be enough to accommodate MAXRATS lines of the
X *	height of the scoreFont.
X */
X
X/* parse arguments and set up window state */
X
XInitWindow(argc, argv)
Xchar	**argv;
X{
X	int	i;
X	char	display[256];		/* will contain vs host */
X	int	reverse = 0;
X	char	*borderColor;
X	char	*foreColor;
X	char	*backColor;
X	char	*highColor;
X	char	*mouseColor;
X	Color	cdef;
X	char	*option;
X	
X	display[0] = '\0';
X	progName = argv[0];
X
X	if ((option = XGetDefault(argv[0],"ReverseVideo")) != NULL )
X		if (strcmp (option, "on") == 0)
X			reverse = 1;
X	if ((option = XGetDefault(argv[0],"BorderWidth")) != NULL)
X		borderWidth = atoi(option);
X	if ((option = XGetDefault(argv[0],"BodyFont")) != NULL)
X		fontName = option;
X	if ((borderColor = XGetDefault(argv[0],"Border")) == NULL)
X		borderColor = XGetDefault(argv[0],"BorderColor");
X	backColor = XGetDefault(argv[0],"Background");
X	foreColor = XGetDefault(argv[0],"Foreground");
X	highColor = XGetDefault(argv[0],"Highlight");
X	mouseColor = XGetDefault(argv[0],"Mouse");
X
X	for (i = 1; i < argc; i++) {	/* Parse line */
X		if (argv[i][0] == '=') {
X			geometry = argv[i];
X			continue;
X		}
X		if (index(argv[i], ':') != NULL) {	/* host:display */
X			strncpy(display, argv[i], sizeof(display));
X			continue;
X		}
X		if (strcmp(argv[i], "-rv") == 0 ||
X		    strcmp(argv[i], "-reverse") == 0) {	/* white on black */
X			reverse = 1;
X			continue;
X		}
X		if (strcmp(argv[i], "-fw") == 0 ||
X		    strcmp(argv[i], "-forward") == 0) {	/* black on white */
X			reverse = 0;
X			continue;
X		}
X		if (strcmp(argv[i], "-bw") == 0 ||
X		    strcmp(argv[i], "-border") == 0) {	/* border width */
X			if (++i >= argc) usage();
X			borderWidth = atoi(argv[i]);
X			continue;
X		}
X		if (strcmp(argv[i], "-fn") == 0 ||
X		    strcmp(argv[i], "-font") == 0) {	/* score font */
X			if (++i >= argc) usage();
X			fontName = argv[i];
X			continue;
X		}
X		if (strcmp(argv[i], "-bd") == 0 ||
X		    strcmp(argv[i], "-color") == 0) {	/* border color */
X			if (++i >= argc) usage();
X			borderColor = argv[i];
X			continue;
X		}
X		if (strcmp(argv[i], "-fg") == 0 ||
X		    strcmp(argv[i], "-foreground") == 0) { /* foreground color */
X			if (++i >= argc) usage();
X			foreColor = argv[i];
X			continue;
X		}
X		if (strcmp(argv[i], "-bg") == 0 ||
X		    strcmp(argv[i], "-background") == 0) { /* background color */
X			if (++i >= argc) usage();
X			backColor = argv[i];
X			continue;
X		}
X		if (strcmp(argv[i], "-ms") == 0 ||
X		    strcmp(argv[i], "-mouse") == 0) { /* mouse color */
X			if (++i >= argc) usage();
X			mouseColor = argv[i];
X			continue;
X		}
X		if (strcmp(argv[i], "-hl") == 0 ||
X		    strcmp(argv[i], "-highlight") == 0) { /* highlight color */
X			if (++i >= argc) usage();
X			highColor = argv[i];
X			continue;
X		}
X		usage();
X	}
X
X	if (borderWidth < 0) borderWidth = DEFAULT_BORDER_WIDTH;
X
X	/* Open display  */
X	if (!XOpenDisplay(display))
X		MWError("cannot open display");
X
X	/* Need a font to print scores */
X	scoreFont = XGetFont(fontName);
X	if (!scoreFont)
X		MWError("cannot open font");
X	XQueryFont(scoreFont, &scoreFontInfo);	/* or XOpenFont */
X
X	if (DisplayCells() > 2)		/* get some color map to play with */
X		XGetColorCells(0, 1, 1, &planeMask, &planePixels);
X	else
X		planeMask = AllPlanes;
X
X	if (borderColor && DisplayCells() > 2 &&
X	    XParseColor(borderColor, &cdef) && XGetHardwareColor(&cdef))
X		borderPixmap = XMakeTile(cdef.pixel);
X	else if (borderColor && strcmp(borderColor, "black") == 0)
X		borderPixmap = BlackPixmap;
X	else if (borderColor && strcmp(borderColor, "white") == 0)
X		borderPixmap = WhitePixmap;
X	else
X		borderPixmap = XMakePixmap (
X				(Bitmap) XStoreBitmap (16, 16, grayBits),
X				BlackPixel, WhitePixel);
X
X	if (backColor && strcmp(backColor, "white") == 0) {
X		background = WhitePixel;
X		reverse = 0;
X	} else if (backColor && strcmp(backColor, "black") == 0) {
X		background = BlackPixel;
X		reverse = 0;
X	} else
X		background = WhitePixel;
X	if (DisplayCells() > 2) {
X		if (backColor == NULL)
X			backColor = "white";
X		if (XParseColor(backColor, &cdef)) {
X			if (reverse)
X				cdef.pixel = planePixels | planeMask;
X			else
X				cdef.pixel = planePixels;
X			XStoreColor(&cdef);
X			background = cdef.pixel;
X		}
X	}
X
X	if (foreColor && strcmp(foreColor, "black") == 0) {
X		foreground = BlackPixel;
X		reverse = 0;
X	} else if (foreColor && strcmp(foreColor, "white") == 0) {
X		foreground = WhitePixel;
X		reverse = 0;
X	} else
X		foreground = BlackPixel;
X	if (DisplayCells() > 2) {
X		if (foreColor == NULL)
X			foreColor = "black";
X		if (XParseColor(foreColor, &cdef)) {
X			if (reverse)
X				cdef.pixel = planePixels;
X			else
X				cdef.pixel = planePixels | planeMask;
X			XStoreColor(&cdef);
X			foreground = cdef.pixel;
X		}
X	}
X
X	if (mouseColor && DisplayCells() > 2 &&
X	    XParseColor(mouseColor, &cdef) && XGetHardwareColor(&cdef)) {
X		mouseground = cdef.pixel;
X	} else if (mouseColor && strcmp(mouseColor, "black") == 0) {
X		mouseground = BlackPixel;
X		reverse = 0;
X	} else if (mouseColor && strcmp(mouseColor, "white") == 0) {
X		mouseground = WhitePixel;
X		reverse = 0;
X	} else
X		mouseground = BlackPixel;
X
X	if (highColor && DisplayCells() > 2 &&
X	    XParseColor(highColor, &cdef) && XGetHardwareColor(&cdef))
X		highlight = cdef.pixel;
X	else if (reverse)
X		highlight = background;
X	else
X		highlight = foreground;
X
X	if (reverse) {
X		background = foreground;
X		foreground = highlight;
X	}
X}
X
X/* 
X * actually start the display up, after all the user interaction has
X * been done.
X */
X
XStartWindow(ratBits, ratWidth, ratHeight)
Xshort	*ratBits;
X{
X	WindowInfo mwInfo;
X
X	mwWin.bdrwidth = borderWidth;
X	mwWin.border = borderPixmap;
X	mwWin.background = XMakeTile(background);
X	sprintf(def, DEFAULT_POSITION, MIN_X_DIM,
X		MIN_Y_DIM + (MAXRATS+1) * scoreFontInfo.height);
X	mwWindow = XCreate ("Maze War", progName, geometry, def, &mwWin,
X		   MIN_X_DIM, MIN_Y_DIM + (MAXRATS+1) * scoreFontInfo.height);
X
X	/* set up the subwindows */
X	/* see above comment for magic numbers */
X	viewWindow = XCreateTransparency(mwWindow, VIEW_X_ORIGIN,
X			VIEW_Y_ORIGIN, VIEW_X_DIM, VIEW_Y_DIM);
X	mazeWindow = XCreateTransparency(mwWindow, MAZE_X_ORIGIN,
X			MAZE_Y_ORIGIN, MAZE_X_DIM, MAZE_Y_DIM);
X	scoreWindow = XCreateTransparency(mwWindow, SCORE_X_ORIGIN,
X			SCORE_Y_ORIGIN, SCORE_X_DIM, SCORE_Y_DIM);
X	
X	/* set up the icon */
X	XQueryWindow(mwWindow, &mwInfo);
X	iconWindow = XCreateWindow(RootWindow,
X				mwInfo.x + (mwInfo.width - icon_width) / 2,
X				mwInfo.y + (mwInfo.height - icon_height) / 2,
X				icon_width, icon_height, 0, 0, 0);
X	XTileRelative(iconWindow);
X	XSetIconWindow(mwWindow, iconWindow);
X	iconMask = XStoreBitmap(icon_mask_width, icon_mask_height,
X				icon_mask_bits);
X	XSelectInput(iconWindow, ExposeWindow|UnmapWindow);
X	iconFore = foreground;
X	iconBack = background;
X				
X	initCursors();
X
X	XSelectInput(mwWindow,
X		KeyPressed|ButtonPressed|ButtonReleased|
X		EnterWindow|LeaveWindow|ExposeWindow|UnmapWindow);
X	XMapWindow(viewWindow);
X	XMapWindow(mazeWindow);
X	XMapWindow(scoreWindow);
X	HourGlassCursor();
X	XMapWindow(mwWindow);		/* Map window to screen */
X
X	initMaze();
X	FlipBitmaps();			/* bit-reverse all the bitmaps */
X	initRats(ratBits, ratWidth, ratHeight);
X
X	displayFD = dpyno();
X}
X
X/*
X * Shut down the window system, resetting any terminal modes or what
X * have you that may have been altered. No-op for X V10.
X */
X
XStopWindow()
X{
X	
X}
X
X/* 
X * Clear out the view subwindow. If possible, delay the visible effect
X * until all the lines have been drawn (since this is only called by
X * ShowView(), which is about to draw a bunch of lines).
X */
X
XClearView()
X{
X	XClear(viewWindow);
X}
X
X/*
X * Flash the view window to indicate a hit on an opponent.
X */
X
XFlashTop()
X{
X	XCopyArea(viewWindow, 0, 0, 0, 0, VIEW_X_DIM, VIEW_Y_DIM,
X		GXinvert, planeMask);
X	XFlush();
X
X	/* might want some delay here */
X
X	XCopyArea(viewWindow, 0, 0, 0, 0, VIEW_X_DIM, VIEW_Y_DIM,
X		GXinvert, planeMask);
X	XFlush();
X}
X
X/*
X * Flash the whole window to indicate we were hit.
X */
X
XFlashScreen()
X{
X	XCopyArea(mwWindow, 0, 0, 0, 0, mwWin.width, mwWin.height,
X		GXinvert, planeMask);
X	XFlush();
X
X	/* might want some delay here */
X
X	XCopyArea(mwWindow, 0, 0, 0, 0, mwWin.width, mwWin.height,
X		GXinvert, planeMask);
X	XFlush();
X}
X
X/* 
X * Draw a line in the view subwindow. Don't show it right away if possible.
X */
X
XDrawViewLine(x1, y1, x2, y2)
X{
X	XLine(viewWindow, x1, y1, x2, y2, 1, 1,
X		foreground, GXcopy, planeMask);
X}
X
X/* 
X * Event handling. Presents a uniform event interface to the game, and
X * handles all other events in here. The game only sees the events
X * that affect it directly, as defined in mazewar.h. They are:
X *
X *	keypresses that affect the game
X *	mouse button clicks
X *	incoming network packets
X *	timeouts (there's a "heartbeat" to drive the shot clock)
X *
X * All other events should be swallowed by this routine. Also, since
X * keyboard focus is dependent on the mouse being in the game window,
X * try to let the user know that he's wandered outside the window
X * by inverting the window (should make it obvious) and is now vulnerable
X * and defenseless.
X */
X
Xvoid
XNextEvent(event)
XMWEvent	*event;
X{
X	int	fdmask;
X	XEvent	xEvent;
X	struct timeval timeout;
X	int	ret;
X
X    while (1) {
X	if (flashIcon) {		/* invert the icon colors */
X		int	temp;
X
X		temp = iconFore;
X		iconFore = iconBack;
X		iconBack = temp;
X		repaintIcon();
X	}
X
X	/* must do this every time, since M.theSocket may change! */
X	fdmask = (1 << displayFD) | (1 << M.theSocket);
X	if (!XPending()) {
X		timeout.tv_sec = 0;
X		timeout.tv_usec = 250000;
X		while ((ret = select(32, &fdmask, NULL, NULL, &timeout)) == -1)
X			if (errno != EINTR)
X				MWError("select error on events");
X		if (ret == 0) {
X			event->eventType = EVENT_TIMEOUT;
X			return;
X		}
X	} else
X		fdmask = 0;
X	if (XPending()) {
X		XNextEvent(&xEvent);
X		switch (xEvent.type) {
X		case KeyPressed:
X			event->eventType = 0;
X			switch(((XKeyEvent *) &xEvent)->detail & 0xff) {
X			case KC_A:
X			case KC_KEYPAD_4:
X				event->eventType = EVENT_A;
X				return;
X
X			case KC_S:
X			case KC_KEYPAD_5:
X				event->eventType = EVENT_S;
X				return;
X
X			case KC_D:
X			case KC_KEYPAD_6:
X				event->eventType = EVENT_D;
X				return;
X
X			case KC_F:
X			case KC_KEYPAD_COMMA:
X				event->eventType = EVENT_F;
X				return;
X
X			case KC_BAR:
X			case KC_CURSOR_RIGHT:
X				event->eventType = EVENT_BAR;
X				return;
X
X			case KC_I:
X				event->eventType = EVENT_I;
X				return;
X
X			case KC_K:
X				event->eventType = EVENT_K;
X				return;
X
X			case KC_O:
X				event->eventType = EVENT_O;
X				return;
X
X			case KC_L:
X				event->eventType = EVENT_L;
X				return;
X
X			case KC_Q:
X			case KC_DEL:
X				/* should also deal with Interrupt char */
X				event->eventType = EVENT_INT;
X				return;
X			}
X			break;
X
X#define	RightButton	0
X#define	MiddleButton	1
X#define	LeftButton	2
X		case ButtonPressed:
X			event->eventType = 0;
X			switch(((XButtonPressedEvent *) &xEvent)->detail&0xff) {
X			case RightButton:
X				event->eventType = EVENT_RIGHT_D;
X				return;
X
X			case MiddleButton:
X				event->eventType = EVENT_MIDDLE_D;
X				return;
X
X			case LeftButton:
X				event->eventType = EVENT_LEFT_D;
X				return;
X			}
X			break;
X
X		case ButtonReleased:
X			event->eventType = 0;
X			switch(((XButtonReleasedEvent *) &xEvent)->detail&0xff) {
X			case RightButton:
X				event->eventType = EVENT_RIGHT_U;
X				return;
X
X			case LeftButton:
X				event->eventType = EVENT_LEFT_U;
X				return;
X			}
X			break;
X
X		case EnterWindow:
X			if (xEvent.subwindow != 0)
X				break;
X			if ((((XEnterWindowEvent *)&xEvent)->detail&0xff) == 1)
X				break;
X			if (inverted == TRUE) {
X				inverted = FALSE;
X				invertDisplay();
X			}
X			break;
X
X		case LeaveWindow:
X			if (xEvent.subwindow != 0)
X				break;
X			if ((((XLeaveWindowEvent *)&xEvent)->detail&0xff) == 1)
X				break;
X			if (inverted == FALSE) {
X				inverted = TRUE;
X				invertDisplay();
X			}
X			break;
X
X		case ExposeWindow:
X			if (((XExposeWindowEvent *)&xEvent)->window
X			    == iconWindow) {
X				if (iconMapped == FALSE) {
X					flashIcon = FALSE;
X					iconMapped = TRUE;
X					iconFore = foreground;
X					iconBack = background;
X				}
X				repaintIcon();
X				break;
X			}
X			mapped = TRUE;
X			if (inverted == TRUE) {
X				inverted = FALSE;
X				invertDisplay();
X			}
X			repaintWindow();
X			break;
X
X		case UnmapWindow:
X			if (((XUnmapEvent *)&xEvent)->window
X			    == iconWindow) {
X				flashIcon = FALSE;
X				iconMapped = FALSE;
X				break;
X			}
X			mapped = FALSE;
X			break;
X		}
X	}
X
X	if (fdmask & (1 << M.theSocket)) {
X		int fromLen = sizeof(event->eventSource);
X		int cc;
X
X		event->eventType = EVENT_NETWORK;
X		cc = recvfrom(M.theSocket, event->eventDetail,
X			sizeof(RatPacket), 0, &event->eventSource, &fromLen);
X		if (cc <= 0) {
X			if (cc < 0 && errno != EINTR)
X				perror("event recvfrom");
X			continue;
X		}
X		if (fromLen != sizeof(struct sockaddr_in))
X			continue;
X		ConvertIncoming(event->eventDetail);
X		return;
X	}
X    }
X}
X
X/* 
X * Peek to see if there's a keyboard event waiting, in case the
X * program wants to short-circuit some code. If your system won't let
X * you implement this feature easily, just always return FALSE.
X */
X
XBoolean
XKBEventPending()
X{
X	return (QLength() != 0);
X}
X
X/* Please stand by ... */
X
XHourGlassCursor()
X{
X	XDefineCursor(mwWindow, hourGlassCursor);
X	XFlush();
X}
X
X/* Let the games begin! */
XRatCursor()
X{
X	XDefineCursor(mwWindow, ratCursor);
X	XFlush();
X}
X
X/* He's dead, Jim ... or might be */
XDeadRatCursor()
X{
X	XDefineCursor(mwWindow, deadRatCursor);
X	XFlush();
X}
X
X/* update the displayed bitmap */
X
XHackMazeBitmap(x, y, newBits)
XBitCell *newBits;
X{
X	XBitmapBitsPut(mazeWindow, x*16, y*16, 16, 16, newBits,
X			foreground, background, 0, GXcopy, planeMask);
X	XFlush();
X}
X
X/*
X * Display a rat. X is clever enough that the server does all the work for
X * you; provides a generalized bitblt on Pixmaps. Hopefully other window
X * systems do as well. Width, height, srcX and srcY describe the subbitmap
X * in the rats bitmap that is the desired view of the opponent.
X */
X
XDisplayRatBitmap(screenX, screenY, width, height, srcX, srcY)
X{
X	XPixmapPut(viewWindow, srcX, srcY, screenX, screenY,
X		width, height, ratsPixmap, GXxor, planeMask);
X}
X
X/* 
X * Display the score line for the indicated player. Name is left
X * justified, score is right justified within the score window.
X */
X
XWriteScoreString(rat)
XRatId	rat;
X{
X	char	buf[64];
X	int	leftEdge;
X
X	sprintf(buf, "%d", (unsigned int) M.ratcb.rats[rat].score);
X
X	XText(scoreWindow, 0, rat * scoreFontInfo.height,
X		M.ratcb.rats[rat].name, strlen(M.ratcb.rats[rat].name),
X		scoreFont, foreground, background);
X	/* or XQueryWidth for speed, must XOpenFont above */
X	leftEdge = SCORE_X_DIM - XQueryWidth(buf, scoreFont, 0, 0);
X	XText(scoreWindow, leftEdge, rat * scoreFontInfo.height,
X		buf, strlen(buf),
X		scoreFont, foreground, background);
X}
X
X/* 
X * Clear out the score line for a player that's left the game.
X */
X
XClearScoreLine(rat)
XRatId	rat;
X{
X	XPixSet(scoreWindow,
X		0, rat * scoreFontInfo.height,
X		SCORE_X_DIM, scoreFontInfo.height,
X		background);
X}
X
X/* 
X * Pretty obvious, eh? Means the guy's in sight.
X */
X
XInvertScoreLine(rat)
XRatId	rat;
X{
X	XCopyArea(scoreWindow,
X		0, rat * scoreFontInfo.height,
X		0, rat * scoreFontInfo.height,
X		SCORE_X_DIM, scoreFontInfo.height,
X		GXinvert, planeMask);
X}
X
X/* 
X * Let the user know that a new player joined. This really should only
X * take effect if the window is iconic, so you can keep a game around
X * all day, close it up when there's no activity, and know when
X * someone else is also out to kill some time.
X */
X
XNotifyPlayer()
X{
X	flashIcon = TRUE;
X}
X
X/*
X * END PUBLIC ROUTINES
X */
X
X/* set up needed bitmaps in the server */
X
XinitCursors()
X{
X	ratCursor = XCreateCursor(16, 16, rat_bits, ratMask_bits,
X				0, 0, mouseground, background, GXcopy);
X	deadRatCursor = XCreateCursor(16, 16, deadRat_bits, deadRatMask_bits,
X				0, 0, mouseground, background, GXcopy);
X	hourGlassCursor = XCreateCursor(16, 16, coffeeCup_bits, coffeeCup_bits,
X				0, 0, mouseground, background, GXcopy);
X}
X
X/*
X * construct a Pixmap of the maze, and store it in the server.
X */
X
XinitMaze()
X{
X	register int	i, j, k, line, index;
X	Bitmap		b;
X
X	for (i = 0; i < MAZEYMAX; i++) {
X		line = i * MAZEXMAX * MAZEYMAX;
X		for (j = 0; j < MAZEXMAX; j++) {
X			index = line + j;
X			for (k = 0; k < 16; k++) {
X				if (M.maze[j].y[i])
X					mazeBits[index] = 0177777;
X				else
X					mazeBits[index] = 0;
X				index += 32;
X			}
X					
X		}
X	}
X
X	b = XStoreBitmap(MAZE_X_DIM, MAZE_Y_DIM, mazeBits);
X	mazePixmap = XMakePixmap(b, foreground, background);
X	if (mazePixmap == 0)
X		MWError("Can't create maze Pixmap");
X	XFreeBitmap(b);
X}
X
X/*
X * actually put the maze Pixmap on the screen
X */
X
XdrawMaze()
X{
X	XPixmapPut(mazeWindow, 0, 0, 0, 0, MAZE_X_DIM, MAZE_Y_DIM,
X		mazePixmap, GXcopy, planeMask);
X}
X
X/* 
X * send the rat image bitmap to the server so we can do arbitrary
X * bitblts on them later. X10 doesn't allow you to do this on bitmaps,
X * just pixmaps. Ga.
X */
X
XinitRats(bits, width, height)
Xshort *bits;
X{
X	Bitmap b;
X
X	b = XStoreBitmap(width, height, bits);
X	if (DisplayCells() > 2)
X		ratsPixmap = XMakePixmap(b, planeMask, 0);
X	else
X		ratsPixmap = XMakePixmap(b, 1, 0);
X	if (ratsPixmap == 0)
X		MWError("Can't create rats Pixmap");
X	XFreeBitmap(b);	
X}
X
Xusage()
X{
X	fprintf(stderr,
X"usage: mazewar [-fn {font}] [-update {seconds}] [-scale {integer}] [-rv]\n"
X);
X	fprintf(stderr,
X"             [=[{width}][x{height}][{+-}{xoff}[{+-}{yoff}]]] [[{host}]:[{vs}]]\n"
X);
X	fprintf(stderr,
X"             [-fg {color}] [-bg {color}] [-hl {color}] [-bd {color}]
[-bw {pixels}]\n");
X    exit(1);
X	
X}
X
X/*
X * Repaint the window for exposure and resize events. All drawing is
X * done here, even though there are times during the initialization
X * code when it would seem obvious to put some of the display up; this
X * way portions of the display aren't shown twice then.
X */
X
XrepaintWindow()
X{
X	drawMaze();
X	ShowPosition(M.xloc, M.yloc, M.invincible, M.dir);
X	ShowView(M.xloc, M.yloc, M.dir);
X	ShowAllPositions();
X
X	NewScoreCard();
X	XFlush();
X}
X
X/* 
X * Repaint the icon for exposure events, or while flashing to indicate
X * that there's a new player. 
X */
X
XrepaintIcon()
X{
X	int	temp;
X	
X	XBitmapBitsPut(iconWindow, 0, 0, icon_width, icon_height, icon_bits,
X		iconFore, iconBack, iconMask, GXcopy, AllPlanes);
X}
X
X/* 
X * Invert the whole display. Used to let the user know the mouse has
X * strayed outside the window. Doesn't currently work right.
X */
X
XinvertDisplay()
X{
X#ifdef	notdef
X	XCopyArea(mwWindow, 0, 0, 0, 0, mwWin.width, mwWin.height,
X		GXinvert, planeMask);
X	XFlush();
X#endif
X}
xxFUNNYxx