[comp.sources.games] v11i003: xbd - boulder-dash for X11, Part01/02

billr@saab.CNA.TEK.COM (Bill Randle) (07/27/90)

Submitted-by: Jeroen Houttuin <houttuin@ethz.uucp>
Posting-number: Volume 11, Issue 3
Archive-name: xbd/Part01

	[Here's another X11 game. Boulder-dash is the original game
	 on which the popular "wanderer" is based. I haven't
	 played this....    -br]

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 2)."
# Contents:  README MANIFEST Makefile bd.c bd.h bd.l bitmap
#   bitmap/lmonster2.bits bitmap/rmonster2.bits editor.c field.c
#   levels levels/bdlev015 scores.c shared.c
# Wrapped by billr@saab on Thu Jul 26 16:05:55 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(390 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XBoulder-dash is still in an experimental phase.  Mail your
Xbug reports,  interesting new levels, ideas to the author.
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 390 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MANIFEST'\"
else
echo shar: Extracting \"'MANIFEST'\" \(2005 characters\)
sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
X   File Name		Archive #	Description
X-----------------------------------------------------------
X MANIFEST                   1	This shipping list
X Makefile                   1	
X README                     1	
X bd.c                       1	
X bd.h                       1	
X bd.l                       1	
X bitmap                     1	
X bitmap/blob.bits           2	
X bitmap/blob2.bits          2	
X bitmap/boulder.bits        2	
X bitmap/diamond.bits        2	
X bitmap/diamond2.bits       2	
X bitmap/diamond3.bits       2	
X bitmap/eater.bits          2	
X bitmap/eater2.bits         2	
X bitmap/exit3.bits          2	
X bitmap/explosion.bits      2	
X bitmap/gold.bits           2	
X bitmap/grass.bits          2	
X bitmap/grey.bits           2	
X bitmap/lmonster.bits       2	
X bitmap/lmonster2.bits      1	
X bitmap/nucbal.bits         2	
X bitmap/player.bits         2	
X bitmap/player.old          2	
X bitmap/player2.bits        2	
X bitmap/player2.old         2	
X bitmap/rmonster.bits       2	
X bitmap/rmonster2.bits      1	
X bitmap/space.bits          2	
X bitmap/steel.bits          2	
X bitmap/stone.bits          2	
X bitmap/wall.bits           2	
X bitmap/wall2.bits          2	
X default                    2	
X editor.c                   1	
X field.c                    1	
X levels                     1	
X levels/bdlev001            2	
X levels/bdlev002            2	
X levels/bdlev003            2	
X levels/bdlev004            2	
X levels/bdlev005            2	
X levels/bdlev006            2	
X levels/bdlev007            2	
X levels/bdlev008            2	
X levels/bdlev009            2	
X levels/bdlev010            2	
X levels/bdlev011            2	
X levels/bdlev012            2	
X levels/bdlev013            2	
X levels/bdlev014            2	
X levels/bdlev015            1	
X levels/bdlev016            2	
X levels/bdlev017            2	
X levels/bdlev018            2	
X levels/bdlev019            2	
X levels/bdlev020            2	
X scores                     2	
X scores.c                   1	
X shared.c                   1	
END_OF_FILE
if test 2005 -ne `wc -c <'MANIFEST'`; then
    echo shar: \"'MANIFEST'\" unpacked with wrong size!
