[comp.sources.x] v05i047: golddig2 -- A game for X11, Part03/04

kent@ssbell.uu.net (Kent Landfield) (12/14/89)

Submitted-by: Alexander Siegel <siegel@cs.cornell.edu>
Posting-number: Volume 5, Issue 47
Archive-name: golddig2/part03

#! /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 3 (of 4)."
# Contents:  golddig2/badguy.c golddig2/movement.c golddig2/shared.c
# Wrapped by kent@ssbell on Wed Dec 13 20:36:59 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'golddig2/badguy.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'golddig2/badguy.c'\"
else
echo shar: Extracting \"'golddig2/badguy.c'\" \(16560 characters\)
sed "s/^X//" >'golddig2/badguy.c' <<'END_OF_FILE'
X/* This program was written by Alexander Siegel in September of 1989   */
X/* at Cornell University.  It may may copied freely for private use or */
X/* public dispersion provided that this comment is not removed.  This  */
X/* program, any portion of this program, or any derivative of this     */
X/* program may not be sold or traded for financial gain.               */
X
X#include <stdio.h>
X#include <X11/Xlib.h>
X#include <X11/keysym.h>
X#include "golddig.h"
X
Xextern char badguy_bits[];
X#include "bitmap/badguy2.bits"
X#include "bitmap/badguy3.bits"
X
Xlong random();
X
X#define MAXBADGUY 30     /* Maximum number of bad guys */
X#define MAXBADSCORE 20   /* Maximum amount of score given for */
X                         /* killing bad guys */
Xint numbadguy = 0;       /* Total number of bad guys. */
Xstruct thing_s badguys[MAXBADGUY];  /* Array describing state of all */
X                                    /* bad guys */
Xchar movetree[MAXLEVEL]; /* Direction that badguy should go at each location */
Xint badscore;            /* Score given during current level due to */
X                         /* killing bad guys */
X
X/* Graphics cursors for drawing the possible states of the badguys */
XGC badguy1gc,badguy2gc,badguy3gc;
X
X/* Initialize graphics cursors for bad guys */
Xvoid init_badguy()
X{
X  int gcfunc;
X
X  /* Decide whether to use GXand or GXor depending on screen type */
X  if((BlackPixel(disp,0) & WhitePixel(disp,0)) == BlackPixel(disp,0))
X    gcfunc = GXand;
X  else
X    gcfunc = GXor;
X  /* Generate graphics cursors for drawing bad guy */
X  badguy1gc = makegc(gcfunc,badguy_bits);
X  badguy2gc = makegc(gcfunc,badguy2_bits);
X  badguy3gc = makegc(gcfunc,badguy3_bits);
X}
X
X/* Initialize data structure for bad guys from level data */
Xvoid start_badguy()
X{
X  register int x,y,pos;
X
X  /* Reset the limit on bad guy score given */
X  badscore = 0;
X  /* Initialize number of bad guys to 0 */
X  numbadguy = 0;
X  pos = 0;
X  /* Iterate through each position in level array */
X  for(x=0;x<xsize;++x)
X    for(y=0;y<ysize;++y) {
X      /* Check if level holds a bad guys block at that position */
X      if(level[pos] == BADGUY) {
X        /* Replace bad guys block with space */
X        level[pos] = SPACE;
X        if(numbadguy < MAXBADGUY) {
X          /* Add bad guy to global array.  Note the multiplication by */
X          /* 2 when producing position. */
X          badguys[numbadguy].xstart = badguys[numbadguy].xpos = x << 1;
X          badguys[numbadguy].ystart = badguys[numbadguy].ypos = y << 1;
X          badguys[numbadguy].dir = STAND;
X          /* Bad guys start holding nothing */
X          badguys[numbadguy].hold = SPACE;
X          numbadguy ++;
X        }
X      }
X      pos ++;
X    }
X}
X
X/* Draw all the bad guys out to the game window */
Xvoid draw_badguys()
X{
X  register int i;
X  GC drawgc;
X
X  /* Iterate through each bad guy */
X  for(i=0;i<numbadguy;++i) {
X    /* If bad guy is horizontally offset, use the second graphics */
X    /* cursor */
X    if(badguys[i].xpos & 1)
X      drawgc = badguy2gc;
X    /* If bad guy is vertically offset, use the third graphics cursor */
X    else if(badguys[i].ypos & 1)
X      drawgc = badguy3gc;
X    /* Otherwise use the normal graphics cursor */
X    else
X      drawgc = badguy1gc;
X    /* Fill rectangle surrounding bad guy */
X    XFillRectangle(disp,wind,drawgc,badguys[i].xpos << 3,
X                   badguys[i].ypos << 3,16,16);
X  }
X}
X
X/* Return 1 if the specified position overlaps a bad guy, 0 otherwise. */
X/* Another parameter is provided so that this routine can ignore one */
X/* bad guy. */
Xint overlap_badguy(x,y,num)
Xregister int x,y;   /* Position which will be checked for overlap. */
Xregister int num;   /* Number of bad guy to ignore.  Use a -1 for no */
X                    /* ignoring. */
X{
X  register int i,d;
X
X  /* Iterate through each bad guy */
X  for(i=0;i<numbadguy;++i) {
X    /* If this bad guy is the one that I am supposed to ignore, */
X    /* continue to the next */
X    if(i == num)
X      continue;
X    /* Compute horizontal distance between position and bad guy and */
X    /* check it.  Things are two positions wide in each direction */
X    d = x - badguys[i].xpos;
X    if(d < -1 || d > 1)
X      continue;
X    /* Check vertical distance */
X    d = y - badguys[i].ypos;
X    if(d < -1 || d > 1)
X      continue;
X    /* Found overlap, return a 1 */
X    return(1);
X  }
X  /* Could not find overlap */
X  return(0);
X}
X
X/* Erase and redraw all badguys who have moved in the previous */
X/* movement.  Movement is detected when (xpos,ypos) is different from */
X/* (xold,yold). */
Xvoid drawmove_badguys()
X{
X  register int x,y,i;
X  GC drawgc;
X
X  /* iterate through each bad guy */
X  for(i=0;i<numbadguy;++i) {
X    /* do not erase bad guys who did not move */
X    if(! badguys[i].redraw)
X      continue;
X    /* get position of bad guy in normal coordinates */
X    x = badguys[i].xold >> 1;
X    y = badguys[i].yold >> 1;
X    /* draw block underneath bad guy */
X    draw_block(x,y);
X    /* if horizontally offset, draw block to the right */
X    if(badguys[i].xold & 1)
X      draw_block(x + 1,y);
X    /* if vertically offset, draw block below */
X    if(badguys[i].yold & 1)
X      draw_block(x,y + 1);
X  }
X
X  /* iterate through each bad guy */
X  for(i=0;i<numbadguy;++i) {
X    /* do not draw bad guys who did not move */
X    if(! badguys[i].redraw)
X      continue;
X    /* Put badguy coordinates in registers */
X    x = badguys[i].xpos;
X    y = badguys[i].ypos;
X    /* if bad guy is horizontally offset, use the second graphics */
X    /* cursor */
X    if(x & 1)
X      drawgc = badguy2gc;
X    /* If bad guy is vertically offset, use the third graphics cursor */
X    else if(y & 1)
X      drawgc = badguy3gc;
X    /* Otherwise use the normal graphics cursor */
X    else
X      drawgc = badguy1gc;
X    /* Fill rectangle surrounding bad guy */
X    XFillRectangle(disp,wind,drawgc,x << 3,y << 3,16,16);
X  }
X}
X
X/* Maximum size for FIFO queue used by breadth first search algorithm */
X#define QSIZE 1000
X
X/* Regenerate the movement tree used by bad guys when determining */
X/* movement.  The basic algorithm is a breadth first search of the */
X/* graph produced by interpreting the moveallow array as a directed */
X/* graph.  The root of the tree is the player position.  The result of */
X/* this algorithm is that the shortest path from each position to the */
X/* player is described by the directions in the movement tree. */
Xvoid regen_tree()
X{
X  register int head,tail,lpos,dist;
X  /* This array is used for the queue of graph nodes.  The head and */
X  /* tail variables describe the head and tail of the queue in the */
X  /* array. */
X  struct goals_s {
X    short x,y,dir;
X  } goals[QSIZE];
X
X  /* Do a fast pre-initialization of the movement tree */
X  dist = xsize * ysize;
X  for(lpos=0;lpos<dist;++lpos) {
X    /* Zero out each position.  A 0 in a position signifies that the */
X    /* direction of movement for that position is unknown. */
X    movetree[lpos] = 0;
X    /* If can only move in one direction, set movetree value */
X    /* immediately.  Do not set it if is a force into a STOPBAD space */
X    /* to allow bad guys to try to run over holes.  This loop screws up the */
X    /* search algorithm and the result is that bad guys will not jump */
X    /* off of things.  It makes the search run much faster, and the */
X    /* bad guys were too smart otherwise. */
X    if((moveallow[lpos] & FORCEDOWN) &&
X       ! (fast_lookup[level[lpos + 1]].code & STOPBAD))
X      movetree[lpos] = MOVEDOWN;
X    if((moveallow[lpos] & FORCEUP) &&
X       ! (fast_lookup[level[lpos - 1]].code & STOPBAD))
X      movetree[lpos] = MOVEUP;
X    if((moveallow[lpos] & FORCERIGHT) &&
X       ! (fast_lookup[level[lpos + ysize]].code & STOPBAD))
X      movetree[lpos] = MOVERIGHT;
X    if((moveallow[lpos] & FORCELEFT) &&
X       ! (fast_lookup[level[lpos - ysize]].code & STOPBAD))
X      movetree[lpos] = MOVELEFT;
X    /* If no movement is possible, set a -1 in the movement tree. */
X    if(moveallow[lpos] == 0)
X      movetree[lpos] = -1;
X  }
X  /* Initialize the head and tail of the FIFO queue. */
X  head = 0;
X  tail = 1;
X  /* Set the first goal node to be the player */
X  goals[0].x = player.xpos >> 1;
X  goals[0].y = player.ypos >> 1;
X  goals[0].dir = -1;    /* Make sure every direction is possible */
X  /* While there are still goal nodes, continue */
X  while(head != tail) {
X    /* Compute position of position of goal */
X    lpos = goals[head].x * ysize + goals[head].y;
X    /* If the suggested movement direction is valid and the movement */
X    /* has for that position has not been set, set it. */
X    if(movetree[lpos] == 0 && (moveallow[lpos] & goals[head].dir) != 0) {
X      movetree[lpos] = goals[head].dir;
X      /* Suggest that the block to the left has to rightward pointer */
X      if(goals[head].x > 0 && movetree[lpos - ysize] == 0)
X
X/* Add a suggested movement direction to the FIFO queue */
X#define ADDGOAL(dx,dy,ndir)  { goals[tail].x = goals[head].x + dx; \
X                             goals[tail].y = goals[head].y + dy; \
X                             goals[tail++].dir = ndir; \
X                             if(tail == QSIZE) tail = 0; }
X
X        ADDGOAL(-1,0,MOVERIGHT)
X      /* Suggest that the block to the right has a leftware pointer */
X      if(goals[head].x < xsize - 1 && movetree[lpos + ysize] == 0)
X        ADDGOAL(1,0,MOVELEFT)
X      /* Suggest that the block above has a downward pointer */
X      if(goals[head].y > 0 && movetree[lpos - 1] == 0)
X        ADDGOAL(0,-1,MOVEDOWN)
X      /* Suggest that the block below has an upward pointer */
X      if(goals[head].y < ysize - 1 && movetree[lpos + 1] == 0)
X        ADDGOAL(0,1,MOVEUP)
X    }
X    /* Remove current goal node from head of queue */
X    head ++;
X    if(head == QSIZE)
X      head = 0;
X  }
X}
X
X/* Move all the bad guys one position */
Xvoid move_badguys()
X{
X  int i,x,y,allow;
X  register int lpos;
X  enum directs dir;
X  register char curchar,below;
X
X  /* Iterate through all the bad guys */
X  for(i=0;i<numbadguy;++i) {
X    /* Get old position for bad guys */
X    x = badguys[i].xold = badguys[i].xpos;
X    y = badguys[i].yold = badguys[i].ypos;
X    /* Initially assume that the badguy does not need to be redrawn */
X    badguys[i].redraw = 0;
X    /* Get the character underneath the bad guy */
X    lpos = (x >> 1)*ysize + (y >> 1);
X    curchar = level[lpos];
X    /* Get the character below the bad guy.  If it is off the level, */
X    /* assume it is a stone */
X    if(y < (ysize - 1) << 1)
X      below = level[lpos + 1];
X    else
X      below = STONE;
X
X    /* If the current character is a killer block, move the bad guy to */
X    /* its starting position */
X    if(fast_lookup[curchar].code & KILLIN) {
X      /* Prevent getting too many points from kill bad guys on a */
X      /* single level */
X      if(badscore < MAXBADSCORE) {
X        /* Increment the score */
X        score += 2;
X        badscore += 2;
X      }
X      /* Redraw the score line */
X      draw_score();
X      /* Move the bad guy back to its start */
X      badguys[i].xpos = badguys[i].xstart;
X      badguys[i].ypos = badguys[i].ystart;
X      lpos = (badguys[i].xpos >> 1)*ysize + (badguys[i].ypos >> 1);
X      /* Prevent a bad guy from forming on top of another */
X      while(overlap_badguy(badguys[i].xpos,badguys[i].ypos,i) ||
X            level[lpos] != SPACE) {
X        badguys[i].xpos = random() % xsize;
X        badguys[i].ypos = random() % ysize;
X        lpos = (badguys[i].xpos >> 1)*ysize + (badguys[i].ypos >> 1);
X      }
X      /* Redraw bad guy */
X      badguys[i].redraw = 1;
X      /* Destroy whatever the bad guy was holding */
X      if(badguys[i].hold != SPACE) {
X        if(fast_lookup[badguys[i].hold].code & TREASURE) {
X          goldleft --;
X          /* If that was the last gold piece, escape ladder and other */
X          /* stuff may need to appear. */
X          if(goldleft == 0) {
X            regen_allow();      /* Regenerate the allowable movement array */
X            redrawall();        /* Refresh the entire screen */
X          }
X        }
X        badguys[i].hold = SPACE;
X      }
X      /* Continue to the next bad guy */
X      continue;
X    }
X
X    /* If the bad guy is stuck in a STOPBAD block, do not move him */
X    if((x & 1) == 0 && (y & 1) == 0 &&
X       (fast_lookup[curchar].code & STOPBAD)) {
X      /* Redraw bad guy since underlying block gets redrawn occasionally */
X      badguys[i].redraw = 1;      
X      continue;
X    }
X
X    /* Check if the bad guy is above a hole. */
X    if((x & 1) == 0 && (y & 1) == 0 && fast_lookup[below].code & STOPBAD) {
X      /* If the hole is premature, fill it */
X      if(below >= HOLE1 && below <= HOLE1+2)
X        fill_hole(x >> 1,(y >> 1) + 1);
X    }
X
X    /* Complete previous movement */
X    if((x & 1) != 0 || (y & 1) != 0)
X      dir = badguys[i].dir;
X
X    /* Can only drop things when at a non-offset position and when */
X    /* there is space underneath */
X    else if(curchar == SPACE && badguys[i].hold != SPACE && 
X       /* Drop stuff with a 1 in 20 chance */
X       random() % 20 == 0)
X      dir = PUTDOWN;
X
X    /* Compute next hopeful direction of movement, since badguy is at */
X    /* an even spot */
X    else {
X      /* Get allowable movement direction */
X      allow = moveallow[lpos];
X      /* Prevent bad guy from spontaneously switching direction */
X      if(badguys[i].dir == UP)
X        allow &= ~MOVEDOWN;
X      else if(badguys[i].dir == DOWN)
X        allow &= ~MOVEUP;
X      else if(badguys[i].dir == LEFT)
X        allow &= ~MOVERIGHT;
X      else if(badguys[i].dir == RIGHT)
X        allow &= ~MOVELEFT;
X
X      /* Prevent bad guy from trying to run into somebody else */
X      if((allow & MOVEUP) &&
X         overlap_badguy(badguys[i].xpos,badguys[i].ypos - 2,i))
X        allow &= ~MOVEUP;
X      /* Prevent bad guy from trying to run into somebody else */
X      if((allow & MOVEDOWN) &&
X         overlap_badguy(badguys[i].xpos,badguys[i].ypos + 2,i))
X        allow &= ~MOVEDOWN;
X      /* Prevent bad guy from trying to run into somebody else */
X      if((allow & MOVELEFT) &&
X         overlap_badguy(badguys[i].xpos - 2,badguys[i].ypos,i))
X        allow &= ~MOVELEFT;
X      /* Prevent bad guy from trying to run into somebody else */
X      if((allow & MOVERIGHT) &&
X         overlap_badguy(badguys[i].xpos + 2,badguys[i].ypos,i))
X        allow &= ~MOVERIGHT;
X      
X      /* Try to move according to movement tree */
X      if((allow & MOVEUP) && movetree[lpos] == MOVEUP)
X        dir = UP;
X      else if((allow & MOVEDOWN) && movetree[lpos] == MOVEDOWN)
X        dir = DOWN;
X      else if((allow & MOVELEFT) && movetree[lpos] == MOVELEFT)
X        dir = LEFT;
X      else if((allow & MOVERIGHT) && movetree[lpos] == MOVERIGHT)
X        dir = RIGHT;
X      
X      /* Try circling clockwise around player */
X      else if((allow & MOVEUP) && badguys[i].xpos < player.xpos)
X        dir = UP;
X      else if((allow & MOVEDOWN) && badguys[i].xpos > player.xpos)
X        dir = DOWN;
X      else if((allow & MOVELEFT) && badguys[i].ypos > player.ypos)
X        dir = LEFT;
X      else if((allow & MOVERIGHT) && badguys[i].ypos < player.ypos)
X        dir = RIGHT;
X
X      /* Try approaching player */
X      else if((allow & MOVEUP) && badguys[i].ypos > player.ypos)
X        dir = UP;
X      else if((allow & MOVEDOWN) && badguys[i].ypos < player.ypos)
X        dir = DOWN;
X      else if((allow & MOVELEFT) && badguys[i].xpos > player.xpos)
X        dir = LEFT;
X      else if((allow & MOVERIGHT) && badguys[i].xpos < player.xpos)
X        dir = RIGHT;
X      
X      /* Try moving in any possible direction */
X      else if(allow & MOVEUP)
X        dir = UP;
X      else if(allow & MOVEDOWN)
X        dir = DOWN;
X      else if(allow & MOVELEFT)
X        dir = LEFT;
X      else if(allow & MOVERIGHT)
X        dir = RIGHT;
X
X      /* If totally stuck, just stand in place */
X      else
X        dir = STAND;
X    }
X
X    /* Reverse bad guys direction is REVERSE item is held by player */
X    if((fast_lookup[player.hold].code & REVERSE) &&
X       (x & 1) == 0 && (y & 1) == 0)
X      switch(dir) {
X      case LEFT:  dir = RIGHT; break;
X      case RIGHT: dir = LEFT;  break;
X      case UP:    dir = DOWN;  break;
X      case DOWN:  dir = UP;    break;
X      }
X    
X    /* Execute computed movement. */
X    if(movething(&(badguys[i]),dir,i) == 3) {
X      /* If the bad guy dropped something, the block will have been */
X      /* overwritten and now the bad guy needs to be redrawn */
X      badguys[i].redraw = 1;
X      break;
X    }
X
X    /* Redraw bad guy if it has moved */
X    if(x != badguys[i].xpos || y != badguys[i].ypos)
X      badguys[i].redraw = 1;
X  }
X  /* Redraw bad guys in new positions */
X  drawmove_badguys();
X}
END_OF_FILE
if test 16560 -ne `wc -c <'golddig2/badguy.c'`; then
    echo shar: \"'golddig2/badguy.c'\" unpacked with wrong size!
