[comp.sources.x] v05i010: Xchomp -- Pac-Man

argv@island.uu.net (Dan Heller) (10/14/89)

Submitted-by: Jerry Shekhel <eddie.mit.edu!polygen!jerry>
Posting-number: Volume 5, Issue 10
Archive-name: xchomp/part01



#! /bin/sh
# This is a shell archive.  Remove anything before this line, then feed it
# into a shell via "sh file" or similar.  To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
# If this archive is complete, you will see the following message at the end:
#		"End of archive 1 (of 3)."
# Contents:  xchomp/Makefile xchomp/bitmaps xchomp/bitmaps/demo/
#   xchomp/bitmaps/frame/ xchomp/bitmaps/fruit/
#   xchomp/bitmaps/fruit/ff1.h xchomp/bitmaps/maze/
#   xchomp/bitmaps/pac/ xchomp/contact.c xchomp/drivers.c
#   xchomp/main.c xchomp/resources.c
# Wrapped by argv@island on Fri Oct 13 12:17:29 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
mkdir xchomp
if test -f 'xchomp/Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xchomp/Makefile'\"
else
echo shar: Extracting \"'xchomp/Makefile'\" \(1002 characters\)
sed "s/^X//" >'xchomp/Makefile' <<'END_OF_FILE'
X
X#
X#		MAKEFILE FOR XCHOMP
X#
X
X
X#
X# Add -DFRAME_DELAY=xxxxx to CFLAGS if the game runs too fast without it.
X# The "xxxxx" is the number of microseconds to wait between motion frames.
X#
X
XCFLAGS		= -O
X
XCC		= cc $(CFLAGS)
X
XOBJECTS		= contact.o \
X		  demo.o \
X		  drivers.o \
X		  main.o \
X		  maze.o \
X		  props.o \
X		  resources.o \
X		  status.o
X
XBITMAPFILES	= bitmaps/demo/*.h \
X		  bitmaps/frame/*.h \
X		  bitmaps/fruit/*.h \
X		  bitmaps/maze/*.h \
X		  bitmaps/pac/*.h
X
Xxchomp:	$(OBJECTS)
X	$(CC) -o xchomp $(OBJECTS) -lX11
X	strip xchomp
X
Xcontact.o: contact.c xchomp.h
X	$(CC) -c contact.c
X
Xdemo.o: demo.c xchomp.h
X	$(CC) -c demo.c
X
Xdrivers.o: drivers.c xchomp.h
X	$(CC) -c drivers.c
X
Xmain.o: main.c xchomp.h
X	$(CC) -c main.c
X
Xmaze.o: maze.c xchomp.h
X	$(CC) -c maze.c
X
Xprops.o: props.c xchomp.h
X	$(CC) -c props.c
X
Xresources.o: resources.c xchomp.h bitmaps.h
X	$(CC) -c resources.c
X
Xstatus.o: status.c xchomp.h
X	$(CC) -c status.c
X
Xbitmaps.h: $(BITMAPFILES)
X	cat $(BITMAPFILES) | sed '/^\#define/d' > bitmaps.h
END_OF_FILE
if test 1002 -ne `wc -c <'xchomp/Makefile'`; then
    echo shar: \"'xchomp/Makefile'\" unpacked with wrong size!
fi
# end of 'xchomp/Makefile'
fi
if test ! -d 'xchomp/bitmaps' ; then
    echo shar: Creating directory \"'xchomp/bitmaps'\"
    mkdir 'xchomp/bitmaps'
fi
if test ! -d 'xchomp/bitmaps/demo/' ; then
    echo shar: Creating directory \"'xchomp/bitmaps/demo/'\"
    mkdir 'xchomp/bitmaps/demo/'
fi
if test ! -d 'xchomp/bitmaps/frame/' ; then
    echo shar: Creating directory \"'xchomp/bitmaps/frame/'\"
    mkdir 'xchomp/bitmaps/frame/'
fi
if test ! -d 'xchomp/bitmaps/fruit/' ; then
    echo shar: Creating directory \"'xchomp/bitmaps/fruit/'\"
    mkdir 'xchomp/bitmaps/fruit/'
fi
if test -f 'xchomp/bitmaps/fruit/ff1.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xchomp/bitmaps/fruit/ff1.h'\"
else
echo shar: Extracting \"'xchomp/bitmaps/fruit/ff1.h'\" \(371 characters\)
sed "s/^X//" >'xchomp/bitmaps/fruit/ff1.h' <<'END_OF_FILE'
X#define ff1_width 20
X#define ff1_height 16
Xstatic char ff1_bits[] = {
X   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x63, 0x00,
X   0xa0, 0x94, 0x00, 0xa0, 0x94, 0x00, 0xa0, 0x94, 0x00, 0xa0, 0x94, 0x00,
X   0xa0, 0x94, 0x00, 0xa0, 0x94, 0x00, 0xa0, 0x94, 0x00, 0x20, 0x63, 0x00,
X   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
END_OF_FILE
if test 371 -ne `wc -c <'xchomp/bitmaps/fruit/ff1.h'`; then
    echo shar: \"'xchomp/bitmaps/fruit/ff1.h'\" unpacked with wrong size!
fi
# end of 'xchomp/bitmaps/fruit/ff1.h'
fi
if test ! -d 'xchomp/bitmaps/maze/' ; then
    echo shar: Creating directory \"'xchomp/bitmaps/maze/'\"
    mkdir 'xchomp/bitmaps/maze/'
fi
if test ! -d 'xchomp/bitmaps/pac/' ; then
    echo shar: Creating directory \"'xchomp/bitmaps/pac/'\"
    mkdir 'xchomp/bitmaps/pac/'
fi
if test -f 'xchomp/contact.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xchomp/contact.c'\"
else
echo shar: Extracting \"'xchomp/contact.c'\" \(5693 characters\)
sed "s/^X//" >'xchomp/contact.c' <<'END_OF_FILE'
X
X#include "xchomp.h"
X
X/*
X * This file contains player-ghost contact handling functions.
X * When a collision is detected, execution is vectored to one
X * of these functions, depending on the state of the ghost
X * with which the player collided.
X */
X
X
X/*
X * The following function is called when the player collides with
X * a solid ghost; the player dies.  This is the death sequence.
X * The parameter to this function, as well as all of the collision
X * handling function, is the number (array index) of the ghost
X * with which the player collided.  In this case, it doesn't matter.
X */
Xdie(dummy)
Xint dummy;
X{
X   register int xx = x[PAC_SLOT], yy = y[PAC_SLOT], i, dx, dy;
X   XImage       *old, *new;
X
X   /*
X    * Since the player may be facing one of four directions at
X    * the time of death, there would be way too many images for
X    * me to draw in order to handle all possible cases.  Therefore, I
X    * only drew the images for the case in which the player is facing
X    * left -- they are stored in dead_prot[].  The images for the
X    * other cases are generated here, dynamically, by using the
X    * Xlib image facilities.  Since we can easily read and place
X    * single pixels using images, we can rotate all the death frames
X    * to the desired direction very easily.  The final series of
X    * bitmaps is stored in deadpac[].
X    */
X   new = XGetImage(display, dead_prot[1], 0, 0, GHOST_SIZE,
X      GHOST_SIZE, 1, XYPixmap);
X   for (i = 0; i < 11; i++) {
X      old = XGetImage(display, dead_prot[i], 0, 0, GHOST_SIZE,
X         GHOST_SIZE, 1, XYPixmap);
X      for (dy = 0; dy < GHOST_SIZE; dy++)
X         for (dx = 0; dx < GHOST_SIZE; dx++)
X            if (pac == lpac)
X                XPutPixel(new, dx, dy, XGetPixel(old, dx, dy));
X            else if (pac == rpac)
X                XPutPixel(new, dx, dy, XGetPixel(old, GHOST_SIZE - dx - 1, dy));
X            else if (pac == dpac)
X                XPutPixel(new, dx, dy, XGetPixel(old, GHOST_SIZE - dy - 1, dx));
X            else
X                XPutPixel(new, dx, dy, XGetPixel(old, dy, dx));
X      XPutImage(display, deadpac[i], bitmapGC, new, 0, 0, 0, 0,
X         GHOST_SIZE, GHOST_SIZE);
X      XDestroyImage(old);
X   }
X   XDestroyImage(new);
X   sleep(1);
X
X   /* deactivate the fruit (if displayed) */
X   if (fruit_shown) {
X      XFillRectangle(display, save, clearGC, fruit_x - 2, fruit_y,
X         FRUIT_WIDTH, FRUIT_HEIGHT);
X      dd[fruit_y >> 4][fruit_x >> 4] = '\0';
X      ++fruit_times;
X      fruit_shown = False;
X   }
X
X   /*
X    * Now we'll get rid of all of the ghosts on the screen,
X    * and display the first frame of the death animation at the
X    * position of the player.
X    */
X   XCopyArea(display, save, map, fullcopyGC, 0, 0, WIN_WIDTH,
X      WIN_HEIGHT, 0, 0);
X   XCopyPlane(display, deadpac[0], map, orGC, 0, 0, GHOST_SIZE,
X      GHOST_SIZE, xx, yy, 1);
X   XCopyArea(display, map, window, fullcopyGC, 0, 0, WIN_WIDTH,
X      WIN_HEIGHT, 0, 0);
X   XSync(display, False);
X   sleep(1);
X
X   /*
X    * Now we'll cycle through the death animation frames using
X    * our normal animation mechanism.
X    */
X   for (i = 0; i < 11; i++) {
X      XCopyArea(display, save, map, fullcopyGC, xx, yy, GHOST_SIZE,
X         GHOST_SIZE, xx, yy);
X      XCopyPlane(display, deadpac[i], map, orGC, 0, 0, GHOST_SIZE,
X         GHOST_SIZE, xx, yy, 1);
X      XCopyArea(display, map, window, fullcopyGC, xx, yy, GHOST_SIZE,
X         GHOST_SIZE, xx, yy);
X      XSync(display, False);
X      usleep(125000);
X   }
X   usleep(150000);
X
X   /*
X    * Now we'll remove everything except the maze from the
X    * screen, and return.
X    */
X   XCopyArea(display, save, map, fullcopyGC, xx, yy, GHOST_SIZE,
X      GHOST_SIZE, xx, yy);
X   XCopyArea(display, map, window, fullcopyGC, xx, yy, GHOST_SIZE,
X      GHOST_SIZE, xx, yy);
X   XSync(display, False);
X   dead = True;
X}
X
X
X/*
X * The following function is executed when the player collides
X * with a transparent or flashing ghost; the player eats the
X * ghost.  The game pauses for a moment, displaying the value
X * of the eaten ghost, and then continues.  The parameter is
X * the array index of the eaten ghost.
X */
Xeat(i)
Xint i;
X{
X   register int  xx = x[PAC_SLOT], yy = y[PAC_SLOT], j;
X   static long   val[] = { 200, 400, 800, 1600 };
X
X   /*
X    * The image we want to create here is the following: all of
X    * the ghosts except the one being eaten are drawn, as well as
X    * the score value of the eaten ghost in the position of the
X    * player.  We'll use the normal method: first create the image
X    * on the map, and then copy the selected areas of the map onto
X    * the window.  The "copyGC" graphics context, at this point,
X    * should contain the necessary clipping information.
X    */
X   for (j = 0; j < PAC_SLOT; j++)
X      if (j != i)
X         XCopyPlane(display, ghost[j][count], map, orGC, 0, 0,
X            GHOST_SIZE, GHOST_SIZE, x[j], y[j], 1);
X   XCopyPlane(display, eat_pix[eat_index], map, orGC, 0, 0,
X      GHOST_SIZE, GHOST_SIZE, xx, yy, 1);
X   XCopyArea(display, map, window, copyGC, 0, 0, WIN_WIDTH,
X      WIN_HEIGHT, 0, 0);
X
X   /* adjust the score and wait a second */
X   print_score(val[eat_index]);
X   eat_index = (eat_index + 1) & 0x03;
X   XSync(display, False);
X   sleep(1);
X
X   /* remove all moving figures from the map */
X   XCopyArea(display, save, map, copyGC, 0, 0, WIN_WIDTH,
X      WIN_HEIGHT, 0, 0);
X
X   /*
X    * Now we'll change the ghost state, so that it appears
X    * as a pair of harmless eyes seeking return to the ghost
X    * box.
X    */
X   ghost[i] = eghost;
X   drive[i] = go_home;
X   contact[i] = noop;
X}
X
X
X/*
X * The following is the collision handler for ghost-eyes.
X * The eyes are harmless; this is a no-op.
X */
Xnoop(dummy)
Xint dummy;
X{
X}
X
END_OF_FILE
if test 5693 -ne `wc -c <'xchomp/contact.c'`; then
    echo shar: \"'xchomp/contact.c'\" unpacked with wrong size!