fi
# end of 'MANIFEST'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(1078 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X#/* you just keep on pushing my luck over the */
X#/*           BOULDER        DASH             */
X
XGAME = bd
XEDITOR = bde
X
XBIN = /usr/games
XLIB = /usr/games/lib/bd
X#BIN = ${HOME}/bd
X#LIB = ${HOME}/bd
X
X# manual pages
XMAN = /usr/man/man6
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	cp levels/* ${LIB}
X	chmod 644 ${LIB}/bdlev*
X	chmod 644 ${LIB}/default
X	chmod 644 ${LIB}/scores
X	cp bd.l ${MAN}/bd.6
X
Xupdate: all
X	cp ${GAME} ${EDITOR} ${BIN}
X	chmod 4755 ${BIN}/${GAME}
X
Xclean:
X	rm -f *.o core ${GAME} ${EDITOR}
X
XSRCS = bd.c shared.c field.c scores.c
XOBJS = bd.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}: editor.o shared.o
X	${CC} ${LDFLAGS} -o ${EDITOR} editor.o shared.o -lX11
X
X.c.o:
X	${CC} ${CFLAGS} -c -DLIB=\"${LIB}\" $<
END_OF_FILE
if test 1078 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'bd.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'bd.c'\"
else
echo shar: Extracting \"'bd.c'\" \(4807 characters\)
sed "s/^X//" >'bd.c' <<'END_OF_FILE'
X/* you just keep on pushing my luck over the */
X/*           BOULDER        DASH             */
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 "bd.h"
X 
Xvoid init_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 adapt_timer()
X{
X  if(speed <= 0)
X    speed = 1;
X  cycletime.it_interval.tv_usec = 3*625000 / speed;
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 handle_key(keyhit)
XKeySym keyhit;     /* Key symbol for key stroke provided by 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    players=1;
X    return;
X  }
X  switch(keyhit) {
X  case XK_question:   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:    case XK_R11:
X    gamestop=!gamestop; break;
X  case XK_Left:   case XK_H:  case XK_h:
X    curorder = LEFT; gamestop=False; break;
X  case XK_Up:     case XK_K:  case XK_k:
X    curorder = UP; gamestop=False; break;
X  case XK_Down:   case XK_J:  case XK_j:
X    curorder = DOWN; gamestop=False; break;
X  case XK_Right:  case XK_L:  case XK_l:
X    curorder = RIGHT; gamestop=False; break;
X  }
X}
X
X/**** Timer  procedures  ****/
X
X/* Function which is called whenever the timer signal goes off */
Xvoid ticker(sig)
Xint 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  curtick ++;
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    XSync(disp,False); /*XFlush(disp); */
X    gamestop=True;
X    scoreobs=True;
X    stoplevel=False;
X  }
X  signal(SIGALRM,ticker);
X}
X/**** End timer procedures ****/
X
Xvoid main(argc,argv)
Xint argc;
Xchar **argv;
X{
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    if(argv[i][0] == '-') {
X      if(argv[i][1] == 'l') {
X        if(argv[i][2] == '\0' && i+1 < argc) {
X          sscanf(argv[i+1],"%d",&levelnum);
X          i++;
X        }
X        else
X          sscanf(argv[i]+2,"%d",&levelnum);
X      }
X      else {
X        printf("usage: bd [-l <level>] \n");
X        exit(1);
X      }
X    }
X  }
X
X  levelstart=levelnum;
X  init_level(levelnum); 
X  xstart(EVMASK);
X  XStoreName(disp,wind,"BOULDER DASH ?");
X  XFlush(disp);  /* initializing flush */
X  make_gcs();
X  draw_field(True);
X  draw_score(); scoreobs=True;
X
X  /* initialize timer structure according to speed */
X  if(speed <= 0)
X    speed = 1;
X  cycletime.it_interval.tv_usec = 3*625000 / speed;
X  cycletime.it_interval.tv_sec = 0;
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      sleep(1);
X      draw_field(True);
X    }
X    else if(xev.type == KeyPress) {
X      keycount = XLookupString(&xev,buf,50,&keyhit,(XComposeStatus *) NULL);
X      if(steal=(xev.xkey.state & ControlMask))
X        switch(keyhit)  {
X        /* ^C, ^U kill the game */
X        case XK_C: case XK_U: case XK_c: case XK_u: case XK_backslash:
X          goto game_over;
X        /* ^D Kill; commit suicide */
X        case XK_D: case XK_d:
X          curorder=KILL;
X        /* ^R redraws the level */
X        case XK_R: case XK_r:
X          draw_field(True);
X          break;
X        default: handle_key(keyhit);break;
X        }
X      else handle_key(keyhit);
X    }
X    if(! gamestop)
X      signal(SIGALRM,ticker);
X  }
X  game_over:
X    XSync(disp,False);
X    xend();
X    add_score();
X}
END_OF_FILE
if test 4807 -ne `wc -c <'bd.c'`; then
    echo shar: \"'bd.c'\" unpacked with wrong size!