fi
# end of 'golddig2/badguy.c'
fi
if test -f 'golddig2/movement.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'golddig2/movement.c'\"
else
echo shar: Extracting \"'golddig2/movement.c'\" \(15801 characters\)
sed "s/^X//" >'golddig2/movement.c' <<'END_OF_FILE'
X/* This program was written by Alexander Siegel in September of 1989   */
X/* at Cornell University.  It may may copied freely for private use or */
X/* public dispersion provided that this comment is not removed.  This  */
X/* program, any portion of this program, or any derivative of this     */
X/* program may not be sold or traded for financial gain.               */
X
X#include <stdio.h>
X#include <X11/Xlib.h>
X#include <X11/keysym.h>
X#include "golddig.h"
X
Xlong random();
X
X#define MAXHOLE 100     /* Maximum number of holes at once */
X
Xint holedecay[] = {2,4,6,62,66,70,74};  /* Number of ticks after which */
X                                        /* hole will change form. */
Xint numholes;           /* Total number of holes */
X/* Structure to describe a hole */
Xstruct {
X  int x,y;      /* Position of hole */
X  int ticmade;  /* Value of curtick when hole was created.  Used to */
X                /* time hole transitions. */
X} holes[MAXHOLE];   /* Array for holes. */
X
X/* Compute the allowable directions of movement out of a block.  The */
X/* value in the moveallow array is updated at that position. */
Xvoid allow_posit(x,y)
Xregister int x,y;       /* Position of block which is to be checked */
X{
X  register int pos,code,code2,allow;
X
X  /* Get position of block in level array */
X  pos = x*ysize + y;
X  /* Initially assume that all directions of movement are acceptable */
X  allow = MOVEUP | MOVEDOWN | MOVELEFT | MOVERIGHT;
X  /* Prevent movement off of the level into nowhere land */
X  if(x == 0)
X    allow &= ~MOVELEFT;
X  if(y == 0)
X    allow &= ~MOVEUP;
X  if(x == xsize - 1)
X    allow &= ~MOVERIGHT;
X  if(y == ysize - 1)
X    allow &= ~MOVEDOWN;
X  
X  /* Get the control code for the block at the position */
X  code = fast_lookup[level[pos]].code;
X  /* Use the control code for space if the block is inactive */
X  if((code & INACTIVE) && goldleft > 0)
X    code = fast_lookup[SPACE].code;
X  /* Use the control bits for the block to reduce the allowable */
X  /* movement directions */
X  if(! (code & ULEAVE))
X    allow &= ~MOVEUP;
X  if(! (code & DLEAVE))
X    allow &= ~MOVEDOWN;
X  if(! (code & LLEAVE))
X    allow &= ~MOVELEFT;
X  if(! (code & RLEAVE))
X    allow &= ~MOVERIGHT;
X
X  /* Check block to the left to make sure that it is possible to enter */
X  /* that block from the current position. */
X  if(x > 0) {
X    /* Put control code for block to the left into register */
X    code2 = fast_lookup[level[pos - ysize]].code;
X    if((code2 & INACTIVE) && goldleft > 0)
X      code2 = fast_lookup[SPACE].code;
X    /* Determine if it possible to enter */
X    if(! (code2 & HENTER))
X      allow &= ~MOVELEFT;
X    /* Prevent falling back into it if something can walk back from it */
X    if((code2 & RLEAVE) && ! (code2 & CANFALL))
X      code &= ~LFALL;
X  }
X  /* Check block to the right */
X  if(x < xsize - 1) {
X    code2 = fast_lookup[level[pos + ysize]].code;
X    if((code2 & INACTIVE) && goldleft > 0)
X      code2 = fast_lookup[SPACE].code;
X    /* Determine if it possible to enter */
X    if(! (code2 & HENTER))
X      allow &= ~MOVERIGHT;
X    /* Prevent falling back into it if something can walk back from it */
X    if((code2 & LLEAVE) && ! (code2 & CANFALL))
X      code &= ~RFALL;
X  }
X  /* Check block above */
X  if(y > 0) {
X    code2 = fast_lookup[level[pos - 1]].code;
X    if((code2 & INACTIVE) && goldleft > 0)
X      code2 = fast_lookup[SPACE].code;
X    /* Determine if it possible to enter */
X    if(! (code2 & VENTER))
X      allow &= ~MOVEUP;
X    /* Prevent falling back into it if something can walk back from it */
X    if((code2 & DLEAVE) && ! (code2 & CANFALL))
X      code &= ~UFALL;
X  }
X  /* Check block below */
X  if(y < ysize - 1) {
X    code2 = fast_lookup[level[pos + 1]].code;
X    if((code2 & INACTIVE) && goldleft > 0)
X      code2 = fast_lookup[SPACE].code;
X    /* Determine if it possible to enter */
X    if(! (code2 & VENTER))
X      allow &= ~MOVEDOWN;
X    /* Prevent falling back into it if something can walk back from it */
X    /* Note that things will stick up if there is upward gravity */
X    /* pointing into downward gravity. */
X    if(code2 & ULEAVE)
X      code &= ~DFALL;
X  }
X
X  /* Add gravity force */
X  if((code & DFALL) && (allow & MOVEDOWN))
X    allow |= FORCEDOWN;
X  if((code & UFALL) && (allow & MOVEUP))
X    allow |= FORCEUP;
X  if((code & LFALL) && (allow & MOVELEFT))
X    allow |= FORCELEFT;
X  if((code & RFALL) && (allow & MOVERIGHT))
X    allow |= FORCERIGHT;
X
X  /* Store value back into moveallow array */
X  moveallow[pos] = allow;
X}
X
X/* Call allow_posit on a position and all surrounding positions */
Xvoid allow_area(x,y)
Xint x,y;        /* Position to call allow_posit at */
X{
X  allow_posit(x,y);
X  if(x < xsize - 1)
X    allow_posit(x+1,y);
X  if(x > 0)
X    allow_posit(x-1,y);
X  if(y < ysize - 1)
X    allow_posit(x,y+1);
X  if(y > 0)
X    allow_posit(x,y-1);
X}
X
X/* Regenerate entire moveallow array */
Xvoid regen_allow()
X{
X  int x,y;
X
X  /* Iterate through every possible position and call allow_posit on */
X  /* it. */
X  for(x=0;x<xsize;++x)
X    for(y=0;y<ysize;++y)
X      allow_posit(x,y);
X}
X
X/* Form a hole. */
Xvoid make_hole(x,y,code)
Xint x,y;        /* Position where hole is to be formed */
Xlong code;      /* Code of item held while digging */
X{
X  register int pos;
X
X  /* Compute position in level array where hole is to be created */
X  pos = x*ysize + y;
X  /* Make sure that the position is inside the level array */
X  if(x < 0 || x >= xsize || y < 1 || y >= ysize)
X    return;
X  /* Check for reverse shovel */
X  if(code & RSHOVEL) {
X    /* Make sure that there is space is the specified position */
X    if(level[pos] != SPACE)
X      return;
X    /* Replace space with brick */
X    setchar(x,y,BRICK);
X  }
X  else {
X    /* Make sure that the block can be dug */
X    if(! (fast_lookup[level[pos]].code & CANDIG) ||
X       /* Make sure that the block above it allows for digging */
X       /* underneath. */
X       ! (fast_lookup[level[pos - 1]].code & DIGUND))
X      return;
X    
X    /* Check for power shovel */
X    if(code & PSHOVEL)
X      setchar(x,y,SPACE);
X    else {
X      /* Prevent the creation of too many holes */
X      if(numholes >= MAXHOLE)
X        return;
X      /* Replace the character at the position with the first hole block */
X      setchar(x,y,HOLE1);
X      /* Add that hole to the hole array */
X      holes[numholes].x = x;
X      holes[numholes].y = y;
X      holes[numholes].ticmade = curtick;
X      numholes ++;
X    }
X  }
X  /* Recompute the allowable movement direction for that position and */
X  /* all surrounding positions */
X  allow_area(x,y);
X}
X
X/* Fill up a hole with brick */
Xvoid fill_hole(x,y)
Xint x,y;        /* Position specifying hole */
X{
X  register int i;
X
X  /* Look through all the holes until the right one is found */
X  for(i=0;i<numholes;++i)
X    if(holes[i].x == x && holes[i].y == y) {
X      /* Change the block to a brick */
X      setchar(holes[i].x,holes[i].y,BRICK);
X      /* Recompute the allowable movement for the specified position */
X      /* and all surrounding positions. */
X      allow_area(holes[i].x,holes[i].y);
X      /* Remove the hole from the holes array */
X      holes[i] = holes[numholes - 1];
X      numholes --;
X      return;
X    }
X}
X
X/* Age all holes by one clock tick */
Xvoid change_holes()
X{
X  register int i,j;
X
X  /* Look for decaying holes.  Iterate through each hole. */
X  for(i=0;i<numholes;++i) {
X    /* Check if the hole is exactly at any transition point */
X    for(j=0;j<7;++j)
X      if(holes[i].ticmade + holedecay[j] == curtick) {
X        /* If it is a normal transition point, just change the block */
X        /* type */
X        if(j < 6)
X          setchar(holes[i].x,holes[i].y,(char) (HOLE1 + j + 1));
X        /* If it is the last transition point, fill the hole in */
X        else {
X          fill_hole(holes[i].x,holes[i].y);
X          /* Back up one hole since the hole that was at this position */
X          /* has now been replaced by another. */
X          i --;
X        }
X        break;
X      }
X  }
X}
X
X/* Try to move a thing (player or bad guy) in a given direction.  The */
X/* structure describing the things is updated in place with the new */
X/* position and apparent active command.  A code value is returned */
X/* describing what type of movement actually occurred. */
Xint movething(thing,newdir,num)
Xregister struct thing_s *thing;     /* Pointer to struct describing */
X                                    /* current state of thing */
Xenum directs newdir;                /* New command being attempted */
Xint num;                            /* Number of bad guy or -1 for */
X                                    /* player */
X{
X  register int lpos,code;
X  int nx,ny;
X
X  /* Compute useful local values */
X  lpos = (thing->xpos >> 1)*ysize + (thing->ypos >> 1);
X  code = fast_lookup[level[lpos]].code;
X  if((code & INACTIVE) && goldleft > 0)
X    code = fast_lookup[SPACE].code;
X
X  /* Complete previous initiated movement */
X  if((thing->xpos & 1) || (thing->ypos & 1)) {
X    /* Allow partial horizontal movement to complete */
X    if(thing->xpos & 1) {
X      /* Continue in old direction */
X      switch(thing->dir) {
X      case LEFT:
X        thing->xpos -= 1;
X        thing->dir = LEFT;
X        break;
X      default:
X        thing->xpos += 1;
X        thing->dir = RIGHT;
X        break;
X      }
X    }
X    
X    /* Allow partial vertical movement to complete */
X    if(thing->ypos & 1) {
X      /* Continue in old direction */
X      switch(thing->dir) {
X      case UP:
X        thing->ypos -= 1;
X        thing->dir = UP;
X        break;
X      default:
X        thing->ypos += 1;
X        thing->dir = DOWN;
X        break;
X      }
X    }
X
X    /* Pickup things which are laying around */
X    lpos = (thing->xpos >> 1)*ysize + (thing->ypos >> 1);
X    code = fast_lookup[level[lpos]].code;
X    if(newdir != PUTDOWN && (code & PICKUP) && thing->hold == SPACE) {
X      thing->hold = level[lpos];
X      setchar(thing->xpos >> 1,thing->ypos >> 1,SPACE);
X      allow_area(thing->xpos >> 1,thing->ypos >> 1);
X    }
X
X    /* Activate teleporter if standing on one and not holding an */
X    /* anchor */
X    if((code & TELEPORT) &&
X       ! (fast_lookup[thing->hold].code & ANCHOR)) {
X      do {
X        lpos ++;
X        thing->ypos += 2;
X        if(thing->ypos >> 1 == ysize) {
X          thing->ypos = 0;
X          thing->xpos += 2;
X          if(thing->xpos >> 1 == xsize) {
X            lpos = 0;
X            thing->xpos = 0;
X          }
X        }
X      } while(! (fast_lookup[level[lpos]].code & TELEPORT));
X    }
X
X    /* Activate jump pad if standing on one and not holding an anchor */
X    if((code & UPTWO) &&
X       ! (fast_lookup[thing->hold].code & ANCHOR)) {
X      thing->ypos -= 4;
X      if(thing->ypos < 0)
X        thing->ypos = 0;
X    }
X
X    /* Activate super jump pad */
X    if(code & UPALL) {
X      thing->ypos -= 4;
X      /* Jump to the top of screen if not holding an anchor */
X      if(thing->ypos < 0 ||
X         ! (fast_lookup[thing->hold].code & ANCHOR))
X        thing->ypos = 0;
X    }
X
X    return(1);
X  }
X
X  /* Allow creature to fall */
X  if((moveallow[lpos] & FORCEALL) &&
X     ! (fast_lookup[thing->hold].code & STOPFALL)) {
X    /* Compute position offset in direction of fall */
X    nx = ny = 0;
X    if(moveallow[lpos] & FORCEDOWN) {
X      ny = 1;
X      thing->dir = DOWN;
X    }
X    if(moveallow[lpos] & FORCEUP) {
X      ny = -1;
X      thing->dir = UP;
X    }
X    if(moveallow[lpos] & FORCERIGHT) {
X      nx = 1;
X      thing->dir = RIGHT;
X    }
X    if(moveallow[lpos] & FORCELEFT) {
X      nx = -1;
X      thing->dir = LEFT;
X    }
X
X    /* Prevent falling into another thing */
X    if(! overlap_badguy(thing->xpos + nx + nx,thing->ypos + ny + ny,num)) {
X      /* Drop item behind if falling into a hole */
X      if(level[lpos] == SPACE && thing->hold != SPACE) {
X        /* Compute level position of space that thing is falling into */
X        lpos = ((thing->xpos >> 1)+nx)*ysize + 
X          ((thing->ypos >> 1)+ny);
X        /* Check to see if next position is a hole */
X        if(fast_lookup[level[lpos]].code & STOPBAD) {
X          setchar(thing->xpos >> 1,thing->ypos >> 1,thing->hold);
X          thing->hold = SPACE;
X          allow_area(thing->xpos >> 1,thing->ypos >> 1);
X        }
X      }
X
X      /* Increment position */
X      thing->xpos += nx;
X      thing->ypos += ny;
X      return(2);
X    }
X  }
X
X  /* Slow movement down if holding an anchor */
X  if((fast_lookup[thing->hold].code & ANCHOR) && (random() % 4 != 0))
X    newdir = STAND;
X
X  /* Continue previous movement if it was at right angles to intended */
X  /* movement, and intended movement is impossible */
X  switch(newdir) {
X  /* Check for possible upward movement. */
X  case UP:
X    if(! (moveallow[lpos] & MOVEUP)) {
X      if(thing->dir == LEFT || thing->dir == RIGHT)
X        newdir = thing->dir;
X    }
X    break;
X  /* Check for possible downward movement. */
X  case DOWN:
X    if(! (moveallow[lpos] & MOVEDOWN)) {
X      if(thing->dir == LEFT || thing->dir == RIGHT)
X        newdir = thing->dir;
X    }
X    break;
X  /* Check for possible left movement. */
X  case LEFT:
X    if(! (moveallow[lpos] & MOVELEFT)) {
X      if(thing->dir == UP || thing->dir == DOWN)
X        newdir = thing->dir;
X    }
X    break;
X  /* Check for possible right movement. */
X  case RIGHT:
X    if(! (moveallow[lpos] & MOVERIGHT)) {
X      if(thing->dir == UP || thing->dir == DOWN)
X        newdir = thing->dir;
X    }
X    break;
X  }
X
X  /* By default, the thing is standing in place */
X  thing->dir = STAND;
X  /* Try to execute the intended movement */
X  switch(newdir) {
X  /* Put something down if that is the order */
X  case PUTDOWN:
X    if(level[lpos] == SPACE && thing->hold != SPACE) {
X      setchar(thing->xpos >> 1,thing->ypos >> 1,thing->hold);
X      thing->hold = SPACE;
X      allow_area(thing->xpos >> 1,thing->ypos >> 1);
X    }
X    return(3);
X  /* Dig holes left or right if that is the command.  The make_hole */
X  /* command will fail if it is impossible to dig a hole at the */
X  /* specified location. */
X  case DIGLEFT:
X    make_hole((thing->xpos >> 1) - 1,(thing->ypos >> 1) + 1,
X              fast_lookup[thing->hold].code);
X    if(fast_lookup[thing->hold].code & NSHOVEL) {
X      make_hole((thing->xpos >> 1) - 2,(thing->ypos >> 1) + 1,
X                fast_lookup[thing->hold].code);
X      make_hole((thing->xpos >> 1) - 1,(thing->ypos >> 1) + 2,
X                fast_lookup[thing->hold].code);
X      make_hole((thing->xpos >> 1) - 2,(thing->ypos >> 1) + 2,
X                fast_lookup[thing->hold].code);
X    }
X    return(4);
X  case DIGRIGHT:
X    make_hole((thing->xpos >> 1) + 1,(thing->ypos >> 1) + 1,
X              fast_lookup[thing->hold].code);
X    if(fast_lookup[thing->hold].code & NSHOVEL) {
X      make_hole((thing->xpos >> 1) + 2,(thing->ypos >> 1) + 1,
X                fast_lookup[thing->hold].code);
X      make_hole((thing->xpos >> 1) + 1,(thing->ypos >> 1) + 2,
X                fast_lookup[thing->hold].code);
X      make_hole((thing->xpos >> 1) + 2,(thing->ypos >> 1) + 2,
X                fast_lookup[thing->hold].code);
X    }
X    return(4);
X  /* Since the thing is not falling or completing a previous movement, */
X  /* it can start off in a new direction.  The moveallow array is used */
X  /* to determine which directions are possible. */
X  /* Check for possible upward movement. */
X  case UP:
X    if(moveallow[lpos] & MOVEUP) {
X      thing->ypos -= 1;
X      thing->dir = UP;
X    }
X    break;
X  /* Check for possible downward movement. */
X  case DOWN:
X    if(moveallow[lpos] & MOVEDOWN) {
X      thing->ypos += 1;
X      thing->dir = DOWN;
X    }
X    break;
X  /* Check for possible left movement. */
X  case LEFT:
X    if(moveallow[lpos] & MOVELEFT) {
X      thing->xpos -= 1;
X      thing->dir = LEFT;
X    }
X    break;
X  /* Check for possible right movement. */
X  case RIGHT:
X    if(moveallow[lpos] & MOVERIGHT) {
X      thing->xpos += 1;
X      thing->dir = RIGHT;
X    }
X    break;
X  }
X  return(0);
X}
END_OF_FILE
if test 15801 -ne `wc -c <'golddig2/movement.c'`; then
    echo shar: \"'golddig2/movement.c'\" unpacked with wrong size!
