diff --git a/doc/fixes37.0 b/doc/fixes37.0
index bcab3705b..76b2a48ed 100644
--- a/doc/fixes37.0
+++ b/doc/fixes37.0
@@ -642,6 +642,10 @@ blessed scroll of remove curse read while confused blesses or curses any
can now use m
to try to move to an adjacent boulder's spot without
pushing it; hero poly'd into a giant or a tiny creature or carrying so
little as to be able to squeeze there will succeed, others will fail
+breaching a shop wall, using locking magic to put a door there, then unlocking
+ that door yielded a situation where subsequent shop damage repair
+ produced invalid map data which resulted in an impossible() warning
+ about "wall_angle: unknown" during map display
Fixes to 3.7.0-x Problems that Were Exposed Via git Repository
diff --git a/include/mextra.h b/include/mextra.h
index bd47aae2d..41b519eeb 100644
--- a/include/mextra.h
+++ b/include/mextra.h
@@ -69,7 +69,9 @@
#define GD_DESTROYGOLD 0x02
struct fakecorridor {
- xchar fx, fy, ftyp;
+ xchar fx, fy;
+ schar ftyp; /* from struct rm's typ */
+ uchar flags; /* also from struct rm; an unsigned 5-bit field there */
};
struct egd {
diff --git a/include/patchlevel.h b/include/patchlevel.h
index a98cf6236..bffc5daea 100644
--- a/include/patchlevel.h
+++ b/include/patchlevel.h
@@ -17,7 +17,7 @@
* Incrementing EDITLEVEL can be used to force invalidation of old bones
* and save files.
*/
-#define EDITLEVEL 42
+#define EDITLEVEL 43
/*
* Development status possibilities.
diff --git a/include/rm.h b/include/rm.h
index 1a3ab335d..a875aa6d2 100644
--- a/include/rm.h
+++ b/include/rm.h
@@ -114,20 +114,27 @@ enum levl_typ_types {
* a secret door is revealed, the door gets set to D_CLOSED iff
* it isn't set to D_LOCKED (see cvt_sdoor_to_door() in detect.c).
*
- * D_TRAPPED conflicts with W_NONDIGGABLE but the latter is not
- * expected to be used on door locations.
+ * D_LOCKED conflicts with W_NONDIGGABLE but the latter is not
+ * expected to be used on door locations. D_TRAPPED conflicts
+ * with W_NONPASSWALL but secret doors aren't trapped.
+ * D_SECRET would not fit within struct rm's 5-bit 'flags' field.
*/
/*
* The 5 possible states of doors.
+ * For historical reasons they are numbered as mask bits rather than 0..4.
+ * The trapped flag is OR'd onto the state and only valid if that state
+ * is closed or locked.
+ * The no-door state allows egress when moving diagonally, others do not.
*/
-#define D_NODOOR 0
-#define D_BROKEN 1
-#define D_ISOPEN 2
-#define D_CLOSED 4
-#define D_LOCKED 8
-#define D_TRAPPED 16
-#define D_SECRET 32 /* only used by sp_lev.c, NOT in rm-struct */
+#define D_NODOOR 0x00
+#define D_BROKEN 0x01
+#define D_ISOPEN 0x02
+#define D_CLOSED 0x04
+#define D_LOCKED 0x08
+
+#define D_TRAPPED 0x10
+#define D_SECRET 0x20 /* only used by sp_lev.c, NOT in rm-struct */
/*
* Thrones should only be looted once.
@@ -213,7 +220,7 @@ enum levl_typ_types {
*/
struct rm {
int glyph; /* what the hero thinks is there */
- schar typ; /* what is really there */
+ schar typ; /* what is really there [why is this signed?] */
uchar seenv; /* seen vector */
Bitfield(flags, 5); /* extra information for typ */
Bitfield(horizontal, 1); /* wall/door/etc is horiz. (more typ info) */
@@ -322,7 +329,8 @@ struct damage {
struct damage *next;
long when, cost;
coord place;
- schar typ;
+ schar typ; /* from struct rm */
+ uchar flags; /* also from struct rm; an unsigned 5-bit field there */
};
/* for bones levels: identify the dead character, who might have died on
diff --git a/src/display.c b/src/display.c
index c3ac520d5..60b140bb3 100644
--- a/src/display.c
+++ b/src/display.c
@@ -2971,16 +2971,44 @@ t_warn(struct rm *lev)
static const char warn_str[] = "wall_angle: %s: case %d: seenv = 0x%x";
const char *wname;
- if (lev->typ == TUWALL)
+ /* 3.7: non-T_wall cases added after shop repair (via breaching a wall,
+ using locking magic to put a door there, then unlocking the door;
+ D_CLOSED carried over to the wall) triggered warning for "unknown" */
+ switch (lev->typ) {
+ case TUWALL:
wname = "tuwall";
- else if (lev->typ == TLWALL)
+ break;
+ case TLWALL:
wname = "tlwall";
- else if (lev->typ == TRWALL)
+ break;
+ case TRWALL:
wname = "trwall";
- else if (lev->typ == TDWALL)
+ break;
+ case TDWALL:
wname = "tdwall";
- else
+ break;
+ case VWALL:
+ wname = "vwall";
+ break;
+ case HWALL:
+ wname = "hwall";
+ break;
+ case TLCORNER:
+ wname = "tlcorner";
+ break;
+ case TRCORNER:
+ wname = "trcorner";
+ break;
+ case BLCORNER:
+ wname = "blcorner";
+ break;
+ case BRCORNER:
+ wname = "brcorner";
+ break;
+ default:
wname = "unknown";
+ break;
+ }
impossible(warn_str, wname, lev->wall_info & WM_MASK,
(unsigned int) lev->seenv);
}
diff --git a/src/shk.c b/src/shk.c
index d54b9b7a2..d8e84ffb0 100644
--- a/src/shk.c
+++ b/src/shk.c
@@ -2720,9 +2720,10 @@ append_honorific(char *buf)
{
/* (chooses among [0]..[3] normally; [1]..[4] after the
Wizard has been killed or invocation ritual performed) */
- static const char *const honored[] = { "good", "honored", "most gracious",
- "esteemed",
- "most renowned and sacred" };
+ static const char *const honored[] = {
+ "good", "honored", "most gracious", "esteemed",
+ "most renowned and sacred"
+ };
Strcat(buf, honored[rn2(SIZE(honored) - 1) + u.uevent.udemigod]);
if (is_vampire(g.youmonst.data))
@@ -3481,6 +3482,7 @@ add_damage(
tmp_dam->place.y = y;
tmp_dam->cost = cost;
tmp_dam->typ = levl[x][y].typ;
+ tmp_dam->flags = levl[x][y].flags;
tmp_dam->next = g.level.damagelist;
g.level.damagelist = tmp_dam;
/* If player saw damage, display as a wall forever */
@@ -3570,7 +3572,7 @@ discard_damage_struct(struct damage *dam)
if (prev)
prev->next = dam->next;
}
- (void) memset(dam, 0, sizeof(struct damage));
+ (void) memset(dam, 0, sizeof *dam);
free((genericptr_t) dam);
}
@@ -3802,10 +3804,14 @@ repair_damage(
stop_picking = picking_at(x, y);
/* door or wall repair; trap, if any, is now gone;
- restore original terrain type and move any items away */
+ restore original terrain type and move any items away;
+ rm.doormask and rm.wall_info are both overlaid on rm.flags
+ so the new flags value needs to match the restored typ */
levl[x][y].typ = tmp_dam->typ;
if (IS_DOOR(tmp_dam->typ))
levl[x][y].doormask = D_CLOSED; /* arbitrary */
+ else /* not a door; set rm.wall_info or whatever old flags are relevant */
+ levl[x][y].flags = tmp_dam->flags;
litter = litter_getpos(&k, x, y, shkp);
litter_scatter(litter, k, x, y, shkp);
diff --git a/src/vault.c b/src/vault.c
index 874b0733c..69e81d90c 100644
--- a/src/vault.c
+++ b/src/vault.c
@@ -83,6 +83,7 @@ clear_fcorr(struct monst *grd, boolean forceshow)
if (lev->typ == CORR && cansee(fcx, fcy))
sawcorridor = TRUE;
lev->typ = egrd->fakecorr[fcbeg].ftyp;
+ lev->flags = egrd->fakecorr[fcbeg].flags;
if (IS_STWALL(lev->typ)) {
/* destroy any trap here (pit dug by you, hole dug via
wand while levitating or by monster, bear trap or land
@@ -506,25 +507,29 @@ invault(void)
EGD(guard)->fcbeg = 0;
EGD(guard)->fakecorr[0].fx = x;
EGD(guard)->fakecorr[0].fy = y;
- if (IS_WALL(levl[x][y].typ)) {
- EGD(guard)->fakecorr[0].ftyp = levl[x][y].typ;
- } else { /* the initial guard location is a dug door */
+ EGD(guard)->fakecorr[0].ftyp = levl[x][y].typ;
+ EGD(guard)->fakecorr[0].flags = levl[x][y].flags;
+ if (!IS_WALL(levl[x][y].typ)) {
+ /* the initial guard location happens to be a dug door */
int vlt = EGD(guard)->vroom;
xchar lowx = g.rooms[vlt].lx, hix = g.rooms[vlt].hx;
xchar lowy = g.rooms[vlt].ly, hiy = g.rooms[vlt].hy;
+ int typ = levl[x][y].typ;
if (x == lowx - 1 && y == lowy - 1)
- EGD(guard)->fakecorr[0].ftyp = TLCORNER;
+ typ = TLCORNER;
else if (x == hix + 1 && y == lowy - 1)
- EGD(guard)->fakecorr[0].ftyp = TRCORNER;
+ typ = TRCORNER;
else if (x == lowx - 1 && y == hiy + 1)
- EGD(guard)->fakecorr[0].ftyp = BLCORNER;
+ typ = BLCORNER;
else if (x == hix + 1 && y == hiy + 1)
- EGD(guard)->fakecorr[0].ftyp = BRCORNER;
+ typ = BRCORNER;
else if (y == lowy - 1 || y == hiy + 1)
- EGD(guard)->fakecorr[0].ftyp = HWALL;
+ typ = HWALL;
else if (x == lowx - 1 || x == hix + 1)
- EGD(guard)->fakecorr[0].ftyp = VWALL;
+ typ = VWALL;
+
+ EGD(guard)->fakecorr[0].ftyp = typ;
}
levl[x][y].typ = DOOR;
levl[x][y].doormask = D_NODOOR;
@@ -581,14 +586,19 @@ wallify_vault(struct monst *grd)
if ((trap = t_at(x, y)) != 0)
deltrap(trap);
if (x == lox)
- typ =
- (y == loy) ? TLCORNER : (y == hiy) ? BLCORNER : VWALL;
+ typ = (y == loy) ? TLCORNER
+ : (y == hiy) ? BLCORNER
+ : VWALL;
else if (x == hix)
- typ =
- (y == loy) ? TRCORNER : (y == hiy) ? BRCORNER : VWALL;
+ typ = (y == loy) ? TRCORNER
+ : (y == hiy) ? BRCORNER
+ : VWALL;
else /* not left or right side, must be top or bottom */
typ = HWALL;
levl[x][y].typ = typ;
+ /* FIXME? both rm.doormask and rm.wall_info overlay
+ rm.flags, so clearing doormask clobbers wall_info
+ rather than reset it to the proper value. Do we care? */
levl[x][y].doormask = 0;
/*
* hack: player knows walls are restored because of the
@@ -789,6 +799,7 @@ gd_move(struct monst *grd)
verbalize("You've been warned, knave!");
mnexto(grd);
levl[m][n].typ = egrd->fakecorr[0].ftyp;
+ levl[m][n].flags = egrd->fakecorr[0].flags;
newsym(m, n);
grd->mpeaceful = 0;
return -1;
@@ -805,6 +816,7 @@ gd_move(struct monst *grd)
n = grd->my;
(void) rloc(grd, TRUE);
levl[m][n].typ = egrd->fakecorr[0].ftyp;
+ levl[m][n].flags = egrd->fakecorr[0].flags;
newsym(m, n);
grd->mpeaceful = 0;
letknow:
@@ -832,8 +844,8 @@ gd_move(struct monst *grd)
if (egrd->fcend > 1) {
if (egrd->fcend > 2 && in_fcorridor(grd, grd->mx, grd->my)
&& !egrd->gddone && !in_fcorridor(grd, u.ux, u.uy)
- && levl[egrd->fakecorr[0].fx][egrd->fakecorr[0].fy].typ
- == egrd->fakecorr[0].ftyp) {
+ && (levl[egrd->fakecorr[0].fx][egrd->fakecorr[0].fy].typ
+ == egrd->fakecorr[0].ftyp)) {
pline("%s, confused, disappears.", noit_Monnam(grd));
disappear_msg_seen = TRUE;
goto cleanup;
@@ -902,7 +914,8 @@ gd_move(struct monst *grd)
for (ny = y - 1; ny <= y + 1; ny++) {
if ((nx == x || ny == y) && (nx != x || ny != y)
&& isok(nx, ny)) {
- typ = (crm = &levl[nx][ny])->typ;
+ crm = &levl[nx][ny];
+ typ = crm->typ;
if (!IS_STWALL(typ) && !IS_POOL(typ)) {
if (in_fcorridor(grd, nx, ny))
goto nextnxy;
@@ -914,16 +927,11 @@ gd_move(struct monst *grd)
egrd->gddone = 1;
if (ACCESSIBLE(typ))
goto newpos;
-#ifdef STUPID
- if (typ == SCORR)
- crm->typ = CORR;
- else
- crm->typ = DOOR;
-#else
crm->typ = (typ == SCORR) ? CORR : DOOR;
-#endif
if (crm->typ == DOOR)
crm->doormask = D_NODOOR;
+ else
+ crm->flags = 0;
goto proceed;
}
}
@@ -971,6 +979,7 @@ gd_move(struct monst *grd)
break;
}
crm->typ = CORR;
+ crm->flags = 0;
proceed:
newspot = TRUE;
unblock_point(nx, ny); /* doesn't block light */
@@ -979,11 +988,15 @@ gd_move(struct monst *grd)
if ((nx != gx || ny != gy) || (grd->mx != gx || grd->my != gy)) {
fcp = &(egrd->fakecorr[egrd->fcend]);
+ /* fakecorr overflow does not occur because egrd->fakecorr[]
+ is too small, but it has occurred when the same are
+ put into it repeatedly for some as yet unexplained reason */
if (egrd->fcend++ == FCSIZ)
panic("fakecorr overflow");
fcp->fx = nx;
fcp->fy = ny;
fcp->ftyp = typ;
+ fcp->flags = crm->flags;
} else if (!egrd->gddone) {
/* We're stuck, so try to find a new destination. */
if (!find_guard_dest(grd, &egrd->gdx, &egrd->gdy)