fi
# end of 'xchomp/contact.c'
fi
if test -f 'xchomp/drivers.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xchomp/drivers.c'\"
else
echo shar: Extracting \"'xchomp/drivers.c'\" \(20425 characters\)
sed "s/^X//" >'xchomp/drivers.c' <<'END_OF_FILE'
X
X#include "xchomp.h"
X
X/*
X * This file contains functions which control the motion of the player
X * and the ghosts.
X */
X
X
X/*
X * The following function is called explicitly during each animation
X * cycle, to control the motion of the player.  It updates the position
X * variables (x[], y[]), the direction variables (ix[], iy[]), and the
X * array of clipping rectangles (rectangle[]).
X */
Xcontrol_pac()
X{
X   register int         xx = x[PAC_SLOT], yy = y[PAC_SLOT], i, dx, dy;
X   register char        *pc = md[yy >> 4] + (xx >> 4);
X   register int         *px = ix + PAC_SLOT, *py = iy + PAC_SLOT;
X
X   /* check for a collision */
X   for (i = 0; i < PAC_SLOT; i++) {
X      dx = x[i] - xx;
X      dy = y[i] - yy;
X      if ((abs(dx) < 6) && (abs(dy) < 6))
X         (*contact[i])(i);
X      if (dead) return;
X   }
X
X   /*
X    * The rest of this function determines the direction of the
X    * player according to the surroundings and the last key pressed
X    * by the user.  This took a while to implement correctly, and I
X    * don't quite recall all of the reasoning that went into the
X    * implementation of this code.
X    */
X
X   if (!(xx & 0x0f) && !(yy & 0x0f)) {
X      if (*px > 0) {
X         if (pc[1]) *px = 0;
X      }
X      else if (*px < 0) {
X         if (pc[-1]) *px = 0;
X      }
X      else if (*py < 0) {
X         if (pc[-BLOCK_WIDTH]) *py = 0;
X      }
X      else if (pc[BLOCK_WIDTH]) *py = 0;
X      switch (last_key) {
X         case XK_Up:
X            if (!pc[-BLOCK_WIDTH]) *py = (-2), *px = 0, pac = upac;
X            break;
X         case XK_Down:
X            if (!pc[BLOCK_WIDTH]) *py = 2, *px = 0, pac = dpac;
X            break;
X         case XK_Left:
X            if (!pc[-1]) *px = (-2), *py = 0, pac = lpac;
X            break;
X         case XK_Right:
X            if (!pc[1]) *px = 2, *py = 0, pac = rpac;
X            break;
X         default: break;
X      }
X      check_dots();
X      rectangle[PAC_SLOT].x = (x[PAC_SLOT] += *px) - 2;
X      rectangle[PAC_SLOT].y = (y[PAC_SLOT] += *py) - 2;
X      return;
X   }
X
X   if (*px > 0) {
X      if (last_key == XK_Left)
X         *px = (-2), pac = lpac;
X   }
X   else if (*px < 0) {
X      if (last_key == XK_Right)
X         *px = 2, pac = rpac;
X   }
X   else if (*py > 0) {
X      if (last_key == XK_Up)
X         *py = (-2), pac = upac;
X   }
X   else if (last_key == XK_Down)
X      *py = 2, pac = dpac;
X   rectangle[PAC_SLOT].x = (x[PAC_SLOT] += *px) - 2;
X   rectangle[PAC_SLOT].y = (y[PAC_SLOT] += *py) - 2;
X}
X
X
X/*
X * The following function checks to see whether the player has
X * eaten something which is not a ghost -- a dot, a power-dot,
X * or the fruit.  If so, the appropriate action is taken.
X */
Xcheck_dots()
X{
X   register char        *pi;
X   register int         i;
X   register funcptr     driver;
X   static long		fval[] = { 100, 200, 300, 300, 500, 700, 700,
X				   1000, 1000, 2000, 2000, 3000, 3000,
X				   5000 };
X
X   /*
X    * The following line produces a pointer to the character in the
X    * dot information array (dd[]) which corresponds to the player's
X    * position on the screen.
X    */
X   pi = dd[y[PAC_SLOT] >> 4] + (x[PAC_SLOT] >> 4);
X
X   /* check for a regular dot */
X   if (*pi == '.') {
X      *pi = '\0';
X
X      /* erase the dot from the background image */
X      XFillRectangle(display, save, clearGC, x[PAC_SLOT] + 6,
X         y[PAC_SLOT] + 6, 4, 4);
X      print_score(10L);
X      if (--numdots == 0) {
X         completed = True;
X         return;
X      }
X   }
X
X   /* check for a power-dot */
X   else if (*pi == 'O') {
X      *pi = '\0';
X
X      /*
X       * Here we'll erase the power-dot from both the power-dot
X       * map and the background map, so that it no longer flashes.
X       */
X      XFillRectangle(display, powermap, clearGC, x[PAC_SLOT],
X         y[PAC_SLOT], GHOST_SIZE, GHOST_SIZE);
X      XCopyArea(display, powermap, save, fullcopyGC, x[PAC_SLOT],
X         y[PAC_SLOT], GHOST_SIZE, GHOST_SIZE, x[PAC_SLOT], y[PAC_SLOT]);
X      print_score(50L);
X      if (--numdots == 0) {
X         completed = True;
X         return;
X      }
X
X      /* set up ghost-eating mode */
X      eat_index = 0;
X      eat_mode = True;
X      grey_tick = 0;
X      count_sync = count;
X
X      /*
X       * Change the state of each solid ghost to that of a white
X       * ghost running away from the player at half speed.
X       */
X      for (i = 0; i < PAC_SLOT; i++) {
X         if ((driver = drive[i]) == follow) {
X            drive[i] = run;
X            contact[i] = eat;
X            ghost[i] = gghost;
X            ix[i] = -ix[i] / 2;
X            iy[i] = -iy[i] / 2;
X         }
X         else if (driver == hover) {
X            drive[i] = hover2;
X            contact[i] = eat;
X            ghost[i] = gghost;
X            ix[i] /= 2;
X            iy[i] /= 2;
X         }
X         else if ((driver == hover2) || (driver == run))
X            ghost[i] = gghost;
X      }
X   }
X
X   /* check for the fruit */
X   else if (*pi == 'F') {
X      *pi = '\0';
X      print_score(fval[plevel]);
X
X      /*
X       * We have to do some fancy stuff here.  We want to instantly
X       * change the fruit on the screen to the image of a score value,
X       * without stopping the game (as with ghost eating).  The problem
X       * is that this subroutine is called AFTER the background image has
X       * been restored onto the map in the game loop, and therefore, AFTER
X       * the clipping information has been set for the pending screen
X       * update.  Therefore, we have to copy this image onto BOTH off-
X       * screen maps, and we have to reset the clipping information here,
X       * so that the image is displayed on the screen immediately.  This
X       * would not be a problem if the score value images were the same
X       * size as the player, as in the case of dots and power-dots.
X       */
X      XCopyPlane(display, fval_pix[plevel], save, fullcopyGC,
X	 0, 0, FRUIT_WIDTH, FRUIT_HEIGHT, fruit_x - 2, fruit_y, 1);
X      XCopyArea(display, save, map, fullcopyGC, fruit_x - 2,
X	 fruit_y, FRUIT_WIDTH, FRUIT_HEIGHT, fruit_x - 2, fruit_y);
X      XSetClipRectangles(display, copyGC, 0, 0, rectangle,
X	 NUM_FIGURES + MAX_POWER_DOTS + 1, Unsorted);
X
X      /*
X       * Now we'll set the fruit frame counter to 43.  The main loop will
X       * clear the fruit area when it is at 50, so the fruit score value
X       * will disappear nicely in a few seconds.
X       */
X      fruit_count = 43;
X   }
X}
X
X
X/*-- GHOST DRIVERS -----------------------------------------------------*/
X
X
X/*
X * The rest of this file contains ghost drivers.  These routines are invoked
X * through pointers, to control the motion of the ghosts.  There are several
X * of these routines, corresponding to the several different ghost states.
X * The parameter to each of these is the ghost number (array index) for which
X * to update the direction arrays (ix[], iy[]).
X */
X
X
X/*
X * The function below causes ghosts to follow the player around, with a bit
X * of randomness thrown in as well.
X */
Xfollow(i)
Xregister int i;
X{
X   register char  *pc = md[y[i] >> 4] + (x[i] >> 4);
X   register int   dir = 0x0f, sense;
X   register int   *px = ix + i, *py = iy + i;
X   int            xx = x[i], yy = y[i], pmx = x[PAC_SLOT], pmy = y[PAC_SLOT];
X   static intm    find[3] = { { 0, 1, 2 }, { 3, 3, 4 }, { 5, 6, 7 } };
X
X   static intm  fxvec[16] = {
X                { 0, 0, 0, 0, 0, 0, 0, 0 },             /* no way to go */
X                { 2, 2, 2, 2, 2, 2, 2, 2 },             /* right only */
X                { -2, -2, -2, -2, -2, -2, -2, -2 },     /* left only */
X                { -2, 2, 2, -2, 2, -2, -2, 2 },         /* left or right */
X                { 0, 0, 0, 0, 0, 0, 0, 0 },             /* down only */
X                { 2, 2, 2, 0, 2, 0, 0, 2 },             /* down or right */
X                { -2, -2, -2, -2, 0, 0, 0, 0 },         /* down or left */
X                { -2, -2, 2, -2, 2, -2, 0, 0 },         /* down, left, or right */
X                { 0, 0, 0, 0, 0, 0, 0, 0 },             /* up only */
X                { 0, 0, 0, 0, 2, 2, 2, 2 },             /* up or right */
X                { -2, 0, 0, -2, 0, -2, -2, -2 },        /* up or left */
X                { 0, 0, 2, -2, 2, -2, -2, 2 },          /* up, left, or right */
X                { 0, 0, 0, 0, 0, 0, 0, 0 },             /* up or down */
X                { 0, 0, 2, 0, 2, 0, 0, 2 },             /* up, down, or right */
X                { -2, 0, 0, -2, 0, 0, 0, 0 },           /* up, down, or left */
X                { -2, 0, 0, -2, 2, 0, 0, 2 } };         /* any which way */
X
X   static intm  fyvec[16] = {
X                { 0, 0, 0, 0, 0, 0, 0, 0 },             /* no way to go */
X                { 0, 0, 0, 0, 0, 0, 0, 0 },             /* right only */
X                { 0, 0, 0, 0, 0, 0, 0, 0 },             /* left only */
X                { 0, 0, 0, 0, 0, 0, 0, 0 },             /* left or right */
X                { 2, 2, 2, 2, 2, 2, 2, 2 },             /* down only */
X                { 0, 0, 0, 2, 0, 2, 2, 0 },             /* down or right */
X                { 0, 0, 0, 0, 2, 2, 2, 2 },             /* down or left */
X                { 0, 0, 0, 0, 0, 0, 2, 2 },             /* down, left, or right */
X                { -2, -2, -2, -2, -2, -2, -2, -2 },     /* up only */
X                { -2, -2, -2, -2, 0, 0, 0, 0 },         /* up or right */
X                { 0, -2, -2, 0, -2, 0, 0, 0 },          /* up or left */
X                { -2, -2, 0, 0, 0, 0, 0, 0 },           /* up, left, or right */
X                { -2, -2, -2, -2, 2, 2, 2, 2 },         /* up or down */
X                { -2, -2, 0, 2, 0, 2, 2, 0 },           /* up, down, or right */
X                { 0, -2, -2, 0, -2, 2, 2, 2 },          /* up, down, or left */
X                { 0, -2, -2, 0, 0, 2, 2, 0 } };         /* any which way */
X
X   /* first, find the directions in which this ghost can go */
X   if (pc[1] || (*px < 0)) dir &= ~0x01;
X   if (pc[-1] || (*px > 0)) dir &= ~0x02;
X   if (pc[BLOCK_WIDTH] || (*py < 0)) dir &= ~0x04;
X   if (pc[-BLOCK_WIDTH] || (*py > 0)) dir &= ~0x08;
X
X   /* now choose the new direction for the ghost */
X   if ((dir != 0x01) && (dir != 0x02) && (dir != 0x04) && (dir != 0x08)) {
X      if ((random() & 0x0f) > 4)
X         sense = find[sgn(pmy - yy) + 1][sgn(pmx - xx) + 1];
X      else sense = random() & 0x07;
X      *px = fxvec[dir][sense];
X      *py = fyvec[dir][sense];
X   }
X   else {
X      *px = *fxvec[dir];
X      *py = *fyvec[dir];
X   }
X}
X
X
X/*
X * The function below causes ghosts to run away from the player
X * at half speed.  It is set up as the driver function during
X * the ghost-eating periods of the game.
X */
Xrun(i)
Xregister int i;
X{
X   register char  *pc = md[y[i] >> 4] + (x[i] >> 4);
X   register int   dir = 0x0f, sense;
X   register int   *px = ix + i, *py = iy + i;
X   int            xx = x[i], yy = y[i], pmx = x[PAC_SLOT], pmy = y[PAC_SLOT];
X   static intm    find[3] = { { 0, 1, 2 }, { 3, 3, 4 }, { 5, 6, 7 } };
X
X   static intm  rxvec[16] = {
X                { 0, 0, 0, 0, 0, 0, 0, 0 },             /* no way to go */
X                { 1, 1, 1, 1, 1, 1, 1, 1 },             /* right only */
X                { -1, -1, -1, -1, -1, -1, -1, -1 },     /* left only */
X                { 1, -1, -1, 1, -1, 1, 1, -1 },         /* left or right */
X                { 0, 0, 0, 0, 0, 0, 0, 0 },             /* down only */
X                { 0, 1, 0, 0, 0, 1, 1, 0 },             /* down or right */
X                { 0, -1, -1, 0, 0, 0, -1, -1 },         /* down or left */
X                { 1, 1, -1, 0, 0, 1, 1, -1 },           /* down, left, or right */
X                { 0, 0, 0, 0, 0, 0, 0, 0 },             /* up only */
X                { 1, 1, 0, 0, 0, 1, 1, 0 },             /* up or right */
X                { 0, -1, -1, 0, 0, 0, -1, -1 },         /* up or left */
X                { 1, -1, -1, 0, 0, 0, -1, -1 },         /* up, left, or right */
X                { 0, 0, 0, 0, 0, 0, 0, 0 },             /* up or down */
X                { 0, 1, 0, 0, 0, 1, 1, 0 },             /* up, down, or right */
X                { 0, -1, -1, 0, 0, 0, -1, -1 },         /* up, down, or left */
X                { 1, -1, 0, 0, 0, 0, 1, -1 } };         /* any which way */
X
X   static intm  ryvec[16] = {
X                { 0, 0, 0, 0, 0, 0, 0, 0 },             /* no way to go */
X                { 0, 0, 0, 0, 0, 0, 0, 0 },             /* right only */
X                { 0, 0, 0, 0, 0, 0, 0, 0 },             /* left only */
X                { 0, 0, 0, 0, 0, 0, 0, 0 },             /* left or right */
X                { 1, 1, 1, 1, 1, 1, 1, 1 },             /* down only */
X                { 1, 0, 1, 1, 1, 0, 0, 1 },             /* down or right */
X                { 1, 0, 0, 1, 1, 1, 0, 0 },             /* down or left */
X                { 0, 0, 0, 1, 1, 0, 0, 0 },             /* down, left, or right */
X                { -1, -1, -1, -1, -1, -1, -1, -1 },     /* up only */
X                { 0, 0, -1, -1, -1, 0, 0, -1 },         /* up or right */
X                { -1, 0, 0, -1, -1, -1, 0, 0 },         /* up or left */
X                { 0, 0, 0, -1, -1, -1, 0, 0 },          /* up, left, or right */
X                { 1, 1, 1, 1, -1, -1, -1, -1 },         /* up or down */
X                { 1, 0, 1, 1, -1, 0, 0, -1 },           /* up, down, or right */
X                { 1, 0, 0, -1, 1, -1, 0, 0 },           /* up, down, or left */
X                { 0, 0, 1, 1, -1, -1, 0, 0 } };         /* any which way */
X
X   /* first, find the directions in which this ghost can go */
X   if (pc[1] || (*px < 0)) dir &= ~0x01;
X   if (pc[-1] || (*px > 0)) dir &= ~0x02;
X   if (pc[BLOCK_WIDTH] || (*py < 0)) dir &= ~0x04;
X   if (pc[-BLOCK_WIDTH] || (*py > 0))  dir &= ~0x08;
X
X   /* now choose the new direction for the ghost */
X   if ((dir != 0x01) && (dir != 0x02) && (dir != 0x04) && (dir != 0x08)) {
X      sense = find[sgn(pmy - yy) + 1][sgn(pmx - xx) + 1];
X      *px = rxvec[dir][sense];
X      *py = ryvec[dir][sense];
X   }
X   else {
X      *px = *rxvec[dir];
X      *py = *ryvec[dir];
X   }
X}
X
X
X/*
X * The function below causes ghosts to return to the ghost box at
X * high speed.  It is set up as the driver for ghosts which have
X * been eaten.
X */
Xgo_home(i)
Xregister int i;
X{
X   register char  *pc = md[y[i] >> 4] + (x[i] >> 4);
X   register int   dir = 0x0f, sense;
X   register int   *px = ix + i, *py = iy + i;
X   int            xx = x[i], yy = y[i], pmx = door_x << 4, pmy = (door_y - 1) << 4;
X   static intm    find[3] = { { 0, 1, 2 }, { 3, 3, 4 }, { 5, 6, 7 } };
X
X   static intm  pxvec[16] = {
X                { 0, 0, 0, 0, 0, 0, 0, 0 },             /* no way to go */
X                { 4, 4, 4, 4, 4, 4, 4, 4 },             /* right only */
X                { -4, -4, -4, -4, -4, -4, -4, -4 },     /* left only */
X                { -4, 4, 4, -4, 4, -4, -4, 4 },         /* left or right */
X                { 0, 0, 0, 0, 0, 0, 0, 0 },             /* down only */
X                { 4, 4, 4, 0, 4, 0, 0, 4 },             /* down or right */
X                { -4, -4, -4, -4, 0, 0, 0, 0 },         /* down or left */
X                { -4, -4, 4, -4, 4, -4, 0, 0 },         /* down, left, or right */
X                { 0, 0, 0, 0, 0, 0, 0, 0 },             /* up only */
X                { 0, 0, 0, 0, 4, 4, 4, 4 },             /* up or right */
X                { -4, 0, 0, -4, 0, -4, -4, -4 },        /* up or left */
X                { 0, 0, 4, -4, 4, -4, -4, 4 },          /* up, left, or right */
X                { 0, 0, 0, 0, 0, 0, 0, 0 },             /* up or down */
X                { 0, 0, 4, 0, 4, 0, 0, 4 },             /* up, down, or right */
X                { -4, 0, 0, -4, 0, 0, 0, 0 },           /* up, down, or left */
X                { -4, 0, 0, -4, 4, 0, 0, 4 } };         /* any which way */
X
X   static intm  pyvec[16] = {
X                { 0, 0, 0, 0, 0, 0, 0, 0 },             /* no way to go */
X                { 0, 0, 0, 0, 0, 0, 0, 0 },             /* right only */
X                { 0, 0, 0, 0, 0, 0, 0, 0 },             /* left only */
X                { 0, 0, 0, 0, 0, 0, 0, 0 },             /* left or right */
X                { 4, 4, 4, 4, 4, 4, 4, 4 },             /* down only */
X                { 0, 0, 0, 4, 0, 4, 4, 0 },             /* down or right */
X                { 0, 0, 0, 0, 4, 4, 4, 4 },             /* down or left */
X                { 0, 0, 0, 0, 0, 0, 4, 4 },             /* down, left, or right */
X                { -4, -4, -4, -4, -4, -4, -4, -4 },     /* up only */
X                { -4, -4, -4, -4, 0, 0, 0, 0 },         /* up or right */
X                { 0, -4, -4, 0, -4, 0, 0, 0 },          /* up or left */
X                { -4, -4, 0, 0, 0, 0, 0, 0 },           /* up, left, or right */
X                { -4, -4, -4, -4, 4, 4, 4, 4 },         /* up or down */
X                { -4, -4, 0, 4, 0, 4, 4, 0 },           /* up, down, or right */
X                { 0, -4, -4, 0, -4, 4, 4, 4 },          /* up, down, or left */
X                { 0, -4, -4, 0, 0, 4, 4, 0 } };         /* any which way */
X
X   if (xx == pmx) {
X      if (yy == pmy) {
X
X	 /*
X	  * The ghost is right above the door to the ghost box.
X	  * We'll send it down into the box.  We're assuming
X          * here that the ghost box is shaped a certain way.
X	  * If not, the results will be unpredictable.
X	  */
X         *px = 0;
X         *py = 4;
X         return;
X      }
X      else if (yy == (pmy + 48)) {
X
X	 /*
X	  * The ghost is all the way inside the box.  Here it'll
X	  * be "reborn" -- its state will be changed to that of a
X	  * solid ghost hovering inside the ghost box.
X	  */
X         drive[i] = hover;
X         loops[i] = 0;
X         ghost[i] = bghost;
X         contact[i] = die;
X         *px = 2;
X         *py = 0;
X         return;
X      }
X   }
X   else {
X
X      /* otherwise, find the directions in which this ghost can go */
X      if (pc[1] || (*px < 0)) dir &= ~0x01;
X      if (pc[-1] || (*px > 0)) dir &= ~0x02;
X      if (pc[BLOCK_WIDTH] || (*py < 0)) dir &= ~0x04;
X      if (pc[-BLOCK_WIDTH] || (*py > 0))  dir &= ~0x08;
X
X      /* now choose the new direction for the ghost */
X      if ((dir != 0x01) && (dir != 0x02) && (dir != 0x04) && (dir != 0x08)) {
X         sense = find[sgn(pmy - yy) + 1][sgn(pmx - xx) + 1];
X         *px = pxvec[dir][sense];
X         *py = pyvec[dir][sense];
X      }
X      else {
X         *px = *pxvec[dir];
X         *py = *pyvec[dir];
X      }
X   }
X}
X
X
X/*
X * The function below drives the solid ghosts inside the ghost box.
X * They simply hover around in a circular pattern.  Randomness is
X * used to decide when the ghosts leave the box.
X */
Xhover(i)
Xregister int i;
X{
X   register int yy = y[i] >> 4, xx = x[i] >> 4;
X   char         *pc = md[yy] + xx;
X   register int *px = ix + i, *py = iy + i;
X
X   if (xx == door_x)
X      if (yy == (door_y - 1)) {
X
X	 /*
X	  * The ghost is now completely outside the box; we will
X	  * change its driver so that it follows the player around
X	  */
X         drive[i] = follow;
X         follow(i);
X         return;
X      }
X      else if (yy == (door_y + 1))
X
X	 /*
X	  * The ghost is directly underneath the door to the
X	  * outside.  We'll use the number of loops it has made
X	  * inside the box, as well as a bit of randomness,
X	  * to determine whether or not to send it out.
X	  */
X         if ((++loops[i]) > 1)
X            if ((random() & 0x0f) > 7) {
X               *px = 0, *py = (-2);
X               return;
X            }
X
X   /*
X    * The rest of the function drives the ghost around the
X    * box in a circular counterclockwise pattern.
X    */
X   if (*px > 0) {
X      if (pc[1]) *px = 0, *py = (-2);
X   }
X   else if (*px < 0) {
X      if (pc[-1]) *px = 0, *py = 2;
X   }
X   else if (*py > 0) {
X      if (pc[BLOCK_WIDTH]) *px = 2, *py = 0;
X   }
X   else if (pc[-BLOCK_WIDTH]) *px = (-2), *py = 0;
X}
X
X
X/*
X * The function below is just like hover() above, except that
X * it handles the motion of ghosts inside the box during
X * the ghost-eating periods of the game -- they move at half
X * speed.
X */
Xhover2(i)
Xregister int i;
X{
X   register int yy = y[i] >> 4, xx = x[i] >> 4;
X   char         *pc = md[yy] + xx;
X   register int *px = ix + i, *py = iy + i;
X
X   if (xx == door_x)
X      if (yy == (door_y - 1)) {
X         drive[i] = run;
X         run(i);
X         return;
X      }
X      else if (yy == (door_y + 1))
X         if ((++loops[i]) > 1) {
X            *px = 0, *py = (-1);
X            return;
X         }
X
X   if (*px > 0) {
X      if (pc[1]) *px = 0, *py = (-1);
X   }
X   else if (*px < 0) {
X      if (pc[-1]) *px = 0, *py = 1;
X   }
X   else if (*py > 0) {
X      if (pc[BLOCK_WIDTH]) *px = 1, *py = 0;
X   }
X   else if (pc[-BLOCK_WIDTH]) *px = (-1), *py = 0;
X}
END_OF_FILE
if test 20425 -ne `wc -c <'xchomp/drivers.c'`; then
    echo shar: \"'xchomp/drivers.c'\" unpacked with wrong size!
