jfw@eddie.MIT.EDU (John Woods) (11/27/88)
I have found a rather extensive bug in fall.c. The manifestation is that screen 3 was insoluble, because I kept getting hit by falling boulders while ABOVE them. It turns out that fall.c has a number of references to screen[y{+/-}1][x{+/-}1], where there is no check that the resulting subscript is in range (hence it was looking at screen[16][1], where 15 is the maximum subscript. I was unlucky enough to have an @ at that memory location :-). Enclosed below is a replacement for fall.c, which I believe is equivalent to the intent of the original (though I confess that the code is rather confusing to me, for it seems more tortuous than is required. On the other hand, perhaps I am too sleep-deprived thanks to my new daughter:-). The result appears to behave the same (less the buggy behavior) on those few tests that I have tried. I have sent mail to Steven Shipway, but I think the mail bounced (the uncertainty is courtesy of a singularly unhelpful message from someone's mailer about not being able to create dfA99999...). ---------------snip----------snip----------------snip----------------------- #include "wand_head.h" extern void draw_symbol(); extern int debug_disp; extern char screen[NOOFROWS][ROWLEN+1]; int check(mx,my,x,y,dx,dy,sx,sy,howdead) /* check for any falling caused by something moving out of x,y along vector dx,dy. All the others are constant and should really have been global... */ int x,y,sx,sy,dx,dy, *mx, *my; char howdead[25]; { int ret=0; ret+=fall(mx,my,x,y,sx,sy,howdead); ret+=fall(mx,my,x-dx,y-dy,sx,sy,howdead); ret+=fall(mx,my,x-dy,y-dx,sx,sy,howdead); ret+=fall(mx,my,x+dy,y+dx,sx,sy,howdead); ret+=fall(mx,my,x-dx-dy,y-dy-dx,sx,sy,howdead); ret+=fall(mx,my,x-dx+dy,y-dy+dx,sx,sy,howdead); return ret; } int fall(mx,my,x,y,sx,sy,howdead) /* recursive function for falling */ /* boulders and arrows */ int x,y,sx,sy, *mx, *my; char howdead[25]; { int nx = x,nxu = x,nyl = y,nyr = y,retval = 0; int firstrow = 0, firstcol = 0, lastrow = 0, lastcol = 0; if ((y>(NOOFROWS-1))||(y<0)||(x<0)||(x>(ROWLEN-1))) return(0); if((screen[y][x] != 'O') && (screen[y][x] != ' ') && (screen[y][x] != 'M') && (screen[y][x] !='\\') && (screen[y][x] != '/') && (screen[y][x] != '@') && (screen[y][x] != '^')) return(0); firstrow = (y == 0); lastrow = (y == NOOFROWS-1); firstcol = (x == 0); lastcol = (x == ROWLEN - 1); if(screen[y][x] == 'O') { int blankright = 0, blankleft = 0, blankabove = 0, blankbelow = 0, blankupright = 0, blankupleft = 0, blankdnright = 0, blankdnleft = 0; /* blanks above? */ if (!firstrow) { if (!firstcol) blankupleft = (screen[y-1][x-1] == ' '); blankabove = (screen[y-1][x] == ' '); if (!lastcol) blankupright = (screen[y-1][x+1] == ' '); } /* blanks left and right? */ if (!firstcol) blankleft = (screen[y][x-1] == ' '); if (!lastcol) blankright = (screen[y][x+1] == ' '); /* blanks below? */ if (!lastrow) { if (!firstcol) blankdnleft = (screen[y+1][x-1] == ' '); blankbelow = (screen[y+1][x] == ' '); if (!lastcol) blankdnright = (screen[y+1][x+1] == ' '); } if(blankleft && blankupleft) nx--; else { if(blankright && blankupright) nx++; else nx = -1; } if(blankleft && blankdnleft) nxu--; else { if(blankright && blankdnright) nxu++; else nxu = -1; } if(blankabove && blankupright) nyr--; else { if(blankbelow && blankdnright) nyr++; else nyr = -1; } if (blankabove && blankupleft) nyl--; else { if(blankbelow && blankdnleft) nyl++; else nyl = -1; } } if(screen[y][x] == '\\') { if(nx != -1 && (firstrow || nx == (ROWLEN-1) || screen[y-1][++nx] != ' ')) nx = -1; if(nxu != -1 && (lastrow || nxu == 0 || screen[y+1][--nxu] != ' ')) nxu = -1; if(nyr != -1 && (lastcol || nyr == 0 || screen[--nyr][x+1] != ' ')) nyr = -1; if(nyl != -1 && (firstcol || nyl == (NOOFROWS-1) || screen[++nyl][x-1] != ' ')) nyl = -1; } if(screen[y][x] == '/') { if(nx != -1 && (firstrow || nx == 0 || screen[y-1][--nx] != ' ')) nx = -1; if(nxu != -1 && (lastrow || nxu == (ROWLEN-1) || screen[y+1][++nxu] != ' ')) nxu = -1; if(nyr != -1 && (lastcol || nyr == (NOOFROWS-1) || screen[++nyr][x+1] != ' ')) nyr = -1; if(nyl != -1 && (firstcol || nyl == 0 || screen[--nyl][x-1] != ' ')) nyl = -1; } if(nx != -1 && (screen[y][nx] != ' ') && (screen[y][nx] != 'M')) nx = -1; if((y > 0) && (screen[y-1][x] == 'O') && (nx >= 0) && (screen[y][nx] != '^')) /* boulder falls ? */ { screen[y-1][x] = ' '; if(screen[y][nx] == '@') { strcpy(howdead,"a falling boulder"); retval=1; } if(screen[y][nx] == 'M') { *mx = *my = -2; screen[y][nx] = ' '; } screen[y][nx] = 'O'; if(!debug_disp) { if((y<(sy+5)) && (y>(sy-3)) && (x>(sx-6)) && (x<(sx+6))) draw_symbol((x-sx+5)*3,(y-sy+2)*2,' '); if((y<(sy+4)) && (y>(sy-4)) && (nx>(sx-6)) && (nx<(sx+6))) draw_symbol((nx-sx+5)*3,(y-sy+3)*2,'O'); } else { move(y,x+1); addch(' ');; move(y+1,nx+1); addch('O'); } refresh(); retval+=fall(mx,my,nx ,y+1,sx,sy,howdead); retval+=check(mx,my,x,y-1,0,1,sx,sy,howdead); if(y < NOOFROWS-1 && screen[y+1][nx] == '@') { strcpy(howdead,"a falling boulder"); return(1); } if(y < NOOFROWS-1 && screen[y+1][nx] == 'M') { *mx = *my = -2; screen[y+1][nx] = ' '; } } if(nyr != -1 && (screen[nyr][x] != '^')&&(screen[nyr][x] != ' ')&&(screen[nyr][x] != 'M')) nyr = -1; if(x+1<ROWLEN && screen[y][x+1] == '<' && nyr >= 0) /* arrow moves ( < ) ? */ { screen[y][x+1] = ' '; if(screen[nyr][x] == '@') { strcpy(howdead,"a speeding arrow"); retval = 1; } if(screen[nyr][x] == 'M') { *mx = *my = -2; screen[nyr][x] = ' '; } screen[nyr][x] = '<'; if(!debug_disp) { if((y<(sy+4)) && (y>(sy-4)) && (x<(sx+5)) && (x>(sx-7))) draw_symbol((x-sx+6)*3,(y-sy+3)*2,' '); if((nyr<(sy+4)) && (nyr>(sy-4)) && (x<(sx+6)) && (x>(sx-6))) draw_symbol((x-sx+5)*3,(nyr-sy+3)*2,'<'); } else { move(y+1,x+2); addch(' '); move(nyr+1,x+1); addch('<'); } refresh(); retval+=fall(mx,my,x-1,nyr,sx,sy,howdead); retval+=check(mx,my,x+1,y,-1,0,sx,sy,howdead); if(x != 0 && screen[nyr][x-1] == '@') { strcpy(howdead,"a speeding arrow"); return(1); } if(x != 0 && screen[nyr][x-1] == 'M') { *mx = *my = -2; screen[nyr][x-1] = ' '; } } if(nyl != -1 && (screen[nyl][x] != ' ')&&(screen[nyl][x] != '^')&&(screen[nyl][x] != 'M')) nyl = -1; if(x>0 && (screen[y][x-1] == '>') && nyl>=0) /* arrow moves ( > ) ? */ { screen[y][x-1] = ' '; if(screen[nyl][x] == '@') { strcpy(howdead,"a speeding arrow"); retval = 1; } if(screen[nyl][x] == 'M') { *mx = *my = -2; screen[nyl][x] = ' '; } screen[nyl][x] = '>'; if(!debug_disp) { if((y<(sy+4)) && (y>(sy-4)) && (x<(sx+7)) && (x>(sx-5))) draw_symbol((x-sx+4)*3,(y-sy+3)*2,' '); if((nyl<(sy+4)) && (nyl>(sy-4)) && (x<(sx+6)) && (x>(sx-6))) draw_symbol((x-sx+5)*3,(nyl-sy+3)*2,'>'); } else { move(y+1,x); addch(' '); move(nyl+1,x+1); addch('>'); } refresh(); retval+=fall(mx,my,x+1,nyl,sx,sy,howdead); retval+=check(mx,my,x-1,y,1,0,sx,sy,howdead); if(!lastcol && screen[nyl][x+1] == '@') { strcpy(howdead,"a speeding arrow"); return(1); } if(!lastcol && screen[nyl][x+1] == 'M') { *mx = *my = -2; screen[nyl][x+1] = ' '; } } if(nxu != -1 && screen[y][nxu] != ' ') nxu = -1; if(y < NOOFROWS-1 && (screen[y+1][x] == '^') && (nxu >= 0) && (screen[y][x] != '^')) /* balloon rises? */ { screen[y+1][x] = ' '; screen[y][nxu] = '^'; if(!debug_disp) { if((y<(sy+3)) && (y>(sy-5)) && (x>(sx-6)) && (x<(sx+6))) draw_symbol((x-sx+5)*3,(y-sy+4)*2,' '); if((y<(sy+4)) && (y>(sy-4)) && (nxu>(sx-6)) && (nxu<(sx+6))) draw_symbol((nxu-sx+5)*3,(y-sy+3)*2,'^'); } else { move(y+2,x+1); addch(' '); move(y+1,nxu+1); addch('^'); } refresh(); retval+=fall(mx,my,nxu ,y-1,sx,sy,howdead); retval+=check(mx,my,x,y+1,0,-1,sx,sy,howdead); } if(retval>0) return(1); return(0); } --------pins----------------pins----------------pins------------------------ -- John Woods, Charles River Data Systems, (617) 626-1101 jfw@eddie.MIT.EDU, john@frog.UUCP, ...!decvax!frog!john