[comp.sources.x] v10i047: xbd -- Boulder-dash

news@sun.Eng.Sun.COM (news) (11/01/90)

Submitted-by: ethz!houttuin (Jeroen Houttuin)
Posting-number: Volume 10, Issue 47
Archive-name: xbd/part02


#! /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.
# Contents:  xbd/Imakefile xbd/Makefile.orig xbd/README xbd/README.1.2
#   xbd/bitmap xbd/default xbd/field.c xbd/patchlevel.h xbd/scores
#   xbd/scores.c xbd/shared.c xbd/xbd.c xbd/xbd.h xbd/xbd.man
#   xbd/xbde.c
# Wrapped by houttuin@ural on Fri Oct 26 10:16:13 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:
echo '          "shar: End of archive."'
if test -f 'xbd/Imakefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xbd/Imakefile'\"
else
  echo shar: Extracting \"'xbd/Imakefile'\" \(2153 characters\)
  sed "s/^X//" >'xbd/Imakefile' <<'END_OF_FILE'
X#/*********************************************/
X#/* you just keep on pushing my luck over the */
X#/*           BOULDER        DASH             */
X#/*                                           */
X#/*Imakefile:christos@guillemin.EE.CORNELL.edu*/
X#/*********************************************/
X
XGAME            = xbd
XEDITOR          = xbde
XPROGRAMS        = ${GAME} ${EDITOR}
XCDEBUGFLAGS     = -O
XSCOREFONT       = -adobe-times-bold-r-normal--18-180-75-75-p-99-iso8859-1
XSCORESIZE       = 18
XMANDIR          = /usr/local/man/man6
XBINDIR          = /usr/local/games
XLIBDIR          = /usr/local/games/lib/xbd
XDEFINES         = -DLIB=\"${LIBDIR}\" \
X                  -DSCOREFONT=\"${SCOREFONT}\" \
X                  -DSCORESIZE=${SCORESIZE}
XLOCAL_LIBRARIES = $(XLIB)
XSYS_LIBRARIES   = -lm
XLEVELS          = xbdlev001 xbdlev002 xbdlev003 xbdlev004 xbdlev005 \
X                  xbdlev006 xbdlev007 xbdlev008 xbdlev009 xbdlev010 \
X                  xbdlev011 xbdlev012 xbdlev013 xbdlev014 xbdlev015 \
X                  xbdlev016 xbdlev017 xbdlev018 xbdlev019 xbdlev020 \
X                  xbdlev021 xbdlev022 xbdlev023 xbdlev024 xbdlev025 \
X                  xbdlev026 xbdlev027 xbdlev028 xbdlev029 xbdlev030 \
X                  xbdlev031 xbdlev032 xbdlev033 xbdlev034 xbdlev035 \
X                  xbdlev036 xbdlev037 xbdlev038
X
XOBJS1   = xbd.o shared.o field.o scores.o
XOBJS2   = xbde.o shared.o
X
XSRCS1   = xbd.o shared.o field.o scores.o
XSRCS2   = xbde.o shared.o
X
XAllTarget(${PROGRAMS})
XNormalProgramTarget(${GAME},${OBJS1},,$(LOCAL_LIBRARIES),)
XNormalProgramTarget(${EDITOR},${OBJS2},,$(LOCAL_LIBRARIES),)
XInstallProgramWithFlags(${GAME},${BINDIR}/${GAME},-s -m 4755 -o games)
XInstallProgramWithFlags(${EDITOR},${BINDIR}/${EDITOR},-s -o games)
X
Xinstall.man:: xbd.man
X        ${INSTALL} -c -m 0444 xbd.man ${MANDIR}/xbd.6
X
Xinstall:: ${PROGRAMS}
X        -mkdir ${LIBDIR}
X        chown games ${LIBDIR}
X        touch ${LIBDIR}/scores
X        chown games ${LIBDIR}/scores
X        (cp ${LEVELS} ${LIBDIR})
X        cp default ${LIBDIR}
X        (cd ${LIBDIR}; \
X         chown games ${LEVELS} default scores; \
X         chmod 644   ${LEVELS} default scores;)
END_OF_FILE
  if test 2153 -ne `wc -c <'xbd/Imakefile'`; then
    echo shar: \"'xbd/Imakefile'\" unpacked with wrong size!
  fi
  # end of 'xbd/Imakefile'
fi
if test -f 'xbd/Makefile.orig' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xbd/Makefile.orig'\"
else
  echo shar: Extracting \"'xbd/Makefile.orig'\" \(1033 characters\)
  sed "s/^X//" >'xbd/Makefile.orig' <<'END_OF_FILE'
X#/* you just keep on pushing my luck over the */
X#/*           BOULDER        DASH             */
X
XGAME = xbd
XEDITOR = xbde
X
X#BIN = /usr/local/bin
XBIN = ${HOME}/xbd
XLIB = ${HOME}/xbd
X
X# manual pages
XMAN = /usr/man
X
XSCOREFONT = -adobe-times-bold-r-normal--18-180-75-75-p-99-iso8859-1
XSCORESIZE = 18
X
XCC = cc
X
XCFLAGS = -g
XLDFLAGS = -g
X
Xall: ${GAME} ${EDITOR}
X
Xinstall: all
X	-mkdir ${LIB}
X	cp ${GAME} ${EDITOR} ${BIN}
X	chmod 4755 ${BIN}/${GAME}
X	touch ${LIB}/scores
X	chmod 644 ${LIB}/xbdlev*
X	chmod 644 ${LIB}/default
X	chmod 644 ${LIB}/scores
X	cp xbd.man ${MAN}
X
Xupdate: all
X	cp ${GAME} ${EDITOR} ${BIN}
X	chmod 4755 ${BIN}/${GAME}
X
Xclean:
X	rm -f *.o core ${GAME} ${EDITOR}
X
XSRCS = xbd.c shared.c field.c scores.c
XOBJS = xbd.o shared.o field.o scores.o
X
Xlint:
X	lint -DLIB=\"${LIB}\" -DSCOREFONT=\"${SCOREFONT}\" \
X	-DSCORESIZE=${SCORESIZE} ${SRCS}
X
X${GAME}: ${OBJS}
X	${CC} ${LDFLAGS} -o ${GAME} ${OBJS} -lX11
X
X${EDITOR}: xbde.o shared.o
X	${CC} ${LDFLAGS} -o ${EDITOR} xbde.o shared.o -lX11
X
X.c.o:
X	${CC} ${CFLAGS} -c -DLIB=\"${LIB}\" $<
END_OF_FILE
  if test 1033 -ne `wc -c <'xbd/Makefile.orig'`; then
    echo shar: \"'xbd/Makefile.orig'\" unpacked with wrong size!
  fi
  chmod +x 'xbd/Makefile.orig'
  # end of 'xbd/Makefile.orig'
fi
if test -f 'xbd/README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xbd/README'\"
else
  echo shar: Extracting \"'xbd/README'\" \(414 characters\)
  sed "s/^X//" >'xbd/README' <<'END_OF_FILE'
XBoulder-dash is still in an experimental phase.  Mail your
Xbug reports,  interesting new levels, ideas to the author
Xor to xbd@ks.id.ethz.ch.
X
X
X
X
X
XDON'T DISTRIBUTE ANY MODIFIED VERSIONS !
X
X
X
X
XJeroen Houttuin
XInformatikdienste-Kommunikationssysteme
XETH Zentrum RZ-H7
XCH-8092 Zurich
Xtel +41-1-2565837
Xfax +41-1-2615389
Xe-mail: houttuin@ks.id.ethz.ch
XX.400 : C=CH;ADMD=ARCOM;PRMD=SWITCH;O=ETHZ;OU=id;OU=ks;S=houttuin
END_OF_FILE
  if test 414 -ne `wc -c <'xbd/README'`; then
    echo shar: \"'xbd/README'\" unpacked with wrong size!
  fi
  # end of 'xbd/README'
fi
if test -f 'xbd/README.1.2' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xbd/README.1.2'\"
else
  echo shar: Extracting \"'xbd/README.1.2'\" \(842 characters\)
  sed "s/^X//" >'xbd/README.1.2' <<'END_OF_FILE'
X-Time limits per level are implemented.
X-Every level has a name now.
X-You can now also DRAW blocks in the editor.
X-People can now create levels by setting the environment variable XBDLIB
X to point to a directory that they can write to.
X-Tinkle walls were implemented (character 't'). Every level has a tinkle
X duration parameter.
X
X-For new ideas, levels etc. a distribution list has been created:
X	xbd@ks.id.ethz.ch
X
X-Thanks for improvements:
X	Tad.Davis@Central.Sun.com
X	Fernando Mira da Silva <fcr@joyce.inesc.pt>
X	Josh Siegel <siegel@Sun.com>
X	ccsteve@cc.uq.oz.au
X	George Ferguson <ferguson@cs.rochester.edu>
X	Charles D. Farnum <farnum@cypress.Berkeley.edu>
X	Lloyd Taylor <lloyd@aplcen.apl.jhu.edu>
X	Michael Glad <glad@daimi.aau.dk>
X
X-Special thanks for Imakefile and most bug fixes :
X	Christos S. Zoulas <christos@hyperion.EE.CORNELL.edu>
END_OF_FILE
  if test 842 -ne `wc -c <'xbd/README.1.2'`; then
    echo shar: \"'xbd/README.1.2'\" unpacked with wrong size!
  fi
  # end of 'xbd/README.1.2'
fi
if test ! -d 'xbd/bitmap' ; then
    echo shar: Creating directory \"'xbd/bitmap'\"
    mkdir 'xbd/bitmap'
