]> granicus.if.org Git - nethack/commitdiff
U433 - infinite loop with place_branch
authorcohrs <cohrs>
Tue, 20 May 2003 02:05:45 +0000 (02:05 +0000)
committercohrs <cohrs>
Tue, 20 May 2003 02:05:45 +0000 (02:05 +0000)
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.

doc/fixes34.2
include/extern.h
src/mkmap.c
src/sp_lev.c
util/lev_comp.y

index f80ba3b72cd04b0c9b544160c5938312b724e40a..49eba3559233f9a5d6911c464a7b2caa54ec1beb 100644 (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
index 2356a1950adfbe391d1fe4f8502fd8794bbe94b0..24d9538f2a7c606f40e98e975803de9e5928aa2a 100644 (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 ### */
 
index f9a68d68bd1ca63e8a9f1fc7870276aa6cfbc33d..7b94dfa33640486ca0e7ad116638bb1b8e8066de 100644 (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,
index 5aa1027423227279ce9cb017a6cf2cf99afafd80..435609f3e5e284595f82ac8a315b73d189dab005 100644 (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);
index e4cb5100003527dc703987e9ee011f2bdd186484..a12c7cd648e85a3a832a7084f6e352105df1c38a 100644 (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;