fi
# end of 'xchomp/drivers.c'
fi
if test -f 'xchomp/main.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xchomp/main.c'\"
else
echo shar: Extracting \"'xchomp/main.c'\" \(8900 characters\)
sed "s/^X//" >'xchomp/main.c' <<'END_OF_FILE'
X
X#define EXTERN
X#include "xchomp.h"
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X   XEvent		event;
X   int			dummy;
X   XCharStruct		chars;
X   unsigned long	event_mask;
X
X   /* open the display */
X   display 	= XOpenDisplay(NULL);
X   screen 	= DefaultScreen(display);
X   root		= DefaultRootWindow(display);
X   depth 	= DefaultDepth(display, screen);
X   black 	= BlackPixel(display, screen);
X   white 	= WhitePixel(display, screen);
X
X   /* get a font */
X   font = XLoadFont(display, "fixed");
X   XQueryTextExtents(display, font, "000000", 6, &dummy,
X      &ascent, &descent, &chars);
X
X   /*
X    * We want to suspend the game in case the window is iconified.
X    * This is more difficult than it sounds.  On the Sun, iconification
X    * seems to produce an UnmapNotify event -- very nice.  DECwindows,
X    * however, informs the application by generating a PropertyNotify
X    * event on a DEC-specific property -- very nasty.  The atom is
X    * not defined in any of the DECwindows headers, so we will try
X    * to get its value from the server, and use it later.  We are
X    * hoping here that all non-DECwindows servers will return None
X    * for this atom.
X    */
X   DEC_icon_atom = XInternAtom(display, "DEC_WM_ICON_STATE", True);
X
X   /* assemble resources */
X   create_ghost();
X   create_pac();
X   create_fruit();
X   create_maze_symbols();
X   create_demo_images();
X   create_window(argc, argv);
X   create_GCs();
X   create_maps();
X
X   /* select the event mask for the window */
X   event_mask = ExposureMask | KeyPressMask;
X   if (DEC_icon_atom == None)
X      event_mask |= StructureNotifyMask;
X   else event_mask |= PropertyChangeMask;
X   XSelectInput(display, window, event_mask);
X   
X   /* display the window */
X   XMapWindow(display, window);
X   while (True) {
X      XNextEvent(display, &event);
X      if (event.xany.window != window) continue;
X      if (event.type == Expose) break;
X   }
X
X   /*-- The Game Starts Here -----------------------------------------*/
X   {
X	register int	i, num_clips;
X	char		c_buf;
X	XComposeStatus  status;
X
X	static int	flash_ticks[] = {
X			   13, 8, 4, 1, 13, 8, 4, 1,
X			   8, 4, 1, 4, 1, 8, 4, 1,
X			   0, 0, 8, 4, 0, 0, 1, 0 };
X	static int	off_ticks[] = {
X			   19, 14, 10, 7, 19, 14, 10, 7,
X			   14, 10, 7, 10, 7, 14, 10, 7,
X			   1, 1, 14, 10, 1, 1, 7, 1 };
X	static int	screens[] = {
X			   1, 1, 1, 1, 2, 2, 2, 2,
X			   3, 3, 3, 4, 4, 5, 5, 5,
X			   1, 2, 6, 6, 3, 4, 6, 5 };
X
X	high_score = 0L;
X
X     demo:
X
X	/* run the demo screen */
X	demo_seq();
X
X	/* initialize the game */
X	lives = 3;
X	level = (-1);
X	score = 0L;
X	print_score(0L);
X
X     new_screen:
X
X	/* advance the level */
X	plevel = (++level > 13) ? 13 : level;
X	flash_tick = flash_ticks[level % 24];
X	off_tick = off_ticks[level % 24];
X	display_level(True);
X
X	/* initialize dynamic parameters */
X	completed = False;
X	fruit_times = 0;
X
X	/* build the maze */
X	clear_maps();
X        read_maze(screens[level % 24] - 1);
X
X     new_life:
X
X	/* initialize more dynamic parameters */
X	last_key = XK_Left;
X	dead = False;
X	eat_mode = False;
X	count = (-1);
X	fruit_count = (-1);
X	fruit_shown = False;
X	position_players();
X
X	/* display the number of lives */
X	(void)set_lives(lives);
X
X	/* copy the maze to the map and the screen */
X	XCopyArea(display, save, map, fullcopyGC, 0, 0,
X	   WIN_WIDTH, WIN_HEIGHT, 0, 0);
X	XCopyArea(display, map, window, fullcopyGC, 0, 0,
X	   WIN_WIDTH, WIN_HEIGHT, 0, 0);
X
X	/* display the ready message */
X	get_ready();
X
X
X	/*-- The Animation Loop ----------------------------------------*/
X
X	while (True) {
X
X	   /*-- Xlib Event Section -------------------------------------*/
X
X	   while (QLength(display) > 0) {
X	      XNextEvent(display, &event);
X	      if (event.xany.window != window) continue;
X	      switch (event.type) {
X		 case KeyPress:
X		    XLookupString(&event, &c_buf, 1, &last_key, &status);
X		    if (last_key == XK_space)
X		       if (!pause_seq())
X			  goto demo;
X		    break;
X		 case UnmapNotify:
X		    while (True) {
X		       XNextEvent(display, &event);
X		       if (event.xany.window != window) continue;
X		       if (event.type == MapNotify) break;
X		    }
X		    XCopyArea(display, map, window, fullcopyGC, 0, 0,
X		       WIN_WIDTH, WIN_HEIGHT, 0, 0);
X		    restore_status();
X		    if (!pause_seq())
X		       goto demo;
X		    break;
X		 case PropertyNotify:
X		    if (event.xproperty.atom != DEC_icon_atom) break;
X		    while (True) {
X		       XNextEvent(display, &event);
X		       if (event.xany.window != window) continue;
X		       if (event.type != PropertyNotify) continue;
X		       if (event.xproperty.atom == DEC_icon_atom) break;
X		    }
X		    XCopyArea(display, map, window, fullcopyGC, 0, 0,
X		       WIN_WIDTH, WIN_HEIGHT, 0, 0);
X		    restore_status();
X		    if (!pause_seq())
X		       goto demo;
X		    break;
X		 case Expose:
X		    XCopyArea(display, map, window, fullcopyGC, 0, 0,
X		       WIN_WIDTH, WIN_HEIGHT, 0, 0);
X		    restore_status();
X		    break;
X		 default: break;
X	      }
X	   }
X
X	   /*-- Adjust Frame Counter -----------------------------------*/
X
X	   count = (count + 1) & 0x0f;
X
X	   /*-- Flashing Power-Dot And Fruit Section -------------------*/
X
X	   num_clips = NUM_FIGURES;
X
X	   if (count == 0) {
X
X	      /* it's time to flash the power-dots */
X	      XCopyArea(display, powermap, save, powerGC, 0, 0,
X	         WIN_WIDTH, WIN_HEIGHT, 0, 0);
X	      num_clips = NUM_FIGURES + MAX_POWER_DOTS;
X
X	      /* see if it's time to display or erase the fruit */
X	      if (fruit_times < 2) {
X	         if (++fruit_count == 30) {
X		    XCopyPlane(display, fruit_pix[plevel], save, fullcopyGC,
X		       0, 0, GHOST_SIZE, GHOST_SIZE, fruit_x, fruit_y, 1);
X                    num_clips = NUM_FIGURES + MAX_POWER_DOTS + 1;
X		    dd[fruit_y >> 4][fruit_x >> 4] = 'F';
X		    fruit_shown = True;
X	         }
X	         else if (fruit_count == 50) {
X		    XFillRectangle(display, save, clearGC, fruit_x - 2,
X		       fruit_y, FRUIT_WIDTH, FRUIT_HEIGHT);
X		    dd[fruit_y >> 4][fruit_x >> 4] = '\0';
X	  	    fruit_count = 0;
X		    ++fruit_times;
X                    num_clips = NUM_FIGURES + MAX_POWER_DOTS + 1;
X		    fruit_shown = False;
X	         }
X	      }
X	   }
X
X	   /*-- Set Clipping Information -------------------------------*/
X
X	   XSetClipRectangles(display, copyGC, 0, 0, rectangle,
X	      num_clips, Unsorted);
X
X	   /*-- Restore Background Image -------------------------------*/
X
X	   XCopyArea(display, save, map, copyGC, 0, 0, WIN_WIDTH,
X	      WIN_HEIGHT, 0, 0);
X
X	   /*-- Motion Control Section ---------------------------------*/
X
X	   control_pac();
X	   if (dead || completed) break;
X	   for (i = 0; i < PAC_SLOT; i++)
X	      if (!(x[i] & 0x0f) && !(y[i] & 0x0f))
X		 (*drive[i])(i);
X	   for (i = 0; i < PAC_SLOT; i++) {
X	      rectangle[i].x = (x[i] += ix[i]) - 2;
X	      rectangle[i].y = (y[i] += iy[i]) - 2;
X	   }
X
X	   /*-- Flashing Ghost Section ---------------------------------*/
X
X	   /*
X	    * If we're in the middle of a ghost-eating period, this section
X	    * handles the timing and changes ghost states when necessary
X	    */
X	   if (eat_mode)
X	      if (count == count_sync) {
X	         ++grey_tick;
X	         if (grey_tick == flash_tick) {
X		    for (i = 0; i < PAC_SLOT; i++)
X		       if (ghost[i] == gghost)
X		          ghost[i] = fghost;
X		 }
X	         else if (grey_tick == off_tick) {
X		    eat_mode = False;
X		    for (i = 0; i < PAC_SLOT; i++)
X		       if (drive[i] == run) {
X		          ghost[i] = bghost;
X		          contact[i] = die;
X		          drive[i] = follow;
X		          x[i] &= ~0x1;  y[i] &= ~0x01;
X		          ix[i] *= 2;    iy[i] *= 2;
X		       }
X		       else if (drive[i] == hover2) {
X		          ghost[i] = bghost;
X		          contact[i] = die;
X			  drive[i] = hover;
X		          x[i] &= ~0x1;  y[i] &= ~0x01;
X		          ix[i] *= 2;    iy[i] *= 2;
X		       }
X	         }
X	      }
X
X	   /*-- Offscreen Figure Overlay -------------------------------*/
X
X	   for (i = 0; i < PAC_SLOT; i++)
X	      XCopyPlane(display, ghost[i][count], map, orGC, 0, 0, 
X		 GHOST_SIZE, GHOST_SIZE, x[i], y[i], 1);
X	   XCopyPlane(display, pac[count], map, orGC, 0, 0,
X	      GHOST_SIZE, GHOST_SIZE, x[PAC_SLOT], y[PAC_SLOT], 1);
X
X	   /*-- Screen Update ------------------------------------------*/
X
X	   XCopyArea(display, map, window, copyGC, 0, 0, WIN_WIDTH,
X	      WIN_HEIGHT, 0, 0);
X
X	   /*-- Synchronization And Delay ------------------------------*/
X
X	   XSync(display, False);
X
X#ifdef FRAME_DELAY
X	   usleep(FRAME_DELAY);
X#endif
X
X	} /* while */
X
X	/*-- End of Animation Loop -------------------------------------*/
X
X	if (dead) {
X	   if (set_lives(lives - 1)) {
X	      sleep(2);
X	      goto new_life;
X	   }
X	   game_over();
X	   goto demo;
X	}
X
X	if (completed) {
X	   finish();
X	   goto new_screen;
X	}
X   }
X   /*-- The Game Ends Here -------------------------------------------*/
X
X   do_exit();
X}
X
X
Xdo_exit()
X{
X   XUnmapWindow(display, window);
X   XUnloadFont(display, font);
X   XFlush(display);
X   XCloseDisplay(display);
X   exit(1);
X}
END_OF_FILE
if test 8900 -ne `wc -c <'xchomp/main.c'`; then
    echo shar: \"'xchomp/main.c'\" unpacked with wrong size!