fi
if test -f 'xbd/default' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xbd/default'\"
else
  echo shar: Extracting \"'xbd/default'\" \(979 characters\)
  sed "s/^X//" >'xbd/default' <<'END_OF_FILE'
X26 35 15 12 0 0 200 200 1000 Default_level
XSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
XS        b             e    bp    S
XS  www www w w w   ww  www www    S
XS  wrw wrw w w w   w w w   wrw    S
XS  www w w w w w   w w ww  www   nS
XS  wrw wpw wBwrw   wrw w   wwe    S
XS  wwwlwww www www ww  www wnw    S
XS                                 S
XS            bd bd                S
XS    gwww    wwwww  wwwww  w   w  S
XS     wl w   w   w  wdbb   w   w  S
XS     w   w  w   w  w      w   w  S
XS     wB  wg wwEBw  w      w   w  S
XS     wBB wg ww Bw  w      w   w  S
XS     wBB wg ww Bw  w      w   w  S
XSgbg  wBB wg ww Bw  w d    wp  w  S
XSglg  wBBBwg wwwww  wtttw  w   W nS
XSglg  wBBBwg w   w      w  w   w  S
XSggg  w   wg w   w      w  w   w  S
XSglg  w   wg w   w      w  w   w nS
XSgeg  w   w  w   w      w  w   w  S
XSgbg  we w   w   w      w  w   w  S
XSg g gwww   rw   w  twwtw  w   w  S
XSg g                              S
XSgeg        n    e               ES
XSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
END_OF_FILE
  if test 979 -ne `wc -c <'xbd/default'`; then
    echo shar: \"'xbd/default'\" unpacked with wrong size!
  fi
  # end of 'xbd/default'
fi
if test -f 'xbd/field.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xbd/field.c'\"
else
  echo shar: Extracting \"'xbd/field.c'\" \(13876 characters\)
  sed "s/^X//" >'xbd/field.c' <<'END_OF_FILE'
