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)