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