X/*********************************************/
X/* you just keep on pushing my luck over the */
X/*           BOULDER        DASH             */
X/*                                           */
X/*     Jeroen Houttuin, ETH Zurich, 1990     */
X/*********************************************/
X
X#include <stdio.h>
X#include <X11/Xlib.h>
X#include <X11/keysym.h>
X#include <X11/Xutil.h>
X#include <signal.h>
X#include <sys/time.h>
X#include <sys/timeb.h>
X#include "xbd.h"
X
Xvoid
Xblink(i, j)
X  int             i, j;
X{
X  field[i][j].changed = True;
X}
X
Xvoid
Xmove_cell(i, j, ii, jj)
X  int             i, j, ii, jj;
X{
X  field[ii][jj] = field[i][j];
X  field[ii][jj].speed = 1;
X  field[ii][jj].changed = True;
X  field[ii][jj].dir = ((ii - i) == 1) ? S : ((i - ii) == 1) ? N : ((jj - j) == 1) ? E : W;
X  set_cell(i, j, SPACE);
X}
X
Xvoid
Xexplode(a, b, stage)
X  int             a, b, stage;
X{
X  if (field[a][b].content != STEEL)
X  {
X    set_cell(a, b, EXPLOSION);
X    field[a][b].stage = stage;	/* dirty fix, not what stage was meant for */
X  }
X}
X
XBool
Xmove_nucbal(i, j, t)
X  int             i, j, t;
X{
X  ii = (!t) ? (i + y - 1) % y : i;
X  if (!t)
X    jj = j;
X  else
X    switch (field[i][j].dir)
X    {
X    case E:
X      jj = (t == 1) ? (j + x - 1) % x : (j + 1) % x;
X      break;
X    case W:
X    default:
X      jj = (t == 2) ? (j + x - 1) % x : (j + 1) % x;
X      break;
X    }
X  switch (field[ii][jj].content)
X  {
X  case SPACE:
X    move_cell(i, j, ii, jj);
X    return (True);
X  case NUCBAL:
X    explode(i, j, DIAEXPLO);
X    explode(ii, jj, DIAEXPLO);
X    return (True);
X  default:
X    if (field[i][j].dir == N)
X      field[i][j].dir = E;
X    else
X      field[i][j].dir = ((field[i][j].dir + 2) % 4);	/* turn around */
X    return (False);
X  }
X}
X
XBool
Xmove_monster(content, direction)
X  char            content, direction;
X{
X  switch (direction)
X  {
X  case N:
X    ii = (i + y - 1) % y;
X    jj = j;
X    break;
X  case E:
X    jj = (j + 1) % x;
X    ii = i;
X    break;
X  case S:
X    ii = (i + 1) % y;
X    jj = j;
X    break;
X  default:
X    jj = (j + x - 1) % x;
X    ii = i;
X    break;			/* default must be SOMEthing, West */
X  }
X  switch (field[ii][jj].content)
X  {
X  case SPACE:
X    if (!field[ii][jj].changed)
X    {
X      move_cell(i, j, ii, jj);
X      field[ii][jj].dir = direction;
X      return (True);
X    } else
X      return (False);
X    break;
X  case BOULDER:
X  case DIAMOND:
X    if ((direction == N) && (field[ii][jj].speed != 0))
X      if (content == RMONSTER)
X      {
X	explode(i, j, DIAEXPLO);
X	return (True);
X      } else if (content == LMONSTER)
X      {
X	explode(i, j, SPACEEXPLO);
X	return (True);
X      } else
X	return (False);
X    else
X      return (False);
X    break;
X  default:
X    return (False);
X    break;
X  }
X  return (False);
X}
X
XBool
Xsearch_destroy(content)
X  char            content;
X{
X  ii = (i + y - 1) % y;
X  jj = (j + x - 1) % x;
X  if (field[i][jj].content == PLAYER || field[i][jj].content == BLOB)
X  {
X    set_cell(i, j, SPACE);
X    if (field[i][jj].content == PLAYER)
X    {
X      lives--;
X      scoreobs = True;
X    }
X    if (content == RMONSTER)
X      explode(i, jj, DIAEXPLO);
X    else
X      explode(i, jj, SPACEEXPLO);
X    return (True);
X  } else if (field[ii][j].content == PLAYER || field[ii][j].content == BLOB)
X  {
X    set_cell(i, j, SPACE);
X    if (field[ii][j].content == PLAYER)
X    {
X      lives--;
X      scoreobs = True;
X    }
X    if (content == RMONSTER)
X      explode(ii, j, DIAEXPLO);
X    else
X      explode(ii, j, SPACEEXPLO);
X    return (True);
X  } else
X  {
X    ii = (i + 1) % y;
X    jj = (j + 1) % x;
X    if (field[i][jj].content == PLAYER || field[i][jj].content == BLOB)
X    {
X      set_cell(i, j, SPACE);
X      if (field[i][jj].content == PLAYER)
X      {
X	lives--;
X	scoreobs = True;
X      }
X      if (content == RMONSTER)
X	explode(i, jj, DIAEXPLO);
X      else
X	explode(i, jj, SPACEEXPLO);
X      return (True);
X    } else if (field[ii][j].content == PLAYER || field[ii][j].content == BLOB)
X    {
X      set_cell(i, j, SPACE);
X      if (field[ii][j].content == PLAYER)
X      {
X	lives--;
X	scoreobs = True;
X      }
X      if (content == RMONSTER)
X	explode(ii, j, DIAEXPLO);
X      else
X	explode(ii, j, SPACEEXPLO);
X      return (True);
X    } else
X      return (False);
X  }
X}
X
Xvoid
Xpropagate(i, j, dias)
X  int             i, j;
X  Bool            dias;
X{
X  int             t, it, jt;
X  if (dias)
X    set_cell(i, j, DIAMOND);
X  else
X  {
X    field[i][j].checked = PROPAGATED;
X    field[i][j].caught = True;
X  }
X  for (t = 0; (t < 4); ++t)
X  {
X    it = (t == 1) ? (i + y - 1) % y : (t == 3) ? (i + 1) % y : i;	/* neigbour
X									 * right,up,left,down */
X    jt = (t == 2) ? (j + x - 1) % x : (t == 0) ? (j + 1) % x : j;	/* neigbour
X									 * right,up,left,down */
X    switch (field[it][jt].content)
X    {
X    case BLOB:
X      if (field[it][jt].checked != PROPAGATED)
X	propagate(it, jt, dias);
X      break;
X    case SPACE:
X    case GRASS:
X      if (!(rand() % (blobbreak + 1)))
X      {
X	set_cell(it, jt, BLOB);
X	field[it][jt].checked = PROPAGATED;
X	field[it][jt].caught = True;
X      }
X      break;
X    default:
X      break;
X    }
X  }
X}
X
XBool
Xcaught(i, j)
X  int             i, j;
X{
X  Bool            Free;
X  int             t, it, jt;
X
X  field[i][j].checked = 1;
X  Free = False;
X
X  for (t = 0; ((t < 4) && !Free); ++t)
X  {
X    it = (t == 1) ? (i + y - 1) % y : (t == 3) ? (i + 1) % y : i;	/* neigbour
X									 * right,up,left,down */
X    jt = (t == 2) ? (j + x - 1) % x : (t == 0) ? (j + 1) % x : j;	/* neigbour
X									 * right,up,left,down */
X
X    switch (field[it][jt].content)
X    {
X    case SPACE:
X    case GRASS:
X    case RMONSTER:
X    case LMONSTER:
X    case EATER:
X      Free = True;
X      break;
X    case BLOB:
X      Free = (Free || ((field[it][jt].checked == 1) ? !field[i][j].caught
X		       : !caught(it, jt)
X		       )
X	);
X      break;
X    default:
X      break;
X    }
X  }
X  field[i][j].caught != Free;
X  return (!Free);
X}
X
Xvoid
Xdiaboulderproc(i, j)
X  int             i, j;
X{
X  if (field[i][j].content == DIAMOND)
X    blink(i, j);
X  ii = (ii + 1) % y;
X  field[i][j].dir = NODIR;
X  switch (field[ii][j].content)
X  {
X  case SPACE:			/* directly underneath */
X    move_cell(i, j, ii, j);
X    field[ii][j].speed = 1;
X    break;
X  case PLAYER:
X    if (field[i][j].speed)
X    {
X      set_cell(i, j, SPACE);
X      explode(ii, j, SPACEEXPLO);
X      lives--;
X      scoreobs = True;
X    }
X    break;
X  case LMONSTER:
X  case EATER:
X    if (field[i][j].speed)
X    {
X      set_cell(i, j, SPACE);
X      explode(ii, j, SPACEEXPLO);
X    }
X    break;
X  case RMONSTER:
X    if (field[i][j].speed)
X    {
X      set_cell(i, j, SPACE);
X      explode(ii, j, DIAEXPLO);
X    }
X    break;
X  case TINKLE:
X    if (field[i][j].speed)
X    {
X      tinkact = True;
X      field[ii][j].stage = field[i][j].content;
X      field[ii][j].speed = 1;
X      set_cell(i, j, SPACE);
X      break;
X    }
X    break;
X  case WALL:
X  case BOULDER:
X  case DIAMOND:
X  case EXPLOSION:
X    jj = (j + 1) % x;
X    if (field[i][jj].content == SPACE && field[ii][jj].content == SPACE)
X    {
X      move_cell(i, j, i, jj);
X      field[i][jj].speed = 0;
X    } else
X    {
X      jj = (j - 1) % x;
X      if (field[i][jj].content == SPACE
X	  && field[ii][jj].content == SPACE)
X      {
X	move_cell(i, j, i, jj);
X	field[i][jj].speed = 0;
X      } else
X	field[i][j].speed = 0;
X    }
X    break;
X  default:
X    field[i][j].speed = 0;
X    break;
X  }
X}
X
Xvoid
Xcalculate_field()
X{
X  players = 0;
X  /* Iterate through each horizontal line */
X  if (!time)
X    curorder = KILL;
X  for (i = y - 1; i >= 0; --i)
X  {
X    for (j = 0; j < x; ++j)
X    {
X      if (!(field[i][j].changed))
X      {
X	ii = i;
X	jj = j;
X	switch (field[i][j].content)
X	{
X	case PLAYER:
X	  players++;
X	  switch (curorder)	/* find cell player wants to go to */
X	  {
X	  case STAND:
X	    break;
X	  case UP:
X	    ii = (i + y - 1) % y;
X	    break;
X	  case DOWN:
X	    ii = (i + 1) % y;
X	    break;
X	  case LEFT:
X	    jj = (j + x - 1) % x;
X	    break;
X	  case RIGHT:
X	    jj = (j + 1) % x;
X	    break;
X	  }
X	  if (!(curorder == STAND) && !(field[i][j].changed))
X	  {
X	    if (curorder == KILL)
X	    {
X	      set_cell(i, j, EXPLOSION);
X	      lives--;
X	      scoreobs = True;
X	      break;
X	    }
X	    switch (field[ii][jj].content)	/* check cell player wants to
X						 * go to */
X	    {
X	    case SPACE:
X	    case GRASS:
X	    case DIAMOND:
X	      if (field[ii][jj].content == DIAMOND)
X	      {
X		if (curorder == UP && field[ii][jj].speed)
X		  break;
X		score += diapoints;
X		if (diareq)
X		  diareq--;
X		scoreobs = True;
X	      }
X	      if (steal)
X		set_cell(ii, jj, SPACE);
X	      else
X		move_cell(i, j, ii, jj);
X	      break;
X	    case BOULDER:
X	      jjj = (2 * jj - j + x) % x;	/* the cell behind the
X						 * boulder */
X	      if (field[i][jjj].content == SPACE && ((rand() % 2) == 0) &&
X		  !(field[ii][jj].dir == E))
X	      {
X		move_cell(i, jj, i, jjj);
X		field[i][jjj].speed = 0;
X		if (!steal)
X		{
X		  move_cell(i, j, i, jj);
X		}
X	      }
X	      break;
X	    case EXIT:
X	      if (diareq < 1)
X	      {
X		if (!steal)
X		  move_cell(i, j, ii, jj);
X		else
X		  set_cell(ii, jj, SPACE);
X		if (!levincreased)
X		{
X		  levelnum++;
X		  lives++;
X		  levincreased = True;
X		  for (jj = time / 10; jj > 0; --jj)
X		  {
X		    score += 10;
X		    draw_score();
X		    XFlush(disp);
X		  }
X		}
X		gamestop = True;
X		stoplevel = True;
X	      }
X	      break;
X	    }
X	  }
X	  blink(i, j);
X	  break;
X	case DIAMOND:
X	case BOULDER:
X	  diaboulderproc(i, j);
X	  break;
X	case EATER:
X	  if (!field[i][j].speed)
X	  {
X	    for (jjj = 0; ((!field[i][j].changed) && (jjj < 4)); ++jjj)
X	    {
X	      ii = (jjj == 2) ? (i + 1) % y : (jjj == 0) ? (i + y - 1) % y : i;
X	      jj = (jjj == 1) ? (j + 1) % x : (jjj == 3) ? (j + x - 1) % x : j;
X	      switch (field[ii][jj].content)
X	      {
X	      case PLAYER:
X		lives--;
X		scoreobs = True;
X	      case DIAMOND:
X		if (field[ii][jj].speed && (ii == i - 1) && (jj == j))
X		  break;
X	      case BLOB:
X	      case LMONSTER:
X	      case RMONSTER:
X	      case NUCBAL:
X		move_cell(i, j, ii, jj);
X		break;
X	      default:
X		break;
X	      }
X	    }
X	  } else
X	  {
X	    jjj = field[i][j].dir;
X	    ii = (jjj == 2) ? (i + 1) % y : (jjj == 0) ? (i + y - 1) % y : i;
X	    jj = (jjj == 1) ? (j + 1) % x : (jjj == 3) ? (j + x - 1) % x : j;
X	    switch (field[ii][jj].content)
X	    {
X	    case LMONSTER:
X	    case BLOB:
X	    case SPACE:
X	    case GRASS:
X	    case DIAMOND:
X	    case RMONSTER:
X	    case PLAYER:
X	    case NUCBAL:
X	      if (field[ii][jj].content == PLAYER)
X	      {
X		lives--;
X		scoreobs = True;
X	      }
X	      move_cell(i, j, ii, jj);
X	      break;
X	    case BOULDER:
X	      jjj = (2 * jj - j + x) % x;	/* the cell behind the
X						 * boulder */
X	      if (field[i][jjj].content == SPACE && ((rand() % 2) == 0) && !(field[ii][jj].dir == E))
X	      {
X		move_cell(i, jj, i, jjj);
X		move_cell(i, j, i, jj);
X	      } else
X		field[i][j].speed = 0;
X	      break;
X	    default:
X	      field[i][j].speed = 0;
X	      break;
X	    }
X	  }
X	  blink(i, j);
X	  break;
X	case RMONSTER:
X	  blink(i, j);
X	  if (search_destroy(RMONSTER))
X	    break;
X	  jjj = 3;
X	  while (jjj >= 0 && !move_monster(RMONSTER, (field[i][j].dir + jjj + 2) % 4))
X	    jjj--;
X	  break;
X	case LMONSTER:
X	  blink(i, j);
X	  if (search_destroy(LMONSTER))
X	    break;
X	  jjj = 0;
X	  while (jjj <= 4 && !move_monster(LMONSTER, (field[i][j].dir + jjj + 3) % 4))
X	    jjj++;
X	  break;
X	case EXPLOSION:
X	  jjj = field[i][j].stage;
X	  if (!(jjj % 5))	/* this is the initiating explosion */
X	  {
X	    jjj++;		/* use jjj for setting new stage */
X	    ii = (i + 1) % y;
X	    jj = (j + 1) % x;
X	    explode(i, j, jjj);
X	    explode(i, jj, jjj);
X	    explode(ii, j, jjj);
X	    explode(ii, jj, jjj);
X	    ii = (i + y - 1) % y;
X	    explode(ii, j, jjj);
X	    explode(ii, jj, jjj);
X	    jj = (j + x - 1) % x;
X	    explode(ii, jj, jjj);
X	    explode(i, jj, jjj);
X	    ii = (i + 1) % y;
X	    explode(ii, jj, jjj);
X	  } else
X	  {
X	    if (jjj % 10 < 3)
X	      field[i][j].stage++;
X	    else if (jjj > DIAEXPLO)
X	    {
X	      set_cell(i, j, DIAMOND);
X	    } else if (jjj > BOULDEXPLO)
X	    {
X	      set_cell(i, j, BOULDER);
X	    } else if (jjj > SPACEEXPLO)
X	    {
X	      set_cell(i, j, SPACE);
X	    } else
X	      field[i][j].stage++;
X	  }
X	  break;
X	case EXIT:
X	  blink(i, j);
X	  break;
X	case BLOB:
X	  blobcells++;
X	  if (blobcollapse)
X	    set_cell(i, j, BOULDER);
X	  else
X	  {
X	    if (blobcells > critical)
X	      blobcollapse = True;
X	    else
X	    {
X	      if (!field[i][j].checked)
X	      {
X		if (caught(i, j))
X		  propagate(i, j, DIAMOND);
X		else
X		  propagate(i, j, False);
X	      }
X	      field[i][j].checked = False;
X	      field[i][j].caught = True;
X	    }
X	  }
X	  blink(i, j);
X	  break;
X	case NUCBAL:
X	  for (jjj = 0; ((jjj < 3) && !move_nucbal(i, j, jjj)); ++jjj);
X	  blink(i, j);
X	  break;
X	case MAGICWALL:
X	  jj = (j + x - 1) % x;
X	  if (field[i][jj].content == SPACE)
X	    set_cell(i, jj, MAGICWALL);
X	  jj = (j + 1) % x;
X	  if (field[i][jj].content == SPACE)
X	    set_cell(i, jj, MAGICWALL);
X	  break;
X	case TINKLE:
X	  if (tinkact)
X	  {
X	    blink(i, j);
X	    if (tinkdur > 0)
X	    {
X	      switch (field[i][j].stage)
X	      {
X	      case BOULDER:
X		{
X		  field[i][j].content = DIAMOND;
X		  diaboulderproc(i, j);
X		  break;
X		}
X	      case DIAMOND:
X		{
X		  field[i][j].content = BOULDER;
X		  diaboulderproc(i, j);
X		  break;
X		}
X	      default:
X		break;
X	      }
X	    }
X	  }
X	  set_cell(i, j, TINKLE);	/* reset to empty tinkle wall */
X	  break;
X	default:
X	  break;
X	}
X      }
X    }
X  }
X  curorder = STAND;		/* reset orders */
X  blobcells = 0;
X  pgc = (pgc == pgc1) ? ((rand() % 22) == 0) ? pgc2 : pgc1 :
X    pgc1;
X  dgc = (dgc == dgc1) ? dgc2 : dgc1;
X  lgc = (lgc == lgc1) ? lgc2 : lgc1;
X  rgc = (rgc == rgc1) ? rgc2 : rgc1;
X  egc = (egc == egc1) ? egc2 : egc1;
X  Bgc = (Bgc == Bgc1) ? Bgc2 : Bgc1;
X  if (tinkact)
X    tgc = (tgc == tgc1) ? tgc2 : tgc1;
X  if (!diareq)
X  {
X    Egc = (Egc == Egc1) ? Egc2 : Egc1;
X    if (diareq == 0)
X    {
X      diapoints = extradiapoints;
X      scoreobs = True;
X    }
X  }
X}
END_OF_FILE
  if test 13876 -ne `wc -c <'xbd/field.c'`; then
    echo shar: \"'xbd/field.c'\" unpacked with wrong size!
  fi
  # end of 'xbd/field.c'
