home *** CD-ROM | disk | FTP | other *** search
- /* This program was written by Alexander Siegel in September of 1989 */
- /* at Cornell University. It may may copied freely for private use or */
- /* public dispersion provided that this comment is not removed. This */
- /* program, any portion of this program, or any derivative of this */
- /* program may not be sold or traded for financial gain. */
-
- #include <stdio.h>
- #include <X11/Xlib.h>
- #include <X11/keysym.h>
- #include "golddig.h"
-
- #define MAXHOLE 100 /* Maximum number of holes at once */
-
- int holedecay[] = {2,4,6,62,66,70,74}; /* Number of ticks after which */
- /* hole will change form. */
- int numholes; /* Total number of holes */
- /* Structure to describe a hole */
- struct {
- int x,y; /* Position of hole */
- int ticmade; /* Value of curtick when hole was created. Used to */
- /* time hole transitions. */
- } holes[MAXHOLE]; /* Array for holes. */
-
- /* Compute the allowable directions of movement out of a block. The */
- /* value in the moveallow array is updated at that position. */
- void allow_posit(x,y)
- register int x,y; /* Position of block which is to be checked */
- {
- register int pos,code,allow;
-
- /* Get position of block in level array */
- pos = x*ysize + y;
- /* Initially assume that all directions of movement are acceptable */
- allow = MOVEUP | MOVEDOWN | MOVELEFT | MOVERIGHT;
- /* Prevent movement off of the level into nowhere land */
- if(x == 0)
- allow &= ~MOVELEFT;
- if(y == 0)
- allow &= ~MOVEUP;
- if(x == xsize - 1)
- allow &= ~MOVERIGHT;
- if(y == ysize - 1)
- allow &= ~MOVEDOWN;
-
- /* Get the control code for the block at the position */
- code = fast_lookup[level[pos]].code;
- /* Use the control code for space if the block is inactive */
- if((code & INACTIVE) && goldleft > 0)
- code = fast_lookup[SPACE].code;
- /* Use the control bits for the block to reduce the allowable */
- /* movement directions */
- if(! (code & ULEAVE))
- allow &= ~MOVEUP;
- if(! (code & DLEAVE))
- allow &= ~MOVEDOWN;
- if(! (code & HLEAVE))
- allow &= ~(MOVELEFT | MOVERIGHT);
-
- /* Check for blocks where you fall through */
- if(y < ysize - 1 && ! (code & SUPPORT)) {
- /* Get the control code for the block directly underneath */
- code = fast_lookup[level[pos + 1]].code;
- if((code & INACTIVE) && goldleft > 0)
- code = fast_lookup[SPACE].code;
- /* Check if it is possible to fall into block beneath. */
- /* The STOPBAD is so that things can walk over bad guys which are */
- /* stuck in a hole. */
- if((code & VENTER) && ! (code & (ULEAVE | STOPBAD)))
- allow &= ~(MOVELEFT | MOVERIGHT | MOVEUP);
- }
-
- /* Check block to the left to make sure that it is possible to enter */
- /* that block from the current position. */
- if(x > 0) {
- if(! (fast_lookup[level[pos - ysize]].code & HENTER))
- allow &= ~MOVELEFT;
- }
- /* Check block to the right */
- if(x < xsize - 1) {
- if(! (fast_lookup[level[pos + ysize]].code & HENTER))
- allow &= ~MOVERIGHT;
- }
- /* Check block above */
- if(y > 0) {
- if(! (fast_lookup[level[pos - 1]].code & VENTER))
- allow &= ~MOVEUP;
- }
- /* Check block below */
- if(y < ysize - 1) {
- if(! (fast_lookup[level[pos + 1]].code & VENTER))
- allow &= ~MOVEDOWN;
- }
- /* Store value back into moveallow array */
- moveallow[pos] = allow;
- }
-
- /* Call allow_posit on a position and all surrounding positions */
- void allow_area(x,y)
- int x,y; /* Position to call allow_posit at */
- {
- allow_posit(x,y);
- if(x < xsize - 1)
- allow_posit(x+1,y);
- if(x > 0)
- allow_posit(x-1,y);
- if(y < ysize - 1)
- allow_posit(x,y+1);
- if(y > 0)
- allow_posit(x,y-1);
- }
-
- /* Regenerate entire moveallow array */
- void regen_allow()
- {
- int x,y;
-
- /* Iterate through every possible position and call allow_posit on */
- /* it. */
- for(x=0;x<xsize;++x)
- for(y=0;y<ysize;++y)
- allow_posit(x,y);
- }
-
- /* Form a hole. */
- void make_hole(x,y)
- int x,y; /* Position where hole is to be formed */
- {
- register int pos;
-
- /* Compute position in level array where hole is to be created */
- pos = x*ysize + y;
- /* Make sure that the position is inside the level array */
- if(pos < 0 || pos >= xsize * ysize || y < 1 ||
- /* Make sure that the block can be dug */
- ! (fast_lookup[level[pos]].code & CANDIG) ||
- /* Make sure that the block above it allows for digging */
- /* underneath. */
- ! (fast_lookup[level[pos - 1]].code & DIGUND) ||
- /* Prevent the creation of too many holes */
- (numholes >= MAXHOLE))
- return;
- /* Replace the character at the position with the first hole block */
- setchar(x,y,HOLE1);
- /* Add that hole to the hole array */
- holes[numholes].x = x;
- holes[numholes].y = y;
- holes[numholes].ticmade = curtick;
- numholes ++;
- /* Recompute the allowable movement direction for that position and */
- /* all surrounding positions */
- allow_area(x,y);
- }
-
- /* Fill up a hole with brick */
- void fill_hole(x,y)
- int x,y; /* Position specifying hole */
- {
- register int i;
-
- /* Look through all the holes until the right one is found */
- for(i=0;i<numholes;++i)
- if(holes[i].x == x && holes[i].y == y) {
- /* Change the block to a brick */
- setchar(holes[i].x,holes[i].y,BRICK);
- /* Recompute the allowable movement for the specified position */
- /* and all surrounding positions. */
- allow_area(holes[i].x,holes[i].y);
- /* Remove the hole from the holes array */
- holes[i] = holes[numholes - 1];
- numholes --;
- return;
- }
- }
-
- /* Age all holes by one clock tick */
- void change_holes()
- {
- register int i,j;
-
- /* Look for decaying holes. Iterate through each hole. */
- for(i=0;i<numholes;++i) {
- /* Check if the hole is exactly at any transition point */
- for(j=0;j<7;++j)
- if(holes[i].ticmade + holedecay[j] == curtick) {
- /* If it is a normal transition point, just change the block */
- /* type */
- if(j < 6)
- setchar(holes[i].x,holes[i].y,(char) (HOLE1 + j + 1));
- /* If it is the last transition point, fill the hole in */
- else {
- fill_hole(holes[i].x,holes[i].y);
- /* Back up one hole since the hole that was at this position */
- /* has now been replaced by another. */
- i --;
- }
- break;
- }
- }
- }
-
- /* Try to move a thing (player or bad guy) in a given direction. The */
- /* structure describing the things is updated in place with the new */
- /* position and apparent active command. A code value is returned */
- /* describing what type of movement actually occurred. */
- int movething(thing,newdir,num)
- register struct thing_s *thing; /* Pointer to struct describing */
- /* current state of thing */
- enum directs newdir; /* New command being attempted */
- int num; /* Number of bad guy or -1 for */
- /* player */
- {
- register int lpos,code;
-
- /* Compute useful local values */
- lpos = (thing->xpos >> 1)*ysize + (thing->ypos >> 1);
- code = fast_lookup[level[lpos]].code;
- if((code & INACTIVE) && goldleft > 0)
- code = fast_lookup[SPACE].code;
-
- /* Complete previous initiated movement */
- if((thing->xpos & 1) || (thing->ypos & 1)) {
- /* Allow partial horizontal movement to complete */
- if(thing->xpos & 1) {
- /* Continue in old direction if trying to stop */
- switch(newdir != LEFT && newdir != RIGHT ? thing->dir : newdir) {
- case LEFT:
- thing->xpos -= 1;
- thing->dir = LEFT;
- break;
- default:
- thing->xpos += 1;
- thing->dir = RIGHT;
- break;
- }
- }
-
- /* Allow partial vertical movement to complete */
- if(thing->ypos & 1) {
- /* Continue in old direction if trying to stop */
- switch(newdir != UP && newdir != DOWN ? thing->dir : newdir) {
- case UP:
- if(moveallow[lpos + 1] & MOVEUP) {
- thing->ypos -= 1;
- thing->dir = UP;
- break;
- }
- default:
- thing->ypos += 1;
- thing->dir = DOWN;
- break;
- }
- }
-
- /* Pickup things which are laying around */
- lpos = (thing->xpos >> 1)*ysize + (thing->ypos >> 1);
- code = fast_lookup[level[lpos]].code;
- if(newdir != PUTDOWN && (code & PICKUP) && thing->hold == SPACE) {
- thing->hold = level[lpos];
- setchar(thing->xpos >> 1,thing->ypos >> 1,SPACE);
- allow_area(thing->xpos >> 1,thing->ypos >> 1);
- }
-
- /* Activate teleporter if standing on one */
- if(code & TELEPORT) {
- do {
- lpos ++;
- thing->ypos += 2;
- if(thing->ypos >> 1 == ysize) {
- thing->ypos = 0;
- thing->xpos += 2;
- if(thing->xpos >> 1 == xsize) {
- lpos = 0;
- thing->xpos = 0;
- }
- }
- } while(! (fast_lookup[level[lpos]].code & TELEPORT));
- }
- return(1);
- }
-
- /* Allow creature to fall */
- if(! (code & SUPPORT) &&
- (moveallow[lpos] & MOVEDOWN) &&
- ! (moveallow[lpos+1] & MOVEUP) &&
- (thing->hold == SPACE ||
- ! (fast_lookup[thing->hold].code & STOPFALL))) {
- /* Prevent falling into another thing */
- if(! overlap_badguy(thing->xpos,thing->ypos+2,num)) {
- /* Drop item behind if falling into a hole */
- if(level[lpos] == SPACE && thing->hold != SPACE &&
- (fast_lookup[level[lpos+1]].code & STOPBAD)) {
- setchar(thing->xpos >> 1,thing->ypos >> 1,thing->hold);
- thing->hold = SPACE;
- allow_area(thing->xpos >> 1,thing->ypos >> 1);
- }
- /* Increment vertical position */
- thing->ypos += 1;
- thing->dir = STAND;
- return(2);
- }
- /* Since there is something below, allow creature to move left or */
- /* right. This changes the moveallow array permanently and can */
- /* have an interesting effect on the behavior of the bad guys. */
- else {
- if((thing->xpos >> 1) > 0 &&
- (fast_lookup[level[lpos - ysize]].code & HENTER))
- moveallow[lpos] |= MOVELEFT;
- if((thing->xpos >> 1) < xsize - 1 &&
- (fast_lookup[level[lpos + ysize]].code & HENTER))
- moveallow[lpos] |= MOVERIGHT;
- }
- }
-
- /* Since the thing is not falling or completing a previous movement, */
- /* it can start off in a new direction. The moveallow array is used */
- /* to determine which directions are possible. */
- thing->dir = STAND;
- switch(newdir) {
- /* Put something down if that is the order */
- case PUTDOWN:
- if(level[lpos] == SPACE && thing->hold != SPACE) {
- setchar(thing->xpos >> 1,thing->ypos >> 1,thing->hold);
- thing->hold = SPACE;
- allow_area(thing->xpos >> 1,thing->ypos >> 1);
- }
- return(3);
- /* Check for possible upward movement. */
- case UP:
- if(moveallow[lpos] & MOVEUP) {
- thing->ypos -= 1;
- thing->dir = UP;
- }
- break;
- /* Check for possible downward movement. */
- case DOWN:
- if(moveallow[lpos] & MOVEDOWN) {
- thing->ypos += 1;
- thing->dir = DOWN;
- }
- break;
- /* Check for possible left movement. */
- case LEFT:
- if(moveallow[lpos] & MOVELEFT) {
- thing->xpos -= 1;
- thing->dir = LEFT;
- }
- break;
- /* Check for possible right movement. */
- case RIGHT:
- if(moveallow[lpos] & MOVERIGHT) {
- thing->xpos += 1;
- thing->dir = RIGHT;
- }
- break;
- /* Dig holes left or right if that is the command. The make_hole */
- /* command will fail if it is impossible to dig a hole at the */
- /* specified location. */
- case DIGLEFT:
- make_hole((thing->xpos >> 1) - 1,(thing->ypos >> 1) + 1);
- if(fast_lookup[thing->hold].code & NSHOVEL) {
- make_hole((thing->xpos >> 1) - 2,(thing->ypos >> 1) + 1);
- make_hole((thing->xpos >> 1) - 1,(thing->ypos >> 1) + 2);
- make_hole((thing->xpos >> 1) - 2,(thing->ypos >> 1) + 2);
- }
- return(4);
- case DIGRIGHT:
- make_hole((thing->xpos >> 1) + 1,(thing->ypos >> 1) + 1);
- if(fast_lookup[thing->hold].code & NSHOVEL) {
- make_hole((thing->xpos >> 1) + 2,(thing->ypos >> 1) + 1);
- make_hole((thing->xpos >> 1) + 1,(thing->ypos >> 1) + 2);
- make_hole((thing->xpos >> 1) + 2,(thing->ypos >> 1) + 2);
- }
- return(4);
- }
- return(0);
- }
-