fi
# end of 'golddig2/movement.c'
fi
if test -f 'golddig2/shared.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'golddig2/shared.c'\"
else
echo shar: Extracting \"'golddig2/shared.c'\" \(14143 characters\)
sed "s/^X//" >'golddig2/shared.c' <<'END_OF_FILE'
X/* This program was written by Alexander Siegel in September of 1989   */
X/* at Cornell University.  It may may copied freely for private use or */
X/* public dispersion provided that this comment is not removed.  This  */
X/* program, any portion of this program, or any derivative of this     */
X/* program may not be sold or traded for financial gain.               */
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 <string.h>
X#include "golddig.h"
X
X/* Include all the bitmaps for the terrain blocks */
X#include "bitmap/player.bits"
X#include "bitmap/badguy.bits"
X#include "bitmap/ladder.bits"
X#include "bitmap/space.bits"
X#include "bitmap/wall.bits"
X#include "bitmap/hole1.bits"
X#include "bitmap/hole2.bits"
X#include "bitmap/hole3.bits"
X#include "bitmap/hole4.bits"
X#include "bitmap/hole5.bits"
X#include "bitmap/hole6.bits"
X#include "bitmap/hole7.bits"
X#include "bitmap/stone.bits"
X#include "bitmap/ghost.bits"
X#include "bitmap/gold.bits"
X#include "bitmap/escape.bits"
X#include "bitmap/rope.bits"
X#include "bitmap/uplevel.bits"
X#include "bitmap/invis.bits"
X#include "bitmap/steplad.bits"
X#include "bitmap/tube.bits"
X#include "bitmap/chute.bits"
X#include "bitmap/vrope.bits"
X#include "bitmap/teleport.bits"
X#include "bitmap/armor.bits"
X#include "bitmap/parac.bits"
X#include "bitmap/nshovel.bits"
X#include "bitmap/hourgl.bits"
X#include "bitmap/reverse.bits"
X#include "bitmap/portable.bits"
X#include "bitmap/larrow.bits"
X#include "bitmap/rarrow.bits"
X#include "bitmap/darrow.bits"
X#include "bitmap/uarrow.bits"
X#include "bitmap/kill.bits"
X#include "bitmap/jump.bits"
X#include "bitmap/anchor.bits"
X#include "bitmap/sjump.bits"
X#include "bitmap/speed.bits"
X#include "bitmap/pshovel.bits"
X#include "bitmap/rshovel.bits"
X#include "bitmap/fog.bits"
X#include "bitmap/window.bits"
X#include "bitmap/anti.bits"
X
Xchar *sprintf();    /* UNIX brain damage */
X
X/* All in and out movements except up */
X#define NOUPBITS   DLEAVE | LLEAVE | RLEAVE | HENTER | VENTER
X/* All in and out movements */
X#define MOVEBITS   NOUPBITS | ULEAVE
X/* Standard bit pattern for empty space */
X#define SPACEBITS  NOUPBITS | DIGUND | DFALL
X/* Generic item which can be picked up */
X#define ITEMBITS   SPACEBITS | PICKUP
X/* Bit pattern used for dug holes */
X#define HOLEBITS   SPACEBITS | STOPBAD | NODRAW
X
X/* Structure describing all the characteristics of all blocks.  Refer */
X/* to the defines and structure definition in golddig.h. */
Xstruct symbs_s symbs[] = 
X  {{SPACE,SPACE,"space",space_bits,SPACEBITS,XK_space,0},
X   {'!','|',"escape",escape_bits,MOVEBITS | DIGUND | INACTIVE,XK_exclam,XK_1},
X   {BRICK,BRICK,"wall",wall_bits,CANDIG | KILLIN,XK_3,XK_numbersign},
X   {'$','$',"gold",gold_bits,ITEMBITS | TREASURE,XK_4,XK_dollar},
X   {'-','-',"rope",rope_bits,NOUPBITS | DIGUND,XK_minus,0},
X   {HOLE1,HOLE1,"hole1",hole1_bits,HOLEBITS,0,0},
X   {HOLE1+1,HOLE1+1,"hole2",hole2_bits,HOLEBITS,0,0},
X   {HOLE1+2,HOLE1+2,"hole3",hole3_bits,HOLEBITS,0,0},
X   {HOLE1+3,HOLE1+3,"hole4",hole4_bits,HOLEBITS,0,0},
X   {HOLE1+4,HOLE1+4,"hole5",hole5_bits,HOLEBITS,0,0},
X   {HOLE1+5,HOLE1+5,"hole6",hole6_bits,HOLEBITS,0,0},
X   {HOLE1+6,HOLE1+6,"hole7",hole7_bits,HOLEBITS,0,0},
X   {'<','<',"left arrow",larrow_bits,LLEAVE | HENTER | VENTER | LFALL | DIGUND,
X      XK_comma,XK_less},
X   {'=','=',"tube",tube_bits,RLEAVE | LLEAVE | HENTER,XK_equal,0},
X   {'>','>',"right arrow",rarrow_bits,RLEAVE | HENTER | VENTER | RFALL | 
X      DIGUND,XK_period,XK_greater},
X   {STONE,STONE,"stone",stone_bits,KILLIN,XK_2,XK_at},
X   {'^','^',"anti-space",anti_bits,ULEAVE | LLEAVE | RLEAVE | HENTER |
X      VENTER | DIGUND | UFALL,XK_6,XK_asciicircum},
X   {'a','a',"armor",armor_bits,ITEMBITS | ARMOR,XK_A,XK_a},
X   {BADGUY,BADGUY,"bad guy",badguy_bits,SPACEBITS,XK_B,XK_b},
X   {'c','c',"chute",chute_bits,DLEAVE | DFALL | VENTER,XK_C,XK_c},
X   {'d','d',"down arrow",darrow_bits,DLEAVE | HENTER | VENTER | DIGUND |
X      DFALL,XK_D,XK_d},
X   {'e','e',"reverse monster",reverse_bits,ITEMBITS | REVERSE, XK_E,XK_e},
X   {'f','f',"up arrow",uarrow_bits,ULEAVE | HENTER | VENTER | UFALL |
X      DIGUND,XK_F,XK_f},
X   {'g',BRICK,"ghost brick",ghost_bits,(SPACEBITS) & ~HENTER,XK_G,XK_g},
X   {'i',SPACE,"invisible block",invis_bits,KILLIN,XK_I,XK_i},
X   {'j','j',"jump pad",jump_bits,NOUPBITS | UPTWO,XK_J,XK_j},
X   {'k','k',"kill zone",kill_bits,HENTER | VENTER | DIGUND |
X      KILLIN,XK_K,XK_k},
X   {'l','l',"power shovel",pshovel_bits,ITEMBITS | PSHOVEL,XK_L,XK_l},
X   {'m','m',"super jump pad",sjump_bits,NOUPBITS | UPALL,XK_M,XK_m},
X   {'n','n',"nuclear shovel",nshovel_bits,ITEMBITS | NSHOVEL,XK_N,XK_n},
X   {'o','o',"anchor",anchor_bits,ITEMBITS | ANCHOR,XK_O,XK_o},
X   {PLAYER,PLAYER,"player",player_bits,SPACEBITS,XK_P,XK_p},
X   {'q','q',"speed boot",speed_bits,ITEMBITS | SPEED,XK_Q,XK_q},
X   {'r','r',"parachute",parac_bits,ITEMBITS | STOPFALL,XK_R,XK_r},
X   {'s','s',"step ladder",steplad_bits,MOVEBITS | PICKUP,XK_S,XK_s},
X   {'t','t',"teleporter",teleport_bits,SPACEBITS | TELEPORT,XK_T,XK_t},
X   {'u','u',"leave level",uplevel_bits,SPACEBITS | UPLEVEL |
X      INACTIVE,XK_U,XK_u},
X   {'v','v',"vertical rope",vrope_bits,ULEAVE | DLEAVE |
X      HENTER | VENTER,XK_V,XK_v},
X   {'w','w',"window",window_bits,SPACEBITS | UPLEVEL,XK_W,XK_w},
X   {'x','x',"extra brick",rshovel_bits,ITEMBITS | RSHOVEL,XK_X,XK_x},
X   {'y','y',"heavy fog",fog_bits,SPACEBITS,XK_Y,XK_y},
X   {'z','z',"time stop",hourgl_bits,ITEMBITS | TIMESTOP,XK_Z,XK_z},
X   {'|','|',"ladder",ladder_bits,MOVEBITS,XK_backslash,XK_bar},
X   {'~','-',"portable rope",portable_bits,NOUPBITS | DIGUND |
X      PICKUP,XK_asciitilde,XK_quoteleft},
X
X   /* List terminator */
X   {'\0','\0',(char *) 0,(char *) 0,0,0,0}};
X
XFont scorefont;     /* Font used to display score */
XGC scoregc;         /* GC used to draw score */
XGC blackgc;         /* Simple black foreground GC */
X
X/* Manufaction a 16x16 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,16,16,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
X/* Start X11 and do some basic initialization */
Xvoid xstart(evmask)
Xlong evmask;    /* Event mask which will be used in XSelectInput */
X{
X  register int i;
X  XGCValues xgcv;
X  XWMHints wmhints;
X
X  /* Open up the display */
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    exit(-1);
X  }
X
X  /* Create the game window */
X  wind = XCreateSimpleWindow(disp,DefaultRootWindow(disp),20,20,
X                             50 << 4,(30 << 4) + SCORESIZE,
X                             2,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  /* Clear fast block type lookup table */
X  for(i=0;i<256;++i) {
X    fast_lookup[i].gc = NULL;
X    /* Everything starts out looking like a space */
X    fast_lookup[i].code = SPACEBITS;
X  }
X  /* Generate block type lookup table from symbs array defined above. */
X  /* After this the symbs array will be used very rarely. */
X  for(i=0;symbs[i].symb != '\0';++i) {
X    fast_lookup[symbs[i].symb].gc  =
X      makegc(GXcopy,symbs[i].bits);
X    fast_lookup[symbs[i].symb].code = symbs[i].code;
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 = WhitePixel(disp,0);
X  xgcv.background = BlackPixel(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  xgcv.foreground = BlackPixel(disp,0);
X  xgcv.background = WhitePixel(disp,0);
X  blackgc = XCreateGC(disp,wind,
X                      GCFunction | GCForeground | GCBackground,
X                      &xgcv);
X
X  /* Tell the WM that we want input... */
X  wmhints.input = True;
X  wmhints.flags = InputHint;
X  XSetWMHints(disp, wind, &wmhints);
X
X  /* Select the interesting window events */
X  XSelectInput(disp,wind,evmask);
X
X  /* Name and raise the window */
X  XMapRaised(disp,wind);
X
X  /* Flush and synchronize the server */
X  XFlush(disp);
X  XSync(disp,False);
X}
X
X/* Gracefully shut X windows down.  It is not strictly necessary to */
X/* call this function. */
Xvoid xend()
X{
X  XUnloadFont(disp,scorefont);
X  XUnmapWindow(disp,wind);
X  XDestroyWindow(disp,wind);
X  XCloseDisplay(disp);
X}
X
X/* Draw a block from the level array in the output window. */
Xvoid draw_block(x,y)
Xint x,y;    /* Position of block in array */
X{
X  register char curchar;
X  GC drawgc;
X
X  /* Get the block character out of the level array */
X  curchar = level[x*ysize + y];
X  /* If there is gold left and this block is inactive, replace it with */
X  /* a space. */
X  if(goldleft > 0 && (fast_lookup[curchar].code & INACTIVE))
X    curchar = SPACE;
X  /* Get the graphics cursor */
X  drawgc = fast_lookup[curchar].gc;
X  /* Replace questionable characters with spaces */
X  if(drawgc == NULL)
X    drawgc = fast_lookup[SPACE].gc;
X  /* Fill the block */
X  XFillRectangle(disp,wind,drawgc,x << 4,y << 4,16,16);
X}
X
X/* Change a block character in the level array.  The block is redrawn. */
Xvoid setchar(x,y,ch)
Xint x,y;    /* Position of block character to change. */
Xchar ch;    /* Character to change it to */
X{
X  if(level[x*ysize + y] != ch) {
X    level[x*ysize + y] = ch;
X    draw_block(x,y);
X  }
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,"score: %d  level: %d  speed: %d",score,levelnum,speed);
X  /* Clear the current score line */
X  XFillRectangle(disp,wind,blackgc,0,ysize << 4,xsize << 4,SCORESIZE);
X  /* Actually draw the text */
X  XDrawString(disp,wind,scoregc,0,(ysize << 4) + SCORESIZE - 1,buf,
X              strlen(buf));
X}
X
X/* Redraw the entire level */
Xvoid draw_level()
X{
X  int x,y;
X
X  /* Change the window size */
X  XResizeWindow(disp,wind,xsize << 4,(ysize << 4) + SCORESIZE);
X  /* Draw the score and level number */
X  draw_score();
X  /* Iterate through each block position and draw it */
X  for(x=0;x < xsize;++x)
X    for(y=0;y < ysize;++y)
X      draw_block(x,y);
X}
X
X/* Load a level out of a file.  The global variables worldname and */
X/* levelnum are used to produce the file name which is stored in */
X/* filename. */
Xvoid load_level()
X{
X  FILE *levelfile;
X  register int i,j;
X  int x,y;
X  char buf[300];
X
X  /* Manufaction the file name by starting with the world name and */
X  /* appending the level number to it. */
X  strcpy(filename,LIB);
X  strcat(filename,"/");
X  strcat(filename,worldname);
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,LIB);
X    strcat(buf,"/default");
X    /* Open default level file for reading */
X    levelfile = fopen(buf,"r");
X    if(levelfile == NULL) {
X      perror(worldname);
X      exit(1);
X    }
X  }
X
X  /* Load the first line of the level file */
X  if(fgets(buf,300,levelfile) == NULL) {
X    x = 50;
X    y = 30;
X  }
X  else {
X    /* Extract the level size */
X    sscanf(buf,"%d %d",&x,&y);
X  }
X  /* Change level size only if it is necessary */
X  if(xsize == -1)
X    xsize = x;
X  if(ysize == -1)
X    ysize = y;
X  /* Carefully check the sanity of the size parameters */
X  if(xsize < 5)
X    xsize = 5;
X  if(xsize > 250)
X    xsize = 250;
X  if(ysize < 5)
X    ysize = 5;
X  if(ysize > 250)
X    ysize = 250;
X  if(xsize * ysize > MAXLEVEL) {
X    if(xsize > ysize)
X      xsize = MAXLEVEL / ysize;
X    else
X      ysize = MAXLEVEL / xsize;
X  }
X  /* Iterate through each horizontal line */
X  for(i=0;i<ysize;++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<xsize;++j) {
X        /* Break out if line ends prematurely */
X        if(buf[j] == '\n' || buf[j] == '\0')
X          break;
X        level[j*ysize + i] = buf[j];
X      }
X    }
X    else
X      j = 0;
X    /* Fill in rest of premature lines with spaces */
X    for(;j<xsize;++j)
X      level[j*ysize + i] = SPACE;
X  }
X  /* Close the level file */
X  fclose(levelfile);
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    perror(worldname);
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\n",xsize,ysize);
X  /* Terminate the lines for writing out the horizontal level lines */
X  buf[xsize] = '\n';
X  buf[xsize+1] = '\0';
X  /* Iterate through each vertical position */
X  for(i=0;i<ysize;++i) {
X    /* Copy each horizontal line into the output buffer */
X    for(j=0;j<xsize;++j)
X      buf[j] = level[j*ysize + i];
X    /* Write the line out to the file */
X    fputs(buf,levelfile);
X  }
X  /* Close the data file */
X  fclose(levelfile);
X}
X
X
END_OF_FILE
if test 14143 -ne `wc -c <'golddig2/shared.c'`; then
    echo shar: \"'golddig2/shared.c'\" unpacked with wrong size!
fi
# end of 'golddig2/shared.c'
fi
echo shar: End of archive 3 \(of 4\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 4 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