fi
# end of 'bd.c'
fi
if test -f 'bd.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'bd.h'\"
else
echo shar: Extracting \"'bd.h'\" \(3405 characters\)
sed "s/^X//" >'bd.h' <<'END_OF_FILE'
X/* you just keep on pushing my luck over the */
X/*           BOULDER        DASH             */
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/space.bits"
X#include "bitmap/grass.bits"
X#include "bitmap/diamond.bits"
X#include "bitmap/diamond2.bits"
X#include "bitmap/diamond3.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/exit3.bits"
X
X#define w 35
X#define h 26
X#define LEVELPREFIX "bdlev"
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 | FocusChangeMask
X
X/* direction masks */
X#define N 0
X#define E 1
X#define S 2
X#define W 3
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'
X#define RMONSTER            'r'
X#define GRASS               'g'
X#define WALL                'w'
X#define MAGICWALL           'W'
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'
X#define BLOB                'B'
X
XFont scorefont;     /* Font used to display score */
XGC whitegc,scoregc,gc,Bgc,Bgc1,Bgc2,ngc,egc,
X   egc1,egc2,Egc1,Wgc,Wgc2,Egc2,Egc3,Egc,
X   lgc,lgc1,lgc2,rgc,rgc1,rgc2,xgc,Sgc,bgc
X   ,dgc,dgc1,dgc2,dgc3,wgc,pgc,pgc1,pgc2,sgc,ggc;
Xchar filename[300];     /* Current file name of this level */
Xint i, j, ii, jj, jjj;
Xint blobbreak;
Xint critical;
Xint curtick;            /* Current clock tick number */
Xint blobcells;
Xint x,y,xin,yin,players,lives,levelnum,levelstart,
X    speed,diareq,diapoints,extradiapoints;
XBool steal;    /* steal instead of go */
XBool stoplevel, blobcollapse;
Xenum directs {
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, 5 is 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 3405 -ne `wc -c <'bd.h'`; then
    echo shar: \"'bd.h'\" unpacked with wrong size!
fi
# end of 'bd.h'
fi
if test -f 'bd.l' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'bd.l'\"
else
echo shar: Extracting \"'bd.l'\" \(3204 characters\)
sed "s/^X//" >'bd.l' <<'END_OF_FILE'
X.TH Boulder-dash l "April 1 1990"
X.UC 4
X.SH NAME
XBoulder-dash - Collect diamonds, kill monsters, close in blob etc. etc.
X.SH SYNOPSIS
X.B bd
X[
X.B \-l
X.I level
X]
X.br
X.B bde
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 bd
Xis a game designed for X windows (originally a similar game with the same name
Xran on CBM64).
X.I dbe
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 the level when creating a new
Xlevel.
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 bde
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.br
Xheight width speed 
X.I dp
X.I extra-dp
Xblob-brake
X.br
XWhere 'blob-brake' indicates how strongly blob propagation is slowed down.
XBlocks are painted by pressing the left mouse button.
XSpaces are painted by pressing the right mouse button.
XA new block type is selected by one of the following
Xkeys:
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
Xw \- draw wall
X.br
Xx \- draw explosion
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
XPressing control W inside the editor window will stop editing
Xand save the level.  Pressing control C quits without saving.
XPressing control E will erase the contents of the
Xeditor.
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'.
X.SH FILES
Xbd - Boulder-dash executable
X.br
Xbde - Boulder-dash editor executable
X.br
Xscores - high score list
X.br
Xdefault - default level
X.br
Xbdlev### - levels
X.SH BUGS
XTimer routines don't run properly on some machines.
END_OF_FILE
if test 3204 -ne `wc -c <'bd.l'`; then
    echo shar: \"'bd.l'\" unpacked with wrong size!
fi
# end of 'bd.l'
fi
if test ! -d 'bitmap' ; then
    echo shar: Creating directory \"'bitmap'\"
    mkdir 'bitmap'
fi
if test -f 'bitmap/lmonster2.bits' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'bitmap/lmonster2.bits'\"
else
echo shar: Extracting \"'bitmap/lmonster2.bits'\" \(944 characters\)
sed "s/^X//" >'bitmap/lmonster2.bits' <<'END_OF_FILE'
X#define lmonster2_width 32
X#define lmonster2_height 32
X#define lmonster2_x_hot -1
X#define lmonster2_y_hot -1
Xstatic char lmonster2_bits[] = {
X   0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f,
X   0x06, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x60, 0xe6, 0xff, 0xff, 0x67,
X   0xe6, 0xff, 0xff, 0x67, 0x66, 0x00, 0x00, 0x66, 0x66, 0x00, 0x00, 0x66,
X   0x66, 0xfe, 0x7f, 0x66, 0x66, 0xfe, 0x7f, 0x66, 0x66, 0xfe, 0x7f, 0x66,
X   0x66, 0x0e, 0x70, 0x66, 0x66, 0x0e, 0x70, 0x66, 0x66, 0xce, 0x73, 0x66,
X   0x66, 0x4e, 0x72, 0x66, 0x66, 0x4e, 0x72, 0x66, 0x66, 0xce, 0x73, 0x66,
X   0x66, 0x0e, 0x70, 0x66, 0x66, 0x0e, 0x70, 0x66, 0x66, 0xfe, 0x7f, 0x66,
X   0x66, 0xfe, 0x7f, 0x66, 0x66, 0xfe, 0x7f, 0x66, 0x66, 0x00, 0x00, 0x66,
X   0x66, 0x00, 0x00, 0x66, 0xe6, 0xff, 0xff, 0x67, 0xe6, 0xff, 0xff, 0x67,
X   0x06, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x60, 0xfe, 0xff, 0xff, 0x7f,
X   0xfe, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00};
END_OF_FILE
if test 944 -ne `wc -c <'bitmap/lmonster2.bits'`; then
    echo shar: \"'bitmap/lmonster2.bits'\" unpacked with wrong size!
fi
# end of 'bitmap/lmonster2.bits'
fi
if test -f 'bitmap/rmonster2.bits' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'bitmap/rmonster2.bits'\"
else
echo shar: Extracting \"'bitmap/rmonster2.bits'\" \(944 characters\)
sed "s/^X//" >'bitmap/rmonster2.bits' <<'END_OF_FILE'
X#define rmonster2_width 32
X#define rmonster2_height 32
X#define rmonster2_x_hot -1
X#define rmonster2_y_hot -1
Xstatic char rmonster2_bits[] = {
X   0xff, 0xff, 0xff, 0xff, 0xf1, 0xff, 0xff, 0x8f, 0xe1, 0xff, 0xff, 0x87,
X   0xc1, 0xff, 0xff, 0x83, 0x81, 0xff, 0xff, 0x81, 0x01, 0xff, 0xff, 0x80,
X   0x09, 0xfe, 0x7f, 0x90, 0x19, 0xfc, 0x3f, 0x98, 0x39, 0xf8, 0x1f, 0x9c,
X   0x79, 0xf0, 0x0f, 0x9e, 0xf9, 0xe0, 0x07, 0x9f, 0xd9, 0xc1, 0x83, 0x9b,
X   0x99, 0x83, 0xc1, 0x99, 0x19, 0x07, 0xe0, 0x98, 0x19, 0x0e, 0x70, 0x98,
X   0xd9, 0x1c, 0x38, 0x9b, 0xd9, 0x1c, 0x38, 0x9b, 0x19, 0x1e, 0x70, 0x98,
X   0x19, 0x07, 0xe0, 0x98, 0x99, 0x83, 0xc1, 0x99, 0xd9, 0xc1, 0x83, 0x9b,
X   0xf9, 0xe0, 0x07, 0x9f, 0x79, 0xf0, 0x0f, 0x9e, 0x39, 0xf8, 0x1f, 0x9c,
X   0x19, 0xfc, 0x3f, 0x98, 0x09, 0xfe, 0x7f, 0x90, 0x01, 0xff, 0xff, 0x80,
X   0x81, 0xff, 0xff, 0x81, 0xc1, 0xff, 0xff, 0x83, 0xe1, 0xff, 0xff, 0x87,
X   0xf1, 0xff, 0xff, 0x8f, 0xff, 0xff, 0xff, 0xff};
END_OF_FILE
if test 944 -ne `wc -c <'bitmap/rmonster2.bits'`; then
    echo shar: \"'bitmap/rmonster2.bits'\" unpacked with wrong size!
fi
# end of 'bitmap/rmonster2.bits'
fi
if test -f 'editor.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'editor.c'\"
else
echo shar: Extracting \"'editor.c'\" \(5345 characters\)
sed "s/^X//" >'editor.c' <<'END_OF_FILE'
X/* you just keep on pushing my luck over the */
X/*           BOULDER        DASH             */
X
X#include <stdio.h>
X#include <X11/Xlib.h>
X#include <X11/keysym.h>
X#include <X11/Xutil.h>
X#include "bd.h"
X
Xchar curchar;
XGC drawgc;
X
Xvoid init_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 save_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    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\n",y,x,
X          speed,diareq,diapoints,extradiapoints,blobbreak);
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    /* 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 main(argc,argv)
Xint argc;
Xchar **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    if(argv[i][0] == '-') {
X      /* -w sets the level width */
X      if(argv[i][1] == 'w') {
X        if(argv[i][2] == '\0' && i+1 < argc) {
X          sscanf(argv[i+1],"%d",&xin);
X          i++;
X        }
X        else
X          sscanf(argv[i]+2,"%d",&xin);
X      }
X      /* -h sets the level height */
X      else if(argv[i][1] == 'h') {
X        if(argv[i][2] == '\0' && i+1 < argc) {
X          sscanf(argv[i+1],"%d",&yin);
X          i++;
X        }
X        else
X          sscanf(argv[i]+2,"%d",&yin);
X      }
X      /* -l sets the level number */
X      else if(argv[i][1] == 'l') {
X        if(argv[i][2] == '\0' && i+1 < argc) {
X          sscanf(argv[i+1],"%d",&levelnum);
X          i++;
X        }
X        else
X          sscanf(argv[i]+2,"%d",&levelnum);
X      }
X      else {
X        printf("usage: editor [-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    printf("usage: editor [-h <height>] [-w <width>] -l <level> \n");
X    exit(1);
X  }
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=Egc3;
X  Wgc=Wgc2;
X  drawgc=pgc;
X  draw_field(True);
X
X  /* Main event loop */
X  do {
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      draw_field(True);
X    }
X    else if(xev.type == KeyPress) {
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        puts("Type ^W to finish editing and save the level.");
X        puts("Type ^C to quit editing.");
X        puts("Type ^E to 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 || keyhit == XK_e) &&
X              (xev.xkey.state & ControlMask)) {
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 set_cell(i,j,SPACE);
X        /* Redraw empty level */
X        draw_field(False);
X      }
X      else 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      if(xev.xmotion.state & Button3Mask)
X        set_cell(xev.xmotion.y >> 5,xev.xmotion.x >> 5,SPACE);
X      else
X        set_cell(xev.xmotion.y >> 5,xev.xmotion.x >> 5,curchar);
X    }
X    else if(xev.type == ButtonPress) {
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  /* Flush the graphics commands out to the server */
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 5345 -ne `wc -c <'editor.c'`; then
    echo shar: \"'editor.c'\" unpacked with wrong size!
fi
# end of 'editor.c'
fi
if test -f 'field.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'field.c'\"
else
echo shar: Extracting \"'field.c'\" \(13237 characters\)
sed "s/^X//" >'field.c' <<'END_OF_FILE'
X/* you just keep on pushing my luck over the */
X/*           BOULDER        DASH             */
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 "bd.h"
X
Xvoid blink(i,j)
Xint i,j;
X{
X  field[i][j].changed=True;
X}
X
Xvoid move_cell(i,j,ii,jj)
Xint 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 explode(a,b,stage)
Xint 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 move_nucbal(i,j,t)
Xint 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: jj=(t==1)?(j+x-1)%x:(j+1)%x;break;
X      case W: default:  jj=(t==2)?(j+x-1)%x:(j+1)%x;break;
X    }
X  switch (field[ii][jj].content)
X  {
X    case SPACE:
X      move_cell(i,j,ii,jj);
X      break;
X    case NUCBAL:
X      explode(i,j,DIAEXPLO);
X      explode(ii,jj,DIAEXPLO);
X      break;
X    default:
X      if (field[i][j].dir==N) field[i][j].dir=E;
X      else field[i][j].dir=((field[i][j].dir+2)%4); /*turn around*/
X      break;
X  }
X}
X
XBool move_monster(content,direction)
Xchar content, direction;
X{
X  switch (direction)
X  {
X    case N: ii=(i+y-1)%y; jj=j; break;
X    case E: jj=(j+1)%x; ii=i; break;
X    case S: ii=(i+1)%y;jj=j; break;
X    default:jj=(j+x-1)%x; ii=i; 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);field[ii][jj].dir=direction;return(True);
X      }
X      else return(False);
X      break;
X    case BOULDER: case DIAMOND:
X      if ((direction==N) && (field[ii][jj].speed!=0))
X        if (content==RMONSTER)  {explode(i,j,DIAEXPLO);return(True);}
X        else if (content==LMONSTER)  {explode(i,j,SPACEEXPLO);return(True);}
X      break;
X    default: return(False); break;
X  }
X}
X
XBool search_destroy(content)
Xchar content;
X{
X  ii=(i+y-1)%y; 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) {lives--;scoreobs=True;}
X    if (content==RMONSTER) explode(i,jj,DIAEXPLO);else explode(i,jj,SPACEEXPLO);
X    return(True);
X  }
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) {lives--;scoreobs=True;}
X    if (content==RMONSTER) explode(ii,j,DIAEXPLO);else explode(ii,j,SPACEEXPLO);
X    return(True);
X  }
X  else
X  {
X    ii=(i+1)%y; 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) {lives--;scoreobs=True;}
X        if (content==RMONSTER) explode(i,jj,DIAEXPLO);
X          else explode(i,jj,SPACEEXPLO);
X        return(True);
X      }
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) {lives--;scoreobs=True;}
X        if (content==RMONSTER) explode(ii,j,DIAEXPLO);
X          else explode(ii,j,SPACEEXPLO);
X        return(True);
X      }
X  }
X}
X
Xvoid propagate(i,j,dias)
Xint i,j;
XBool 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 right,up,left,down*/
X    jt=(t==2)?(j+x-1)%x:(t==0)?(j+1)%x:j;/*neigbour 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: 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 caught(i,j)
Xint i,j;
X{
X  Bool Free; 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 right,up,left,down*/
X    jt=(t==2)?(j+x-1)%x:(t==0)?(j+1)%x:j;/*neigbour right,up,left,down*/
X
X    switch(field[it][jt].content)
X    {
X      case SPACE: case GRASS: case RMONSTER: case LMONSTER: 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 calculate_field()
X{
X  players=0;
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))
X     {
X      ii=i;jj=j;
X      switch(field[i][j].content)
X      {
X        case PLAYER    :
X          blink(i,j);
X          players++;
X          switch (curorder) /* find cell player wants to go to */
X          {
X            case STAND: break;
X            case UP :ii=(i+y-1)%y;break;
X            case DOWN: ii=(i+1)%y;break;
X            case LEFT: jj=(j+x-1)%x;break;
X            case RIGHT: jj=(j+1)%x;break;
X          }
X          if (!(curorder==STAND))
X          {
X            if (curorder==KILL) 
X            {
X              set_cell(i,j,EXPLOSION);lives--;scoreobs=True;break;
X            }
X            switch(field[ii][jj].content) /*check cell player wants to go to */
X            {
X              case SPACE: case GRASS: case DIAMOND:
X                if (field[ii][jj].content==DIAMOND)
X                {
X                  score+=diapoints;
X                  if (diareq) 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 boulder */
X                if (field[i][jjj].content==SPACE && ((rand()%2)==0))
X                  {
X                    move_cell(i,jj,i,jjj);
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 set_cell(ii,jj,SPACE);
X                  levelnum++;
X                  lives++;
X                  gamestop=True;
X                  stoplevel=True;
X                }
X                break;
X            }
X          }
X          break;
X        case DIAMOND: blink(i,j);
X        case BOULDER:
X          ii=(ii+1)%y;
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: 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 WALL: case BOULDER: case DIAMOND: 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                }
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                      }
X                      else field[i][j].speed=0;
X                  }
X              break;
X            default:
X              field[i][j].speed=0;
X              break;
X            }
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 BLOB: case LMONSTER: case RMONSTER: 
X                case PLAYER: case NUCBAL: case DIAMOND:
X                  if (field[ii][jj].content==PLAYER){lives--;scoreobs=True;}
X                  move_cell(i,j,ii,jj);
X                  break;
X                default:
X                  break;
X              }
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: case BLOB: case SPACE: case GRASS: case DIAMOND:
X              case RMONSTER: case PLAYER: case NUCBAL:
X                if (field[ii][jj].content==PLAYER){lives--;scoreobs=True;}
X                move_cell(i,j,ii,jj); 
X                break; 
X              case BOULDER:
X                jjj=(2*jj-j+x)%x; /* the cell behind the boulder */
X                if (field[i][jjj].content==SPACE && ((rand()%2)==0))
X                  {
X                    move_cell(i,jj,i,jjj);
X                    move_cell(i,j,i,jj);
X                  }
X                else 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)) 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)) 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%10)) /* this is the initiating explosion */
X          {
X            jjj++; /* use jjj for setting new stage */
X            ii=(i+1)%y;jj=(j+1)%x;
X            explode(i,j,jjj);explode(i,jj,jjj);
X            explode(ii,j,jjj);explode(ii,jj,jjj);
X            ii=(i+y-1)%y;
X            explode(ii,j,jjj);explode(ii,jj,jjj);
X            jj=(j+x-1)%x;
X            explode(ii,jj,jjj);explode(i,jj,jjj);
X            ii=(i+1)%y;
X            explode(ii,jj,jjj);
X          }
X          else
X          {
X            if (jjj%10 < 8)
X              field[i][j].stage++;
X            else if (jjj>DIAEXPLO)
X                 {
X                   set_cell(i,j,DIAMOND);
X                 }
X                 else if (jjj>BOULDEXPLO)
X                      {
X                        set_cell(i,j,BOULDER);
X                      }
X                      else if (jjj>SPACEEXPLO)
X                           {
X                             set_cell(i,j,SPACE);
X                           }
X                           else 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 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) set_cell(i,jj,MAGICWALL);
X          jj=(j+1)%x;
X          if (field[i][jj].content==SPACE) set_cell(i,jj,MAGICWALL);
X          break;
X        default: break;
X      }
X     }
X    }
X  }
X  curorder=STAND;  /* reset orders */
X  blobcells=0;
X  pgc=(pgc==pgc1)?((rand()%22)==0)?pgc2:pgc1: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 (diareq==0)
X  {
X    Egc=Egc2;
X    diapoints=extradiapoints;
X    scoreobs=True;
X  }
X}
X
END_OF_FILE
if test 13237 -ne `wc -c <'field.c'`; then
    echo shar: \"'field.c'\" unpacked with wrong size!
