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.
This commit is contained in:
cohrs
2003-05-20 02:05:45 +00:00
parent 619da67425
commit 14c12765a0
5 changed files with 92 additions and 1 deletions

View File

@@ -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

View File

@@ -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 ### */

View File

@@ -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,

View File

@@ -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);

View File

@@ -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;