From: cohrs Date: Tue, 20 May 2003 02:05:45 +0000 (+0000) Subject: U433 - infinite loop with place_branch X-Git-Tag: MOVE2GIT~1979 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=14c12765a00b32e5a22292cb318ad395d9bdf830;p=nethack U433 - infinite loop with place_branch This solution is mostly a band-aid. Make sure information set by join_map that is overlaid by the MAP is cleared out. This ensures that place_branch will never consider invalid data. A new function, remove_rooms(), with a helper, remove_room(), takes care of this, but only for rooms created by join_map, which addresses the only known case that causes this problem. There's a possibility that some other strange behavior, especially in minetn-6, will be fixed by this as well. The problem of disconnected caves on minetn-6 is not yet addressed. Also, add a check to lev_comp.y to make sure the required fg semantics of joined levels (fg must be ROOM or CORR) are actually met. Doesn't affect any levels currently included in the distro, but might address levels others are trying to make. --- diff --git a/doc/fixes34.2 b/doc/fixes34.2 index f80ba3b72..49eba3559 100644 --- a/doc/fixes34.2 +++ b/doc/fixes34.2 @@ -68,6 +68,7 @@ poison missiles were unintentionally more likely to inflict "deadly poison" provide feedback when going invisible after eating a stalker killer on tombstone had no prefix for starvation/exhaustion case ensure proper message ordering for boulder trap messages +clean up data set by join_map that is overlaid by MAPs on special levels Platform- and/or Interface-Specific Fixes diff --git a/include/extern.h b/include/extern.h index 2356a1950..24d9538f2 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1011,6 +1011,7 @@ E void NDECL(mkinvokearea); /* ### mkmap.c ### */ void FDECL(flood_fill_rm, (int,int,int,BOOLEAN_P,BOOLEAN_P)); +void FDECL(remove_rooms, (int,int,int,int)); /* ### mkmaze.c ### */ diff --git a/src/mkmap.c b/src/mkmap.c index f9a68d68b..7b94dfa33 100644 --- a/src/mkmap.c +++ b/src/mkmap.c @@ -17,6 +17,7 @@ STATIC_DCL void FDECL(pass_three,(SCHAR_P,SCHAR_P)); STATIC_DCL void NDECL(wallify_map); STATIC_DCL void FDECL(join_map,(SCHAR_P,SCHAR_P)); STATIC_DCL void FDECL(finish_map,(SCHAR_P,SCHAR_P,XCHAR_P,XCHAR_P)); +STATIC_DCL void FDECL(remove_room,(int)); void FDECL(mkmap, (lev_init *)); char *new_locations; @@ -361,13 +362,91 @@ finish_map(fg_typ, bg_typ, lit, walled) levl[i][j].lit = TRUE; } +/* + * When level processed by join_map is overlaid by a MAP, some rooms may no + * longer be valid. All rooms in the region lx <= x < hx, ly <= y < hy are + * removed. Rooms partially in the region are truncated. This function + * must be called before the REGIONs or ROOMs of the map are processed, or + * those rooms will be removed as well. Assumes roomno fields in the + * region are already cleared, and roomno and irregular fields outside the + * region are all set. + */ +void +remove_rooms(lx, ly, hx, hy) + int lx, ly, hx, hy; +{ + int i; + struct mkroom *croom; + + for (i = nroom - 1; i >= 0; --i) { + croom = &rooms[i]; + if (croom->hx < lx || croom->lx >= hx || + croom->hy < ly || croom->ly >= hy) continue; /* no overlap */ + + if (croom->lx < lx || croom->hx >= hx || + croom->ly < ly || croom->hy >= hy) { /* partial overlap */ + /* TODO: ensure remaining parts of room are still joined */ + + if (!croom->irregular) impossible("regular room in joined map"); + + /* if a "donut" or even disconnected room, leave bounds alone */ + if ((croom->lx < lx && croom->hx >= hx) || + (croom->ly < ly && croom->hy >= hy)) { + continue; + } + + /* truncate the side(s) that are covered by the region */ + if (croom->lx < lx && croom->hx < hx) croom->hx = lx - 1; + if (croom->lx >= lx && croom->hx >= hx) croom->lx = hx; + if (croom->ly < ly && croom->hy < hy) croom->hy = ly - 1; + if (croom->ly >= ly && croom->hy >= hy) croom->ly = hy; + } else { + /* total overlap, remove the room */ + remove_room(i); + } + } +} + +/* + * Remove roomno from the rooms array, decrementing nroom. Also updates + * all level roomno values of affected higher numbered rooms. Assumes + * level structure contents corresponding to roomno have already been reset. + * Currently handles only the removal of rooms that have no subrooms. + */ +void +remove_room(roomno) + int roomno; +{ + struct mkroom *croom = &rooms[roomno]; + struct mkroom *maxroom = &rooms[--nroom]; + int i, j, oroomno; + + if (croom != maxroom) { + /* since the order in the array only matters for making corridors, + * copy the last room over the one being removed on the assumption + * that corridors have already been dug. */ + (void) memcpy((genericptr_t)croom, (genericptr_t)maxroom, + sizeof(struct mkroom)); + + /* since maxroom moved, update affected level roomno values */ + oroomno = nroom + ROOMOFFSET; + roomno += ROOMOFFSET; + for (i = croom->lx; i <= croom->hx; ++i) + for (j = croom->ly; j <= croom->hy; ++j) { + if (levl[i][j].roomno == oroomno) + levl[i][j].roomno = roomno; + } + } + + maxroom->hx = -1; /* just like add_room */ +} + #define N_P1_ITER 1 /* tune map generation via this value */ #define N_P2_ITER 1 /* tune map generation via this value */ #define N_P3_ITER 2 /* tune map smoothing via this value */ void mkmap(init_lev) - lev_init *init_lev; { schar bg_typ = init_lev->bg, diff --git a/src/sp_lev.c b/src/sp_lev.c index 5aa102742..435609f3e 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -2167,6 +2167,11 @@ dlb *fd; for(x = xstart; x < xstart+xsize; x++) { levl[x][y].typ = Fgetc(fd); levl[x][y].lit = FALSE; + /* clear out levl: load_common_data may set them */ + levl[x][y].flags = 0; + levl[x][y].horizontal = 0; + levl[x][y].roomno = 0; + levl[x][y].edge = 0; /* * Note: Even though levl[x][y].typ is type schar, * lev_comp.y saves it as type char. Since schar != char @@ -2198,6 +2203,8 @@ dlb *fd; has_bounds = TRUE; Map[x][y] = 1; } + if (init_lev.init_present && init_lev.joined) + remove_rooms(xstart, ystart, xstart+xsize, ystart+ysize); } Fread((genericptr_t) &n, 1, sizeof(n), fd); diff --git a/util/lev_comp.y b/util/lev_comp.y index e4cb51000..a12c7cd64 100644 --- a/util/lev_comp.y +++ b/util/lev_comp.y @@ -274,6 +274,9 @@ lev_init : /* nothing */ yyerror("Invalid background type."); init_lev.smoothed = $7; init_lev.joined = $9; + if (init_lev.joined && + init_lev.fg != CORR && init_lev.fg != ROOM) + yyerror("Invalid foreground type for joined map."); init_lev.lit = $11; init_lev.walled = $13; $$ = 1;