fi
if test -f 'xbd/patchlevel.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xbd/patchlevel.h'\"
else
  echo shar: Extracting \"'xbd/patchlevel.h'\" \(21 characters\)
  sed "s/^X//" >'xbd/patchlevel.h' <<'END_OF_FILE'
X#define PATCHLEVEL 0
END_OF_FILE
  if test 21 -ne `wc -c <'xbd/patchlevel.h'`; then
    echo shar: \"'xbd/patchlevel.h'\" unpacked with wrong size!
  fi
  # end of 'xbd/patchlevel.h'
fi
if test -f 'xbd/scores' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xbd/scores'\"
else
  echo shar: Extracting \"'xbd/scores'\" \(405 characters\)
  sed "s/^X//" >'xbd/scores' <<'END_OF_FILE'
X2800 27 30 houttuin 
X1833 12 14 houttuin 
X1770 22 23 houttuin 
X1690 15 16 houttuin 
X1680 37 38 houttuin 
X1626 27 29 houttuin 
X1350 36 36 houttuin 
X1302 2 4 houttuin 
X1284 17 18 houttuin 
X1160 37 37 houttuin 
X1120 77 78 houttuin 
X1110 2 3 houttuin 
X1020 77 77 houttuin 
X960 25 25 houttuin 
X955 2 3 houttuin 
X950 36 36 houttuin 
X934 13 14 houttuin 
X930 16 16 houttuin 
X902 2 3 houttuin 
X883 33 34 houttuin 
END_OF_FILE
  if test 405 -ne `wc -c <'xbd/scores'`; then
    echo shar: \"'xbd/scores'\" unpacked with wrong size!
  fi
  # end of 'xbd/scores'
fi
if test -f 'xbd/scores.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xbd/scores.c'\"
else
  echo shar: Extracting \"'xbd/scores.c'\" \(3472 characters\)
  sed "s/^X//" >'xbd/scores.c' <<'END_OF_FILE'
X/*********************************************/
X/* you just keep on pushing my luck over the */
X/*           BOULDER        DASH             */
X/*                                           */
X/*     Jeroen Houttuin, ETH Zurich, 1990     */
X/*********************************************/
X
X#include <stdio.h>
X#include <X11/Xlib.h>
X#include <X11/keysym.h>
X#include "xbd.h"
X
Xchar           *getenv();
X
X#define NUMHIGH 20		/* Number of high scores that will be
X				 * remembered */
X
X/* Add a high score to the high score list */
Xvoid
Xadd_score()
X{
X  /* Structure containing top game results */
X  struct
X  {
X    int             score;	/* Final score */
X    int             slev, elev;	/* Starting and ending level */
X    char            desc[80];	/* Text description */
X  }               tops[NUMHIGH], next;
X  FILE           *sfile;	/* High score file */
X  char            buf[200];
X  register int    i;
X  int             numscore, cur, numgame;
X
X  /* Generate name of high score file */
X  sprintf(buf, "%s/scores", LIB);
X  /* Open high score file */
X  sfile = fopen(buf, "r");
X  /* Set default values for number of games and high scores */
X  numscore = 0;
X  numgame = 0;
X  /* If file is readable, load in old high score list */
X  if (sfile != NULL)
X  {
X    /* Extract score information from line */
X    while (fgets(buf, 200, sfile) && numscore < NUMHIGH)
X    {
X      sscanf(buf, "%d %d %d %[^\n]", &(next.score), &(next.slev), &(next.elev),
X	     next.desc);
X      tops[numscore] = next;
X      numscore++;
X    }
X    fclose(sfile);
X  }
X  /* Contruct the structure containing the score for this game */
X  next.score = score;
X  next.slev = levelstart;
X  next.elev = levelnum;
X#ifndef hpux
X  sprintf(next.desc, "%s ", getenv("USER"));
X#else
X  sprintf(next.desc, "%s ", getenv("LOGNAME"));
X#endif
X  cur = -1;
X  /* Insert new score in old high score list */
X  if (numscore < NUMHIGH || tops[NUMHIGH - 1].score < next.score)
X  {
X    /* Iterate through high score list */
X    for (i = (numscore >= NUMHIGH ? NUMHIGH - 2 : numscore - 1); i >= 0; i--)
X    {
X      /* Look for place for insertion */
X      if (next.score > tops[i].score)
X	tops[i + 1] = tops[i];	/* Move old scores down one place in list */
X      else
X	break;			/* Found spot for insertion */
X    }
X    tops[i + 1] = next;		/* Overwrite entry in high score list */
X    cur = i + 1;		/* Remember where new high score was inserted */
X    /* Increment the number of high scores */
X    if (numscore < NUMHIGH)
X      numscore++;
X  }
X  /* Increment and print the number of games played */
X  /* Print out new high score list */
X  for (i = 0; i < numscore; ++i)
X  {
X    /* Flag new high score with a leading > */
X    if (i == cur)
X      putchar('*');
X    else
X      putchar(' ');
X    printf("%-16s- Died on level %3d. Started on level %3d.  Score: %8d.\n",
X	   tops[i].desc, tops[i].elev, tops[i].slev, tops[i].score);
X  }
X  /* If current game did not make it to the high score list, print it */
X  /* afterwords */
X  if (cur == -1)
X  {
X    puts("You are quite disappointing:");
X    printf("*%-16s- Died on level %3d. Started on level %3d.  Score: %8d.\n",
X	   next.desc, next.elev, next.slev, next.score);
X  }
X  /* Save new high score list to score file */
X  sprintf(buf, "%s/scores", LIB);
X  sfile = fopen(buf, "w");
X  if (sfile == NULL)
X  {
X    perror(buf);
X    return;
X  }
X  for (i = 0; i < numscore; ++i)
X    fprintf(sfile, "%d %d %d %s\n", tops[i].score, tops[i].slev,
X	    tops[i].elev, tops[i].desc);
X  fclose(sfile);
X}
END_OF_FILE
  if test 3472 -ne `wc -c <'xbd/scores.c'`; then
    echo shar: \"'xbd/scores.c'\" unpacked with wrong size!
  fi
  # end of 'xbd/scores.c'
fi
if test -f 'xbd/shared.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xbd/shared.c'\"
else
  echo shar: Extracting \"'xbd/shared.c'\" \(9674 characters\)
  sed "s/^X//" >'xbd/shared.c' <<'END_OF_FILE'