fi
# end of 'xchomp/main.c'
fi
if test -f 'xchomp/resources.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xchomp/resources.c'\"
else
echo shar: Extracting \"'xchomp/resources.c'\" \(12858 characters\)
sed "s/^X//" >'xchomp/resources.c' <<'END_OF_FILE'
X
X#include "xchomp.h"
X#include "bitmaps.h"
X
X
X/*
X * This file contains all of the functions which build the image and
X * window/pixmap resources for the game, as well as the graphics
X * contexts.
X */
X
Xcreate_window(argc, argv)
Xint argc;
Xchar *argv[];
X{
X   XSizeHints   hints;
X   char         *name = "xchomp";
X
X   window = XCreateSimpleWindow(display, root, 0, 0, WIN_WIDTH,
X      WIN_HEIGHT + GHOST_SIZE + 2, 1, black, white);
X
X   icon = XCreatePixmapFromBitmapData(display, root, icon_bits,
X      ICON_WIDTH, ICON_HEIGHT, 1, 0, 1);
X
X   hints.flags = PSize | PMinSize | PMaxSize;
X   hints.width = hints.min_width = hints.max_width = WIN_WIDTH;
X   hints.height = hints.min_height = hints.max_height = WIN_HEIGHT + GHOST_SIZE + 2;
X
X   XSetStandardProperties(display, window, name, name, icon,
X      argv, argc, &hints);
X}
X
X
Xcreate_pac()
X{
X   int i;
X
X   lpac[3] = XCreatePixmapFromBitmapData(display, root, pacl1_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   lpac[2] = XCreatePixmapFromBitmapData(display, root, pacl2_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   lpac[1] = XCreatePixmapFromBitmapData(display, root, pacl3_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   lpac[0] = XCreatePixmapFromBitmapData(display, root, pacl4_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   lpac[4] = lpac[3];
X   lpac[5] = lpac[2];
X   lpac[6] = lpac[1];
X   lpac[7] = lpac[0];
X   for (i = 8; i < 16; i++)
X      lpac[i] = lpac[i - 8];
X
X   rpac[3] = XCreatePixmapFromBitmapData(display, root, pacr1_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   rpac[2] = XCreatePixmapFromBitmapData(display, root, pacr2_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   rpac[1] = XCreatePixmapFromBitmapData(display, root, pacr3_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   rpac[0] = lpac[0];
X   rpac[4] = rpac[3];
X   rpac[5] = rpac[2];
X   rpac[6] = rpac[1];
X   rpac[7] = rpac[0];
X   for (i = 8; i < 16; i++)
X      rpac[i] = rpac[i - 8];
X
X   upac[3] = XCreatePixmapFromBitmapData(display, root, pacu1_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   upac[2] = XCreatePixmapFromBitmapData(display, root, pacu2_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   upac[1] = XCreatePixmapFromBitmapData(display, root, pacu3_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   upac[0] = lpac[0];
X   upac[4] = upac[3];
X   upac[5] = upac[2];
X   upac[6] = upac[1];
X   upac[7] = upac[0];
X   for (i = 8; i < 16; i++)
X      upac[i] = upac[i - 8];
X
X   dpac[3] = XCreatePixmapFromBitmapData(display, root, pacd1_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   dpac[2] = XCreatePixmapFromBitmapData(display, root, pacd2_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   dpac[1] = XCreatePixmapFromBitmapData(display, root, pacd3_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   dpac[0] = lpac[0];
X   dpac[4] = dpac[3];
X   dpac[5] = dpac[2];
X   dpac[6] = dpac[1];
X   dpac[7] = dpac[0];
X   for (i = 8; i < 16; i++)
X      dpac[i] = dpac[i - 8];
X
X   dead_prot[0] = lpac[0];
X   dead_prot[1] = lpac[1];
X   dead_prot[2] = lpac[2];
X   dead_prot[3] = lpac[3];
X   dead_prot[4] = XCreatePixmapFromBitmapData(display, root, pdie4_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   dead_prot[5] = XCreatePixmapFromBitmapData(display, root, pdie5_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   dead_prot[6] = XCreatePixmapFromBitmapData(display, root, pdie6_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   dead_prot[7] = XCreatePixmapFromBitmapData(display, root, pdie7_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   dead_prot[8] = XCreatePixmapFromBitmapData(display, root, pdie8_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   dead_prot[9] = XCreatePixmapFromBitmapData(display, root, pdie9_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   dead_prot[10] = XCreatePixmapFromBitmapData(display, root, pdie10_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X
X   for (i = 0; i < 11; i++)
X      deadpac[i] = XCreatePixmap(display, root, GHOST_SIZE, GHOST_SIZE, 1);
X
X   small_pac = XCreatePixmapFromBitmapData(display, root, pacsmall_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X}
X
X
Xcreate_ghost()
X{
X   int i;
X
X   bghost[0] = XCreatePixmapFromBitmapData(display, root, frame1_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   bghost[2] = XCreatePixmapFromBitmapData(display, root, frame2_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   bghost[6] = XCreatePixmapFromBitmapData(display, root, frame3_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   bghost[1] = bghost[4] = bghost[5] = bghost[0];
X   bghost[3] = bghost[2];
X   bghost[7] = bghost[6];
X   for (i = 8; i < 16; i++)
X      bghost[i] = bghost[i - 8];
X
X   gghost[0] = XCreatePixmapFromBitmapData(display, root, grey1_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   gghost[2] = XCreatePixmapFromBitmapData(display, root, grey2_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   gghost[6] = XCreatePixmapFromBitmapData(display, root, grey3_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   gghost[1] = gghost[4] = gghost[5] = gghost[0];
X   gghost[3] = gghost[2];
X   gghost[7] = gghost[6];
X   for (i = 8; i < 16; i++)
X      gghost[i] = gghost[i - 8];
X
X   for (i = 0; i <  8; i++) fghost[i] = gghost[i];
X   for (i = 8; i < 16; i++) fghost[i] = bghost[i];
X
X   eghost[0] = XCreatePixmapFromBitmapData(display, root, eye_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   for (i = 1; i < 16; i++) eghost[i] = eghost[0];
X}
X
X
Xcreate_maze_symbols()
X{
X   int          i;
X   Pixmap       empty;
X   static char  index[] = { '1', '2', '3', '4', '5', '6', '7', '8',
X                            'a', 'b', 'c', 'd', 'v', 'e', 'g', '-',
X                            'j', '[', 'm', 'n', 'o', 'q', ']', 's',
X                            't', 'u', '^', '|', 'w', 'x', 'y', 'z',
X                            '.', 'O' };
X   static char  *data[] = { m1_bits, m2_bits, m3_bits, m4_bits, m5_bits,
X                            m6_bits, m7_bits, m8_bits, ma_bits, mb_bits,
X                            mc_bits, md_bits, mdown_bits, me_bits, mg_bits,
X                            mhorz_bits, mj_bits, mleft_bits, mm_bits, mn_bits,
X                            mo_bits, mq_bits, mright_bits, ms_bits, mt_bits,
X                            mu_bits, mup_bits, mvert_bits, mw_bits, mx_bits,
X                            my_bits, mz_bits, mdot_bits, mpower_bits };
X
X   empty = XCreatePixmapFromBitmapData(display, root, mempty_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   for (i = 0; i < 128; maze[i++] = empty);
X
X   for (i = 0; i < sizeof(index); i++)
X      maze[index[i]] = XCreatePixmapFromBitmapData(display, root,
X         data[i], GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X}
X
X
Xcreate_maps()
X{
X   map  = XCreatePixmap(display, root, WIN_WIDTH, WIN_HEIGHT, depth);
X   save = XCreatePixmap(display, root, WIN_WIDTH, WIN_HEIGHT, depth);
X   powermap = XCreatePixmap(display, root, WIN_WIDTH, WIN_HEIGHT, depth);
X}
X
X
X
Xcreate_fruit()
X{
X   fruit_pix[0] = XCreatePixmapFromBitmapData(display, root, fcherry_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   fruit_pix[1] = XCreatePixmapFromBitmapData(display, root, fstraw_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   fruit_pix[2] = XCreatePixmapFromBitmapData(display, root, fwater_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   fruit_pix[3] = fruit_pix[2];
X   fruit_pix[4] = XCreatePixmapFromBitmapData(display, root, fapple_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   fruit_pix[5] = XCreatePixmapFromBitmapData(display, root, fgrape_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   fruit_pix[6] = fruit_pix[5];
X   fruit_pix[7] = XCreatePixmapFromBitmapData(display, root, fbell_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   fruit_pix[8] = fruit_pix[7];
X   fruit_pix[9] = XCreatePixmapFromBitmapData(display, root, fclock_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   fruit_pix[10] = fruit_pix[9];
X   fruit_pix[11] = XCreatePixmapFromBitmapData(display, root, fxlogo_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   fruit_pix[12] = fruit_pix[11];
X   fruit_pix[13] = XCreatePixmapFromBitmapData(display, root, fkey_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X
X   fval_pix[0] = XCreatePixmapFromBitmapData(display, root, ff1_bits,
X      FRUIT_WIDTH, FRUIT_HEIGHT, 1, 0, 1);
X   fval_pix[1] = XCreatePixmapFromBitmapData(display, root, ff2_bits,
X      FRUIT_WIDTH, FRUIT_HEIGHT, 1, 0, 1);
X   fval_pix[2] = XCreatePixmapFromBitmapData(display, root, ff3_bits,
X      FRUIT_WIDTH, FRUIT_HEIGHT, 1, 0, 1);
X   fval_pix[3] = fval_pix[2];
X   fval_pix[4] = XCreatePixmapFromBitmapData(display, root, ff4_bits,
X      FRUIT_WIDTH, FRUIT_HEIGHT, 1, 0, 1);
X   fval_pix[5] = XCreatePixmapFromBitmapData(display, root, ff5_bits,
X      FRUIT_WIDTH, FRUIT_HEIGHT, 1, 0, 1);
X   fval_pix[6] = fval_pix[5];
X   fval_pix[7] = XCreatePixmapFromBitmapData(display, root, ff6_bits,
X      FRUIT_WIDTH, FRUIT_HEIGHT, 1, 0, 1);
X   fval_pix[8] = fval_pix[7];
X   fval_pix[9] = XCreatePixmapFromBitmapData(display, root, ff7_bits,
X      FRUIT_WIDTH, FRUIT_HEIGHT, 1, 0, 1);
X   fval_pix[10] = fval_pix[9];
X   fval_pix[11] = XCreatePixmapFromBitmapData(display, root, ff8_bits,
X      FRUIT_WIDTH, FRUIT_HEIGHT, 1, 0, 1);
X   fval_pix[12] = fval_pix[11];
X   fval_pix[13] = XCreatePixmapFromBitmapData(display, root, ff9_bits,
X      FRUIT_WIDTH, FRUIT_HEIGHT, 1, 0, 1);
X
X   eat_pix[0] = XCreatePixmapFromBitmapData(display, root, fg1_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   eat_pix[1] = XCreatePixmapFromBitmapData(display, root, fg2_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   eat_pix[2] = XCreatePixmapFromBitmapData(display, root, fg3_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X   eat_pix[3] = XCreatePixmapFromBitmapData(display, root, fg4_bits,
X      GHOST_SIZE, GHOST_SIZE, 1, 0, 1);
X}
X
X
Xcreate_GCs()
X{
X   XGCValues            gcv;
X   unsigned long        mask;
X
X   mask = GCForeground | GCBackground | GCFunction |
X          GCFont | GCGraphicsExposures;
X
X   /* resolve colors */
X   if ((black | white) == black)
X      normal = True;
X   else if ((black | white) == white)
X      normal = False;
X   else {
X      black &= white;
X      normal = False;
X   }
X
X   /* context for copying; used for animation */
X   gcv.foreground         = black;
X   gcv.background         = white;
X   gcv.function           = GXcopy;
X   gcv.font               = font;
X   gcv.graphics_exposures = False;
X   copyGC                 = XCreateGC(display, root, mask, &gcv);
X
X   /* context for copying; used for full size areas */
X   gcv.foreground         = black;
X   gcv.background         = white;
X   gcv.function           = GXcopy;
X   gcv.font               = font;
X   gcv.graphics_exposures = False;
X   fullcopyGC             = XCreateGC(display, root, mask, &gcv);
X
X   /* context for overlaying; used for animation */
X   gcv.foreground         = black;
X   gcv.background         = white;
X   gcv.function           = normal ? GXor : GXand;
X   gcv.font               = font;
X   gcv.graphics_exposures = False;
X   orGC                   = XCreateGC(display, root, mask, &gcv);
X
X   /* context for clearing */
X   gcv.foreground         = white;
X   gcv.background         = black;
X   gcv.function           = GXcopy;
X   gcv.font               = font;
X   gcv.graphics_exposures = False;
X   clearGC                = XCreateGC(display, root, mask, &gcv);
X
X   /* context for inverting */
X   gcv.foreground         = white;
X   gcv.background         = black;
X   gcv.function           = GXinvert;
X   gcv.font               = font;
X   gcv.graphics_exposures = False;
X   gcv.plane_mask         = black ^ white;
X   invertGC               = XCreateGC(display, root, mask | GCPlaneMask, &gcv);
X
X   /* context for flashing the power dots */
X   gcv.foreground         = black;
X   gcv.background         = white;
X   gcv.function           = normal ? GXxor : GXequiv;
X   gcv.plane_mask         = black ^ white;
X   gcv.font               = font;
X   gcv.graphics_exposures = False;
X   powerGC                = XCreateGC(display, root, mask | GCPlaneMask, &gcv);
X
X   /* context of depth 1; used for transferring onto bitmaps */
X   gcv.foreground         = 1;
X   gcv.background         = 0;
X   gcv.function           = GXcopy;
X   gcv.font               = font;
X   gcv.graphics_exposures = False;
X   bitmapGC               = XCreateGC(display, bghost[0], mask, &gcv);
X}
X
X
Xcreate_demo_images()
X{
X   demo_map[0] = XCreatePixmapFromBitmapData(display, root, bigc_bits,
X      48, 48, 1, 0, 1);
X   demo_map[1] = XCreatePixmapFromBitmapData(display, root, bigh_bits,
X      48, 48, 1, 0, 1);
X   demo_map[2] = XCreatePixmapFromBitmapData(display, root, bigo_bits,
X      48, 48, 1, 0, 1);
X   demo_map[3] = XCreatePixmapFromBitmapData(display, root, bigm_bits,
X      48, 48, 1, 0, 1);
X   demo_map[4] = XCreatePixmapFromBitmapData(display, root, bigp_bits,
X      48, 48, 1, 0, 1);
X}
X
X
Xclear_maps()
X{
X   XFillRectangle(display, powermap, clearGC, 0, 0, WIN_WIDTH, WIN_HEIGHT);
X   XFillRectangle(display, save, clearGC, 0, 0, WIN_WIDTH, WIN_HEIGHT);
X   XFillRectangle(display, map, clearGC, 0, 0, WIN_WIDTH, WIN_HEIGHT);
X}
END_OF_FILE
if test 12858 -ne `wc -c <'xchomp/resources.c'`; then
    echo shar: \"'xchomp/resources.c'\" unpacked with wrong size!
fi
# end of 'xchomp/resources.c'
fi
echo shar: End of archive 1 \(of 3\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 3 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 3 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0