fi
# end of 'field.c'
fi
if test ! -d 'levels' ; then
    echo shar: Creating directory \"'levels'\"
    mkdir 'levels'
fi
if test -f 'levels/bdlev015' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'levels/bdlev015'\"
else
echo shar: Extracting \"'levels/bdlev015'\" \(91 characters\)
sed "s/^X//" >'levels/bdlev015' <<'END_OF_FILE'
X14 4 15 17 10 30 200
X  bd
Xwddw
X wb 
Xb dw
Xdwb 
Xd wd
Xwb b
XEwbd
X  dw
Xbdb 
Xbwdw
Xd d 
Xbdwd
Xwdpd
END_OF_FILE
if test 91 -ne `wc -c <'levels/bdlev015'`; then
    echo shar: \"'levels/bdlev015'\" unpacked with wrong size!
fi
# end of 'levels/bdlev015'
fi
if test -f 'scores.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'scores.c'\"
else
echo shar: Extracting \"'scores.c'\" \(3204 characters\)
sed "s/^X//" >'scores.c' <<'END_OF_FILE'
X/* you just keep on pushing my luck over the */
X/*           BOULDER        DASH             */
X
X#include <stdio.h>
X#include <X11/Xlib.h>
X#include <X11/keysym.h>
X#include "bd.h"
X
Xchar *getenv(),*sprintf();
X
X#define NUMHIGH 20  /* Number of high scores that will be remembered */
X
X/* Add a high score to the high score list */
Xvoid add_score()
X{
X  /* Structure containing top game results */
X  struct {
X    int score;      /* Final score */
X    int slev,elev;  /* Starting and ending level */
X    int uid;        /* Player account uid */
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    /* Extract score information from line */
X    while(fgets(buf,200,sfile) && numscore < NUMHIGH) {
X      sscanf(buf,"%d %d %d %d %[^\n]",&(next.score),&(next.slev),&(next.elev),
X         &(next.uid),next.desc);
X      tops[numscore] = next;
X      numscore ++;
X    }
X    fclose(sfile);
X  }
X
X  /* Contruct the structure containing the score for this game */
X  next.score = score;
X  next.slev = levelstart;
X  next.elev = levelnum;
X  next.uid = getuid();
X  sprintf(next.desc,"%s ",getenv("USER"));
X  cur = -1;
X  /* Insert new score in old high score list */
X  if(numscore < NUMHIGH || tops[NUMHIGH - 1].score < next.score) {
X    /* Iterate through high score list */
X    for(i = (numscore >= NUMHIGH ? NUMHIGH-2 : numscore-1);i >= 0;i--) {
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
X  /* Increment and print the number of games played */
X  /* Print out new high score list */
X  for(i=0;i<numscore;++i) {
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    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
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    perror(buf);
X    return;
X  }
X  for(i=0;i<numscore;++i)
X    fprintf(sfile,"%d %d %d %d %s\n",tops[i].score,tops[i].slev,
X         tops[i].elev,tops[i].uid,tops[i].desc);
X  fclose(sfile);
X}
END_OF_FILE
if test 3204 -ne `wc -c <'scores.c'`; then
    echo shar: \"'scores.c'\" unpacked with wrong size!
fi
# end of 'scores.c'
fi
if test -f 'shared.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'shared.c'\"
else
echo shar: Extracting \"'shared.c'\" \(8595 characters\)
sed "s/^X//" >'shared.c' <<'END_OF_FILE'
X/* you just keep on pushing my luck over the */
X/*           BOULDER        DASH             */
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 "bd.h"
X
X/* Manufaction a 32x32 graphics cursor used in a XFill... operation. */
XGC makegc(func,bits)
Xint func;       /* Drawing function such as GXcopy or GXor. */
Xchar bits[];    /* Bits describing fill pattern.  Produced in 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 make_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  dgc3=makegc(GXcopy,diamond3_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(GXequiv,steel_bits);
X  Egc3=makegc(GXcopy,exit3_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}
X
Xvoid init_level(levelnum)
Xint levelnum;
X{
X
X  FILE *levelfile;
X  char buf[300];
X
X  Egc=Egc1; /* don't blink EXIT */
X  blobcollapse=False;
X  blobcells=0;
X
X  /* Manufaction the file name by starting with the world name and */
X  /* appending the level number to it. */
X/*  strcpy(filename,"/usr/kos/houttuin/bd"); */
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    /* Build the default level name */
X    strcpy(buf,".");
X    strcat(buf,"/default");
X    /* Open default level file for reading */
X    levelfile = fopen(buf,"r");
X    if(levelfile == NULL) {
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 = w;
X    y = h;
X  }
X  else {
X    /* Extract the level parameters */
X    sscanf(buf,"%d %d %d %d %d %d %d", &y, &x, &speed, &diareq, &diapoints, 
X           &extradiapoints, &blobbreak);
X  }
X
X  if (xin && yin) {x=xin; y=yin;} /* read in from editor command line */
X
X  /* are sizes acceptable ?  */
X
X  if(x>w) x=w;if(y>h) y=h;if(x<2) x=2;if(y<1) y=1;
X
X  /* Iterate through each horizontal line */
X  for(i=0;i<y;++i) {
X    /* Load the next line from the file */
X    if(fgets(buf,300,levelfile) != NULL) {
X      /* Go through each horizontal position and copy the data into */
X      /* the level array. */
X      for(j=0;j<x;++j) {
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    }
X    else
X      j = 0;
X    /* Fill in rest of premature lines with steel */
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 draw_score()
X{
X  char buf[50];
X
X  /* Build the output string */
X  sprintf(buf,"sc:%d lv:%d sp:%d ls:%d ds:%d dp:%d",score,levelnum,
X          speed,lives,diareq,diapoints);
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 xstart(evmask)
Xlong evmask;    /* Event mask which will be used in XSelectInput */
X{
X  XGCValues xgcv;
X
X  /* create X window */
X  disp=XOpenDisplay(NULL);
X  /* Check to see if the open display succeeded */
X  if(disp == NULL) {
X    fprintf(stderr,"Display open failed.  Check DISPLAY environment variable.\n"
X            );
X    exit(-1);
X  }
X
X  wind=XCreateSimpleWindow(disp,DefaultRootWindow(disp),0,1,
X                           x<<5,(y<<5)+SCORESIZE,
X                           WhitePixel(disp,0),BlackPixel(disp,0));
X  /* Check to see if the open window succeeded */
X  if(wind == 0) {
X    fprintf(stderr,"Window open failed.\n");
X    XCloseDisplay(disp);
X    exit(-1);
X  }
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
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 xend()
X{
X  gamestop=True; /* tricky; prevent ticker function from using Xlib fcts */
X  XUnloadFont(disp,scorefont);
X  XUnmapWindow(disp,wind);
X  XDestroyWindow(disp,wind);
X  XCloseDisplay(disp);
X}
X
Xvoid draw_field(redrawall)
Xshort 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     :XFillRectangle(disp,wind,ggc,j<<5,i<<5,32,32);break;
X          case SPACE     :XFillRectangle(disp,wind,sgc,j<<5,i<<5,32,32);break;
X          case PLAYER    :XFillRectangle(disp,wind,pgc,j<<5,i<<5,32,32);break;
X          case WALL      :XFillRectangle(disp,wind,wgc,j<<5,i<<5,32,32);break;
X          case MAGICWALL :XFillRectangle(disp,wind,Wgc,j<<5,i<<5,32,32);break;
X          case DIAMOND   :XFillRectangle(disp,wind,dgc,j<<5,i<<5,32,32);break;
X          case BOULDER   :XFillRectangle(disp,wind,bgc,j<<5,i<<5,32,32);break;
X          case EXPLOSION :XFillRectangle(disp,wind,xgc,j<<5,i<<5,32,32);break;
X          case LMONSTER  :XFillRectangle(disp,wind,lgc,j<<5,i<<5,32,32);break;
X          case RMONSTER  :XFillRectangle(disp,wind,rgc,j<<5,i<<5,32,32);break;
X          case NUCBAL    :XFillRectangle(disp,wind,ngc,j<<5,i<<5,32,32);break;
X          case BLOB      :XFillRectangle(disp,wind,Bgc,j<<5,i<<5,32,32);break;
X          case EATER     :XFillRectangle(disp,wind,egc,j<<5,i<<5,32,32);break;
X          case EXIT      :XFillRectangle(disp,wind,Egc,j<<5,i<<5,32,32);break;
X          case STEEL: 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) draw_score();
X}
X
Xvoid set_cell(i,j,content)
Xint i,j;
Xchar 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 8595 -ne `wc -c <'shared.c'`; then
    echo shar: \"'shared.c'\" unpacked with wrong size!
fi
# end of 'shared.c'
fi
echo shar: End of archive 1 \(of 2\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked both 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