X/*********************************************/
X/* you just keep on pushing my luck over the */
X/*          BOULDER        DASH              */
X/*                                           */
X/*     Jeroen Houttuin, ETH Zurich, 1990     */
X/*********************************************/
X
X#include <stdio.h>
X#include <X11/Xlib.h>
X#include <X11/keysym.h>
X#include <X11/Xutil.h>
X#include <errno.h>
X#include <sys/time.h>
X#include <sys/timeb.h>
X#include "xbd.h"
X
X/* Manufaction a 32x32 graphics cursor used in a XFill... operation. */
XGC
Xmakegc(func, bits)
X  int             func;		/* Drawing function such as GXcopy or GXor. */
X  char            bits[];	/* Bits describing fill pattern.  Produced in
X				 * an X11 */
X/* bitmap file usually. */
X{
X  static XGCValues gcv;
X  Pixmap          pmap;
X
X  /* Build X11 bitmap from data in bits */
X  pmap = XCreatePixmapFromBitmapData(disp, wind, bits, 32, 32, BlackPixel(disp, 0),
X			       WhitePixel(disp, 0), DisplayPlanes(disp, 0));
X  /* Assign the graphics cursor parameters */
X  gcv.function = func;
X  gcv.foreground = BlackPixel(disp, 0);
X  gcv.background = WhitePixel(disp, 0);
X  gcv.tile = pmap;
X  gcv.fill_style = FillTiled;
X  /* Return the created graphics cursor */
X  return (XCreateGC(disp, wind, GCFunction | GCForeground | GCBackground |
X		    GCTile | GCFillStyle, &gcv));
X}
X
Xvoid
Xmake_gcs()
X{
X  pgc = makegc(GXcopy, player_bits);
X  pgc1 = makegc(GXcopy, player_bits);
X  pgc2 = makegc(GXcopy, player2_bits);
X  wgc = makegc(GXcopy, wall_bits);
X  Wgc = makegc(GXcopy, wall_bits);
X  Wgc2 = makegc(GXcopy, wall2_bits);
X  sgc = makegc(GXcopy, space_bits);
X  ggc = makegc(GXcopy, grass_bits);
X  dgc = makegc(GXcopy, diamond_bits);
X  dgc1 = makegc(GXcopy, diamond_bits);
X  dgc2 = makegc(GXcopy, diamond2_bits);
X  Sgc = makegc(GXcopy, steel_bits);
X  bgc = makegc(GXcopy, boulder_bits);
X  xgc = makegc(GXand, explosion_bits);
X  lgc = makegc(GXcopy, lmonster_bits);
X  lgc1 = makegc(GXcopy, lmonster_bits);
X  lgc2 = makegc(GXcopy, lmonster2_bits);
X  rgc = makegc(GXcopy, rmonster_bits);
X  rgc1 = makegc(GXcopy, rmonster_bits);
X  rgc2 = makegc(GXcopy, rmonster2_bits);
X  egc = makegc(GXcopy, eater_bits);
X  egc1 = makegc(GXcopy, eater_bits);
X  egc2 = makegc(GXcopy, eater2_bits);
X  Egc = makegc(GXcopy, steel_bits);
X  Egc1 = makegc(GXcopy, steel_bits);
X  Egc2 = makegc(GXcopy, exit2_bits);
X  ngc = makegc(GXcopy, nucbal_bits);
X  Bgc = makegc(GXcopy, blob_bits);
X  Bgc1 = makegc(GXcopy, blob_bits);
X  Bgc2 = makegc(GXcopy, blob2_bits);
X  tgc = makegc(GXcopy, wall_bits);
X  tgc1 = makegc(GXcopy, wall_bits);
X  tgc2 = makegc(GXcopy, tinkle1_bits);
X  tgc3 = makegc(GXcopy, tinkle2_bits);
X}
X
Xvoid
Xinit_level(levelnum)
X  int             levelnum;
X{
X
X  FILE           *levelfile;
X  char            buf[300], *ptr;
X  extern char    *getenv();
X
X  Egc = Egc1;			/* don't blink EXIT */
X  blobcollapse = False;
X  blobcells = 0;
X  scoreobs = True;
X  tinkact = False;
X  levincreased = False;
X  strcpy(levname, "No_name_for_this_level_yet");
X
X  /* Manufaction the file name by starting with the world name and */
X  /* appending the level number to it. */
X  if (ptr = getenv("XBDLIB"))
X    strcpy(filename, ptr);
X  else
X    strcpy(filename, LIB);
X  strcat(filename, "/");
X  strcat(filename, LEVELPREFIX);
X  sprintf(filename + strlen(filename), "%03d", levelnum);
X  /* Open level file for reading */
X  levelfile = fopen(filename, "r");
X  /* If level file does not exist, use the default level file. */
X  if (levelfile == NULL)
X  {
X    /* Build the default level name */
X    if (ptr = getenv("XBDLIB"))
X      strcpy(buf, ptr);
X    else
X      strcpy(buf, LIB);
X    strcat(buf, "/");
X    strcat(buf, "/default");
X    /* Open default level file for reading */
X    levelfile = fopen(buf, "r");
X    if (levelfile == NULL)
X    {
X      perror(LEVELPREFIX);
X      exit(1);
X    }
X  }
X  /* Load the first line of the level file */
X  if (fgets(buf, 300, levelfile) == NULL)
X  {
X    x = w;
X    y = h;
X    speed = 15;
X    diareq = 12;
X    diapoints = 0;
X    extradiapoints = 0;
X    blobbreak = 200;
X    time = 1000;
X  } else
X  {
X    /* Extract the level parameters */
X    sscanf(buf, "%d %d %d %d %d %d %d %d %d %s", &y, &x, &speed, &diareq,
X	 &diapoints, &extradiapoints, &blobbreak, &tinkdur, &time, levname);
X  }
X
X  if (xin && yin)
X  {
X    x = xin;
X    y = yin;
X  }				/* read in from editor command line */
X  /*
X   * if (x > w) x = w; if (y > h) y = h; if (x < 2) x = 2; if (y < 1) y = 1;
X   * 
X  /*
X   * Iterate through each horizontal line
X   */
X  for (i = 0; i < y; ++i)
X  {
X    /* Load the next line from the file */
X    if (fgets(buf, 300, levelfile) != NULL)
X    {
X      /* Go through each horizontal position and copy the data into */
X      /* the level array. */
X      for (j = 0; j < x; ++j)
X      {
X	/* Break out if line ends prematurely */
X	if (buf[j] == '\n' || buf[j] == '\0')
X	  field[i][j].content = STEEL;	/* break; */
X	field[i][j].content = buf[j];
X	field[i][j].changed = True;
X	field[i][j].dir = N;
X	field[i][j].speed = 0;
X	field[i][j].stage = 0;
X	field[i][j].caught = True;
X	field[i][j].checked = False;
X      }
X    } else
X      j = 0;
X    for (; j < x; ++j)
X      field[i][j].content = STEEL;
X  }
X  /* Close the level file */
X  fclose(levelfile);
X}
X
X/* Draw the score and level number */
Xvoid
Xdraw_score()
X{
X  char            buf[200];
X
X  /* Build the output string */
X  sprintf(buf, "sc:%d lv:%d ls:%d ds:%d dp:%d ti:%d       %s", score, levelnum,
X	  lives, diareq, diapoints, time / 10, levname);
X  /* Clear the current score line */
X  XFillRectangle(disp, wind, whitegc, 0, y << 5, x << 5, SCORESIZE);
X  /* Actually draw the text */
X  XDrawString(disp, wind, scoregc, 0, (y << 5) + SCORESIZE - 1, buf,
X	      strlen(buf));
X  scoreobs = False;
X}
X
Xvoid
Xxstart(evmask)
X  long            evmask;	/* Event mask which will be used in
X				 * XSelectInput */
X{
X  XGCValues       xgcv;
X  XWMHints        wmhints;
X
X  /* create X window */
X  disp = XOpenDisplay(NULL);
X  /* Check to see if the open display succeeded */
X  if (disp == NULL)
X  {
X    fprintf(stderr, "Display open failed.  Check DISPLAY environment variable.\n"
X      );
X    exit(-1);
X  }
X  wind = XCreateSimpleWindow(disp, DefaultRootWindow(disp), 0, 1,
X			     x << 5, (y << 5) + SCORESIZE, 1,
X			     WhitePixel(disp, 0), BlackPixel(disp, 0));
X  /* Check to see if the open window succeeded */
X  if (wind == 0)
X  {
X    fprintf(stderr, "Window open failed.\n");
X    XCloseDisplay(disp);
X    exit(-1);
X  }
X  /* Load in the font used to display the score */
X  scorefont = XLoadFont(disp, SCOREFONT);
X  /* Create GC which will be used from drawing score */
X  xgcv.function = GXcopy;
X  xgcv.font = scorefont;
X  xgcv.foreground = BlackPixel(disp, 0);
X  xgcv.background = WhitePixel(disp, 0);
X  scoregc = XCreateGC(disp, wind,
X		      GCFunction | GCFont | GCForeground | GCBackground,
X		      &xgcv);
X  /* Create GC which will be used for clearing score line */
X  xgcv.function = GXcopy;
X  scorefont = XLoadFont(disp, SCOREFONT);
X  xgcv.foreground = WhitePixel(disp, 0);
X  xgcv.background = BlackPixel(disp, 0);
X  whitegc = XCreateGC(disp, wind,
X		      GCFunction | GCForeground | GCBackground,
X		      &xgcv);
X  wmhints.flags = InputHint;
X  wmhints.input = True;
X  XSetWMHints(disp, wind, &wmhints);
X
X  XSelectInput(disp, wind, evmask);
X  XMapRaised(disp, wind);
X  XWarpPointer(disp, None, wind, 0, 0, 0, 0, 11, 1);
X}
X
X/* Gracefully shut X windows down.  It is not strictly necessary to */
X/* call this function. */
Xvoid
Xxend()
X{
X  gamestop = True;		/* tricky; prevent ticker function from using
X				 * Xlib fcts */
X  XUnloadFont(disp, scorefont);
X  XUnmapWindow(disp, wind);
X  XDestroyWindow(disp, wind);
X  XCloseDisplay(disp);
X}
X
Xvoid
Xdraw_field(redrawall)
X  short           redrawall;
X{
X  char            c;
X
X  /* Iterate through each horizontal line */
X  for (i = y - 1; i >= 0; --i)
X  {
X    for (j = 0; j < x; ++j)
X    {
X      if (field[i][j].changed || redrawall)	/* only redraw changed cells */
X      {
X	c = field[i][j].content;
X	switch (c)
X	{
X	case GRASS:
X	  XFillRectangle(disp, wind, ggc, j << 5, i << 5, 32, 32);
X	  break;
X	case SPACE:
X	  XFillRectangle(disp, wind, sgc, j << 5, i << 5, 32, 32);
X	  break;
X	case PLAYER:
X	  XFillRectangle(disp, wind, pgc, j << 5, i << 5, 32, 32);
X	  break;
X	case WALL:
X	  XFillRectangle(disp, wind, wgc, j << 5, i << 5, 32, 32);
X	  break;
X	case MAGICWALL:
X	  XFillRectangle(disp, wind, Wgc, j << 5, i << 5, 32, 32);
X	  break;
X	case DIAMOND:
X	  XFillRectangle(disp, wind, dgc, j << 5, i << 5, 32, 32);
X	  break;
X	case BOULDER:
X	  XFillRectangle(disp, wind, bgc, j << 5, i << 5, 32, 32);
X	  break;
X	case EXPLOSION:
X	  XFillRectangle(disp, wind, xgc, j << 5, i << 5, 32, 32);
X	  break;
X	case LMONSTER:
X	  XFillRectangle(disp, wind, lgc, j << 5, i << 5, 32, 32);
X	  break;
X	case RMONSTER:
X	  XFillRectangle(disp, wind, rgc, j << 5, i << 5, 32, 32);
X	  break;
X	case NUCBAL:
X	  XFillRectangle(disp, wind, ngc, j << 5, i << 5, 32, 32);
X	  break;
X	case BLOB:
X	  XFillRectangle(disp, wind, Bgc, j << 5, i << 5, 32, 32);
X	  break;
X	case TINKLE:
X	  XFillRectangle(disp, wind, tgc, j << 5, i << 5, 32, 32);
X	  break;
X	case EATER:
X	  XFillRectangle(disp, wind, egc, j << 5, i << 5, 32, 32);
X	  break;
X	case EXIT:
X	  XFillRectangle(disp, wind, Egc, j << 5, i << 5, 32, 32);
X	  break;
X	case STEEL:
X	default:
X	  field[i][j].content = STEEL;
X	  XFillRectangle(disp, wind, Sgc, j << 5, i << 5, 32, 32);
X	  break;
X	}
X	field[i][j].changed = False;
X      }
X    }
X  }
X  if (scoreobs)
X    draw_score();
X}
X
Xvoid
Xset_cell(i, j, content)
X  int             i, j;
X  char            content;
X{
X  field[i][j].content = content;
X  field[i][j].speed = 0;
X  field[i][j].changed = True;
X  field[i][j].stage = 0;
X  field[i][j].caught = True;
X  field[i][j].checked = False;
X}
END_OF_FILE
  if test 9674 -ne `wc -c <'xbd/shared.c'`; then
    echo shar: \"'xbd/shared.c'\" unpacked with wrong size!
  fi
  # end of 'xbd/shared.c'
