v05i047: golddig2 -- A game for X11, Part03/04
Kent Landfield
kent at ssbell.uu.net
Thu Dec 14 14:18:07 AEST 1989
Submitted-by: Alexander Siegel <siegel at 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 at 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
More information about the Comp.sources.x
mailing list