fi
if test -f 'xbd/xbd.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xbd/xbd.c'\"
else
  echo shar: Extracting \"'xbd/xbd.c'\" \(6013 characters\)
  sed "s/^X//" >'xbd/xbd.c' <<'END_OF_FILE'
X/*********************************************/
X/* you just keep on pushing my luck over the */
X/*          BOULDER        DASH              */
X/*                                           */
X/*     Jeroen Houttuin, ETH Zurich, 1990     */
X/*********************************************/
X
X#include <stdio.h>
X#include <X11/Xlib.h>
X#include <X11/keysym.h>
X#include <X11/Xutil.h>
X#include <signal.h>
X#include <sys/time.h>
X#include <sys/timeb.h>
X#include "xbd.h"
X
Xvoid
Xdie(display, event)
X  Display        *display;
X  XErrorEvent    *event;
X{
X  char            buffer[BUFSIZ];
X  XGetErrorText(display, event->error_code, buffer, BUFSIZ);
X  (void) fprintf(stderr, "Display %s: Error %s\n",
X		 XDisplayName(display), buffer);
X  seteuid(getuid());
X  do
X  {
X    (void) fprintf(stderr, "(R)eturn (D)ump Core (E)xit:");
X    switch (fgetc(stdin))
X    {
X    case 'R':
X    case 'r':
X      return;
X    case 'E':
X    case 'e':
X      exit(1);
X      break;
X    case 'D':
X    case 'd':
X      kill(0, 3);
X      break;
X    default:
X      break;
X    }
X  } while (1);
X}
X
Xvoid
Xinit_vars()
X{
X  blobbreak = 100;
X  critical = 100;
X  blobcells = 0;
X  curorder = STAND;
X  gamestop = True;
X  scoreobs = True;
X  stoplevel = False;
X  levelnum = 1;
X  speed = 1;
X  lives = 4;
X  xin = 0;
X  yin = 0;
X  players = 1;
X}
X
Xstruct itimerval cycletime;	/* Structure used when setting up timer */
Xvoid
Xadapt_timer()
X{
X  long            period;
X
X  if (speed <= 0)
X    speed = 1;
X  period = (long) 3 *(long) 625000 / speed;
X  cycletime.it_interval.tv_sec = period / 1000000;
X  cycletime.it_interval.tv_usec = period % 1000000;
X  cycletime.it_value = cycletime.it_interval;
X  setitimer(ITIMER_REAL, &cycletime, (struct itimerval *) NULL);
X}
X
X/* Handle a key stroke by the user. */
Xvoid
Xhandle_key(keyhit)
X  KeySym          keyhit;	/* Key symbol for key stroke provided by X
X				 * windows */
X{
X  if (players <= 0)
X  {
X    init_level(levelnum);
X    adapt_timer();
X    XResizeWindow(disp, wind, x << 5, (y << 5) + SCORESIZE);
X    stoplevel = False;
X    draw_field(True);
X    gamestop = True;
X    players = 1;
X    return;
X  }
X  switch (keyhit)
X  {
X  case XK_question:
X  case XK_slash:
X    puts("Control the player using keyboard keys.");
X    puts("CTRL key - steal instead of go");
X    puts("h,left arrow -  left");
X    puts("l,right arrow -  right");
X    puts("k,up arrow -  up");
X    puts("j,down arrow -  down");
X    puts("\nSPACE - pause/continue game");
X    puts("^C - kill the game");
X    puts("^D - give Dutch act");
X    puts("^R - redraw the screen");
X    break;
X  case XK_space:
X  case XK_R11:
X    gamestop = !gamestop;
X    break;
X  case XK_Left:
X  case XK_H:
X  case XK_h:
X    curorder = LEFT;
X    gamestop = False;
X    break;
X  case XK_Up:
X  case XK_K:
X  case XK_k:
X    curorder = UP;
X    gamestop = False;
X    break;
X  case XK_Down:
X  case XK_J:
X  case XK_j:
X    curorder = DOWN;
X    gamestop = False;
X    break;
X  case XK_Right:
X  case XK_L:
X  case XK_l:
X    curorder = RIGHT;
X    gamestop = False;
X    break;
X  }
X}
X
X/**** Timer  procedures  ****/
X
X/* Function which is called whenever the timer signal goes off */
Xvoid
Xticker(sig)
X  int             sig;
X{
X  signal(SIGALRM, SIG_IGN);
X  /* Ignore any signal which is not an alarm.  Ignore alarm signals */
X  /* after a new level has been drawn until a key is hit. */
X  if (sig != SIGALRM)
X    return;
X  if (time)
X    time--;
X  if (tinkact)
X    tinkdur--;
X  if (time % 10 == 1)
X    scoreobs = True;
X
X  if (!gamestop)
X  {
X    calculate_field();
X    draw_field(0);
X    XFlush(disp);
X  }
X  if (stoplevel)
X  {
X    init_level(levelnum);
X    adapt_timer();
X    XResizeWindow(disp, wind, x << 5, (y << 5) + SCORESIZE);
X    XFlush(disp);
X    gamestop = True;
X    stoplevel = False;
X  }
X  signal(SIGALRM, ticker);
X}
X/**** End timer procedures ****/
X
Xvoid
Xmain(argc, argv)
X  int             argc;
X  char          **argv;
X{
X  long            period;
X  KeySym          keyhit;
X  char            buf[50];
X  static XEvent   xev;
X  int             keycount, i;
X
X  printf("type ? for help.\n");
X
X  init_vars();
X
X  /* scan the command line for executing parameters and flags */
X  for (i = 1; i < argc; ++i)
X  {
X    if (argv[i][0] == '-')
X    {
X      if (argv[i][1] == 'l')
X      {
X	if (argv[i][2] == '\0' && i + 1 < argc)
X	{
X	  sscanf(argv[i + 1], "%d", &levelnum);
X	  i++;
X	} else
X	  sscanf(argv[i] + 2, "%d", &levelnum);
X      } else
X      {
X	printf("usage: xbd [-l <level>] \n");
X	exit(1);
X      }
X    }
X  }
X
X  levelstart = levelnum;
X  init_level(levelnum);
X  xstart(EVMASK);
X  XSetErrorHandler(die);
X  XStoreName(disp, wind, "BOULDER DASH ?");
X  make_gcs();
X  draw_field(True);
X  draw_score();
X
X  /* initialize timer structure according to speed */
X  if (speed <= 0)
X    speed = 1;
X  period = (long) 3 *(long) 625000 / speed;
X  cycletime.it_interval.tv_sec = period / 1000000;
X  cycletime.it_interval.tv_usec = period % 1000000;
X  cycletime.it_value = cycletime.it_interval;
X  /* start the system timer.  the timer signal catcher will be set */
X  /* after the first x event is received. */
X  signal(SIGALRM, SIG_IGN);
X  setitimer(ITIMER_REAL, &cycletime, (struct itimerval *) NULL);
X
X  while (lives > 0)		/* MAIN LOOP */
X  {
X    XWindowEvent(disp, wind, EVMASK, &xev);
X    signal(SIGALRM, SIG_IGN);
X    if ((xev.type == Expose && xev.xexpose.count == 0))
X    {
X      draw_field(True);
X      draw_score();
X    } else if (xev.type == KeyPress)
X    {
X      keycount = XLookupString(&xev, buf, 50, &keyhit, (XComposeStatus *) NULL);
X      if (steal = (xev.xkey.state & ControlMask))
X	switch (keyhit)
X	{
X	  /* ^C, ^U kill the game */
X	case XK_C:
X	case XK_U:
X	case XK_c:
X	case XK_u:
X	case XK_backslash:
X	  goto game_over;
X	  /* ^D Kill; commit suicide */
X	case XK_D:
X	case XK_d:
X	  curorder = KILL;
X	  /* ^R redraws the level */
X	case XK_R:
X	case XK_r:
X	  draw_field(True);
X	  break;
X	default:
X	  handle_key(keyhit);
X	  break;
X	}
X      else
X	handle_key(keyhit);
X    }
X    if (!gamestop)
X    {
X      XSync(disp, False);
X      signal(SIGALRM, ticker);
X    }
X  }
Xgame_over:
X  XSync(disp, False);
X  xend();
X  add_score();
X}
END_OF_FILE
  if test 6013 -ne `wc -c <'xbd/xbd.c'`; then
    echo shar: \"'xbd/xbd.c'\" unpacked with wrong size!
  fi
  # end of 'xbd/xbd.c'
fi
if test -f 'xbd/xbd.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xbd/xbd.h'\"
else
  echo shar: Extracting \"'xbd/xbd.h'\" \(4426 characters\)
  sed "s/^X//" >'xbd/xbd.h' <<'END_OF_FILE'
X/*********************************************/
X/* you just keep on pushing my luck over the */
X/*           BOULDER        DASH             */
X/*                                           */
X/*     Jeroen Houttuin, ETH Zurich, 1990     */
X/*********************************************/
X
X/* define bit maps */
X#include "bitmap/player.bits"
X#include "bitmap/player2.bits"
X#include "bitmap/wall.bits"
X#include "bitmap/wall2.bits"
X#include "bitmap/tinkle1.bits"
X#include "bitmap/tinkle2.bits"
X#include "bitmap/space.bits"
X#include "bitmap/grass.bits"
X#include "bitmap/diamond.bits"
X#include "bitmap/diamond2.bits"
X#include "bitmap/steel.bits"
X#include "bitmap/boulder.bits"
X#include "bitmap/explosion.bits"
X#include "bitmap/rmonster.bits"
X#include "bitmap/rmonster2.bits"
X#include "bitmap/lmonster.bits"
X#include "bitmap/lmonster2.bits"
X#include "bitmap/nucbal.bits"
X#include "bitmap/blob.bits"
X#include "bitmap/blob2.bits"
X#include "bitmap/eater.bits"
X#include "bitmap/eater2.bits"
X#include "bitmap/exit2.bits"
X
X#define w 35
X#define h 26
X#define LEVELPREFIX "xbdlev"
X
X#define SCOREFONT "-adobe-times-bold-r-normal--18-180-75-75-p-99-iso8859-1"
X#define SCORESIZE 18
X
X#define EVMASK KeyPressMask | ExposureMask | ButtonPressMask | PointerMotionMask | FocusChangeMask
X
X/* direction masks */
X#define N 0
X#define E 1
X#define S 2
X#define W 3
X#define NODIR 4
X
X#define SPACEEXPLO 0
X#define BOULDEXPLO 10
X#define DIAEXPLO 20
X#define PROPAGATED 10
X
X#define PLAYER              'p'
X#define SPACE               ' '
X#define LMONSTER            'l'	/* Right turning monster */
X#define RMONSTER            'r'
X#define GRASS               'g'
X#define WALL                'w'
X#define MAGICWALL           'W'	/* Expanding wall */
X#define DIAMOND             'd'
X#define STEEL               'S'
X#define BOULDER             'b'
X#define EXPLOSION           'x'
X#define EXIT                'E'
X#define EATER               'e'
X#define NUCBAL              'n'	/* Nuclear ballon */
X#define BLOB                'B'	/* lava */
X#define TINKLE              't'	/* Tinkle wall */
X
XFont            scorefont;	/* Font used to display score */
XGC              whitegc, scoregc, gc, Bgc, Bgc1, Bgc2, ngc, egc, egc1,
X                egc2, Egc1, Wgc, Wgc2, Egc2, Egc, lgc, lgc1, lgc2, rgc,
X                rgc1, rgc2, xgc, Sgc, bgc
X               ,dgc, dgc1, dgc2, wgc, pgc, pgc1, pgc2, sgc, ggc, tgc, tgc1,
X                tgc2, tgc3;
Xchar            filename[300];	/* Current file name of this level */
Xchar            levname[64];	/* Levelname */
Xint             i, j, ii, jj, jjj;
Xint             blobbreak;
Xint             critical;
Xint             time;		/* Current clock tick number */
Xint             blobcells;
Xint             tinkdur;	/* Tinkle duration */
XBool            tinkact;	/* Tinkle active   */
XBool            levincreased;
Xint             x, y, xin, yin, players, lives, levelnum, levelstart, speed,
X                diareq, diapoints, extradiapoints;
XBool            steal;		/* steal instead of go */
XBool            stoplevel, blobcollapse;
Xenum directs
X{
X  STAND, UP, DOWN, LEFT, RIGHT, KILL
X};
X
Xenum directs    curorder;	/* Current order which player has */
X/* typed at the keyboard. */
Xstruct cell
X{
X  char            content;
X  Bool            changed;	/* has cell changed since last drawing */
X  Bool            caught;	/* for BLOB */
X  Bool            checked;	/* for BLOB algorithm */
X  char            dir;
X  short           speed;
X  short           stage;	/* painting stage for blinking etc. */
X}               field[h][w];
X
XBool            gamestop;
XBool            scoreobs;	/* is score line obsolete ? */
Xint             levelnum;	/* Current level number */
Xint             lives;		/* Current number of lives */
Xint             score;		/* Total score */
Xint             speed;		/* Speed of game.  1 is slowest, 15 is
X				 * default */
Xchar            filename[300];	/* Current file name of this level */
X
XDisplay        *disp;		/* X11 display of client */
XWindow          wind;		/* X11 window where game is displayed */
X
XGC              makegc();
Xvoid            make_gcs();
Xvoid            init_level();
Xvoid            draw_score();
Xvoid            xstart();
Xvoid            xend();
Xvoid            draw_field();
Xvoid            set_cell();
Xvoid            move_cell();
Xvoid            explode();
XBool            move_monster();
XBool            search_destroy();
Xvoid            calculate_field();
Xvoid            add_score();
END_OF_FILE
  if test 4426 -ne `wc -c <'xbd/xbd.h'`; then
    echo shar: \"'xbd/xbd.h'\" unpacked with wrong size!
  fi
  # end of 'xbd/xbd.h'
fi
if test -f 'xbd/xbd.man' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xbd/xbd.man'\"
else
  echo shar: Extracting \"'xbd/xbd.man'\" \(3347 characters\)
  sed "s/^X//" >'xbd/xbd.man' <<'END_OF_FILE'
X.TH Boulder-dash l "April 1 1990"
X.UC 4
X.SH NAME
XBoulder-dash (v1.2) - Collect diamonds, kill monsters, close in blob etc. etc.
X.SH SYNOPSIS
X.B xbd
X[
X.B \-l
X.I level
X]
X.br
X.B xbde
X.B \-l
X.I level
X[
X.B \-w
X.I width
X]
X[
X.B \-h
X.I height
X]
X.SH DESCRIPTION
X.PP
X.I xbd
Xis a game designed for X windows (originally a similar game with the same name
Xran on CBM64).
X.I xbde
Xis used to create and edit new levels which can be used by
X.I Boulder-dash.
X.PP
XThe goal in
X.I Boulder-dash
Xis to collect a certain number
X.I (ds)
Xof diamonds per level
X.I (lv)
Xand then enter the next level by moving to the blinking exit-field, thus incrementing your number of lives
X.I (ls).
XA diamond is worth
X.I (dp)
Xpoints. Normally extra diamonds are worth more.
X.SH OPTIONS
XThe
X.B "\-l"
Xoption sets the level number for editing or for starting the game.
XThis may be any integer greater than 0.  By default, the game starts
Xat level 1. The
X.B "\-w"
Xand
X.B "\-h"
Xoptions set the width and height of a newly created level.
X.SH USAGE
XWhen playing
X.I Boulder-dash
Xthe following keyboard commands may be used:
X.PP
XSPACE,R11		\- 		stop
X.br
Xh,left arrow 	\- 		move left
X.br
Xl,right arrow 	\- 		move right
X.br
Xk,up arrow 	\- 		move up
X.br
Xj,down arrow 	\-		move down
X.PP
X.br
X?			\-		help
X.PP
XWhen used in combination with the 
X.I control key,
Xthe direction keys make the player 
X.I 'steal'
Xinstead of 
X.I 'go'.
XIn addition, some other control key combinations can be used:
X.PP
X^C		\- 		kill the game
X.br
X^D		\-		give dutch act
X.br
X^R 		\- 		redraw the level
X.PP
XThe mouse must be placed in the game window to use the keyboard
Xcommands.  When the game starts or a level is finished , everything is frozen, and any key will
Xstart/continue the game.
X.PP
X.I xbde
Xcan be used to edit levels.  Levels are stored in ASCII files. The
Xfirst line in a level file contains level specific parameters that
Xshould be edited by hand. The parameters are:
X
X.br
Xheight width speed 
X.I dp
X.I extra-dp
Xblob-brake
Xtinkle-dur
X.I ti name
X
X.br
XWhere blob-brake indicates how strongly blob propagation is slowed down.
Xtink-dur is the time tinkle-walls will keep their magic power. 
X.I ti 
Xis the time permitted to complete this level. 
X.I name
Xis the name of the level.
X.br
XBlocks are painted by pressing the left mouse button.  Spaces are 
Xpainted by pressing the right mouse button.  A new block type is 
Xselected by one of the following keys:
X.PP
X<space> \- draw spaces
X.br
Xb \- draw boulder
X.br
Xd \- draw diamond
X.br
Xe \- draw eater (initial speed: 0)
X.br
Xg \- draw grass
X.br
Xl \- draw left-monster (initial direction: NORTH)
X.br
Xp \- draw player
X.br
Xr \- draw right-monster (initial direction: NORTH)
X.br
Xt \- draw tinkle wall
X.br
Xw \- draw wall
X.br
Xx \- draw explosion (SPACEEXPLO)
X.br
XB \- draw blob
X.br
XE \- draw exit
X.br
XN \- draw nuclear balloon
X.br
XS \- draw steel
X.br
XW \- draw magic wall
X.PP
X.br
XOther commands are:
X.PP
X.br
X^c \- Quit
X.br
X^E \- Erase level
X.br
X^w \- Save level and quit
X.SH AUTHOR
XJeroen Houttuin, Informatikdienste, ETH Zurich 1990.
X.SH CREDITS
XCBM64 for the idea. Alexander Siegel (Cornell University)
Xfor example X-programming in 
X.I 'golddig'.
XChristos S. Zoulas (Cornell University) for Imakefile and bug fixes.
X.SH FILES
Xxbd - Boulder-dash executable
X.br
Xxbde - Boulder-dash editor executable
X.br
Xscores - high score list
X.br
Xdefault - default level
X.br
Xxbdlev### - levels
END_OF_FILE
  if test 3347 -ne `wc -c <'xbd/xbd.man'`; then
    echo shar: \"'xbd/xbd.man'\" unpacked with wrong size!
  fi
  # end of 'xbd/xbd.man'
fi
if test -f 'xbd/xbde.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xbd/xbde.c'\"
else
  echo shar: Extracting \"'xbd/xbde.c'\" \(5575 characters\)
  sed "s/^X//" >'xbd/xbde.c' <<'END_OF_FILE'
X/*********************************************/
X/* you just keep on pushing my luck over the */
X/*           BOULDER        DASH             */
X/*                                           */
X/*     Jeroen Houttuin, ETH Zurich, 1990     */
X/*********************************************/
X
X#include <stdio.h>
X#include <X11/Xlib.h>
X#include <X11/keysym.h>
X#include <X11/Xutil.h>
X#include "xbd.h"
X
Xchar            curchar;
XGC              drawgc;
X
Xvoid
Xinit_vars()
X{
X  levelnum = -1;
X  xin = 0;
X  yin = 0;
X}
X
X/* Save the current level back into a file.  The global variable */
X/* filename is used to determine the file name. */
Xvoid
Xsave_level()
X{
X  FILE           *levelfile;
X  char            buf[300];
X  register int    i, j;
X
X  /* Open the data file */
X  levelfile = fopen(filename, "w");
X  if (levelfile == NULL)
X  {
X    exit(1);
X  }
X  /* Write out the size of the level.  Normal text is used so that */
X  /* levels can be easily copied across architectures. */
X  fprintf(levelfile, "%d %d %d %d %d %d %d %d %d %s\n", y, x,
X	  speed, diareq, diapoints, extradiapoints, blobbreak, tinkdur, time, levname);
X  /* Terminate the lines for writing out the horizontal level lines */
X  buf[x] = '\n';
X  buf[x + 1] = '\0';
X  /* Iterate through each vertical position */
X  for (i = 0; i < y; ++i)
X  {
X    /* Copy each horizontal line into the output buffer */
X    for (j = 0; j < x; ++j)
X      buf[j] = field[i][j].content;
X    /* Write the line out to the file */
X    fputs(buf, levelfile);
X  }
X  /* Close the data file */
X  fclose(levelfile);
X}
X
X/* Main routine for editing levels */
Xvoid
Xmain(argc, argv)
X  int             argc;
X  char          **argv;
X{
X  register int    i, j;
X  static XEvent   xev;
X  KeySym          keyhit;
X  int             keycount;
X  int             tmp;
X  char            buf[50];
X
X  init_vars();
X
X  /* Read in command line options */
X  for (i = 1; i < argc; ++i)
X  {
X    if (argv[i][0] == '-')
X    {
X      /* -w sets the level width */
X      if (argv[i][1] == 'w')
X      {
X	if (argv[i][2] == '\0' && i + 1 < argc)
X	{
X	  sscanf(argv[i + 1], "%d", &xin);
X	  i++;
X	} else
X	  sscanf(argv[i] + 2, "%d", &xin);
X      }
X      /* -h sets the level height */
X      else if (argv[i][1] == 'h')
X      {
X	if (argv[i][2] == '\0' && i + 1 < argc)
X	{
X	  sscanf(argv[i + 1], "%d", &yin);
X	  i++;
X	} else
X	  sscanf(argv[i] + 2, "%d", &yin);
X      }
X      /* -l sets the level number */
X      else if (argv[i][1] == 'l')
X      {
X	if (argv[i][2] == '\0' && i + 1 < argc)
X	{
X	  sscanf(argv[i + 1], "%d", &levelnum);
X	  i++;
X	} else
X	  sscanf(argv[i] + 2, "%d", &levelnum);
X      } else
X      {
X	printf("usage: xbde [-h <height>] [-w <width>] -l <level> \n");
X	exit(1);
X      }
X    }
X  }
X  /* Make sure some value was chosen for the level number.  This */
X  /* discourages everybody editing the same level all the time. */
X  if (levelnum == -1)
X  {
X    printf("usage: editor [-h <height>] [-w <width>] -l <level> \n");
X    exit(1);
X  }
X  /* Load in level data from file. */
X  init_level(levelnum);
X
X  printf("Welcome.  Type h for help.\n");
X
X  /* Start up X windows and create all graphics cursors */
X  xstart(EVMASK);
X  /* Set the name of the output window */
X  XStoreName(disp, wind, "BOULDER DASH - LEVEL EDITOR");
X  XFlush(disp);			/* initializing flush */
X  make_gcs();
X  Egc = Egc2;
X  Wgc = Wgc2;
X  tgc = tgc3;
X  drawgc = pgc;
X  draw_field(True);
X
X  /* Main event loop */
X  do
X  {
X    /* Get the next X window event */
X    XWindowEvent(disp, wind, EVMASK, &xev);
X
X    /* If it was an expose event, redraw everything */
X    if (xev.type == Expose)
X    {
X      draw_field(True);
X      draw_score();
X    } else if (xev.type == KeyPress)
X    {
X      keycount = XLookupString(&xev, buf, 50, &keyhit, (XComposeStatus *) NULL);
X      /* If the 'h', '?' or '/' key was hit, print out the text */
X      /* descriptions of each block type */
X      if (keyhit == XK_H || keyhit == XK_h || keyhit == XK_question ||
X	  keyhit == XK_slash)
X      {
X	puts("^w - finish editing and save the level.");
X	puts("^c - quit editing.");
X	puts("^E - erase level.");
X	puts("Use the left mouse button to paint blocks.");
X	puts("Use the right mouse button to erase blocks.");
X	putchar('\n');
X      }
X      /* A ^E erases the entire level */
X      else if ((keyhit == XK_E) &&
X	       (xev.xkey.state & ControlMask))
X      {
X	/* Replace level contents with space */
X	for (i = 0; i < y; ++i)
X	  for (j = 0; j < x; ++j)
X	    if ((i == 0) || (i == y - 1) || (j == 0) || (j == x - 1))
X	      set_cell(i, j, STEEL);
X	    else
X	      set_cell(i, j, SPACE);
X	/* Redraw empty level */
X	draw_field(False);
X      } else
X	curchar = keyhit;
X    }
X    /* If the mouse moves with the button pressed, or the button is */
X    /* pressed, draw the current block at that position */
X    else if (xev.type == MotionNotify)
X    {
X      if (xev.xmotion.state & Button3Mask)
X	set_cell(xev.xmotion.y >> 5, xev.xmotion.x >> 5, SPACE);
X      else if (xev.xmotion.state & Button1Mask)
X	set_cell(xev.xmotion.y >> 5, xev.xmotion.x >> 5, curchar);
X    } else if (xev.type == ButtonPress)
X    {
X      if (xev.xbutton.button == Button3)
X	set_cell(xev.xbutton.y >> 5, xev.xbutton.x >> 5, SPACE);
X      else
X	set_cell(xev.xbutton.y >> 5, xev.xbutton.x >> 5, curchar);
X    }
X    draw_field(False);
X    XFlush(disp);
X    /* Loop until a control key is pressed */
X  } while (xev.type != KeyPress ||
X	   (keyhit != XK_C && keyhit != XK_c &&
X	    keyhit != XK_W && keyhit != XK_w) ||
X	   !(xev.xkey.state & ControlMask));
X
X  /* Save level to data file */
X  if (keyhit == XK_W || keyhit == XK_w)
X    save_level();
X  xend();
X  exit(0);
X}
END_OF_FILE
  if test 5575 -ne `wc -c <'xbd/xbde.c'`; then
    echo shar: \"'xbd/xbde.c'\" unpacked with wrong size!
  fi
  # end of 'xbd/xbde.c'
fi
echo shar: End of archive.
exit 0

dan
----------------------------------------------------
O'Reilly && Associates   argv@sun.com / argv@ora.com
Opinions expressed reflect those of the author only.