From: PatR Date: Tue, 31 May 2016 00:56:47 +0000 (-0700) Subject: getpos moving to 'cmap' characters X-Git-Tag: NetHack-3.6.1_RC01~722 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7404597ac547ba42b48916745ec6c8330c4ca33a;p=nethack getpos moving to 'cmap' characters While testing something I noticed that moving the cursor to visible '^' by typing '^' while getpos was asking me to pick a location, it didn't always cycle through all visible traps. The most straightforward culprit was after trap detection (via confused gold detection, not ^F) had found a trap door or level teleporter in a closet that itself was a secret corridor spot. But it turned out to be any location that hadn't been seen yet. This is a substantial overhaul of the relevant code and so far works for all the cases I've tried, but there are bound to be cases I haven't tried yet and those may or may not work correctly. There's also a bunch of formatting cleanup, and some simplification of the m/M/o/O/d/D/x/X handling. --- diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 313454491..fbb8b5a9b 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -272,6 +272,8 @@ reviving one of a stack of N corpses in a shop charged a usage fee for all N; remaining N-1 were owned by hero if carried but by shop if on floor gremlin wailing in agony should wake up nearby monsters add more lighting variance to the second bigroom variant +when getpost was picking a location, typing '^' to move to the next known trap + skipped some detected traps if their location was unseen Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository diff --git a/src/do_name.c b/src/do_name.c index 153002e76..5d5c419c6 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -64,10 +64,15 @@ const char *goal; putstr(tmpwin, 0, "Use m or M to move the cursor to next monster."); if (!iflags.terrainmode || (iflags.terrainmode & TER_OBJ) != 0) putstr(tmpwin, 0, "Use o or O to move the cursor to next object."); - putstr(tmpwin, 0, /* d,D are useful regardless of terrainmode */ - "Use d or D to move the cursor to next door or doorway."); + if (!iflags.terrainmode || (iflags.terrainmode & TER_MAP) != 0) { + /* both of these are primarily useful when choosing a travel + destination for the '_' command */ + putstr(tmpwin, 0, + "Use d or D to move the cursor to next door or doorway."); + putstr(tmpwin, 0, + "Use x or X to move the cursor to unexplored location."); + } if (!iflags.terrainmode) { - putstr(tmpwin, 0, "Use x or X to move the cursor to unexplored location."); if (getpos_hilitefunc) putstr(tmpwin, 0, "Use $ to display valid locations."); putstr(tmpwin, 0, "Use # to toggle automatic description."); @@ -134,10 +139,11 @@ enum gloctypes { }; -#define IS_UNEXPLORED_LOC(x,y) (isok((x), (y)) \ - && glyph_is_cmap(levl[(x)][(y)].glyph) \ - && glyph_to_cmap(levl[(x)][(y)].glyph) == S_stone \ - && !levl[(x)][(y)].seenv) +#define IS_UNEXPLORED_LOC(x,y) \ + (isok((x), (y)) \ + && glyph_is_cmap(levl[(x)][(y)].glyph) \ + && glyph_to_cmap(levl[(x)][(y)].glyph) == S_stone \ + && !levl[(x)][(y)].seenv) STATIC_OVL boolean gather_locs_interesting(x,y, gloc) @@ -150,28 +156,35 @@ int x,y, gloc; switch (gloc) { default: - case GLOC_MONS: return (glyph_is_monster(glyph) - && glyph != monnum_to_glyph(PM_LONG_WORM_TAIL)); - case GLOC_OBJS: return (glyph_is_object(glyph) - && glyph != objnum_to_glyph(BOULDER) - && glyph != objnum_to_glyph(ROCK)); - case GLOC_DOOR: return (glyph_is_cmap(glyph) - && (is_cmap_door(glyph_to_cmap(glyph)) - || is_cmap_drawbridge(glyph_to_cmap(glyph)) - || glyph_to_cmap(glyph) == S_ndoor)); - case GLOC_EXPLORE: return (glyph_is_cmap(glyph) - && (is_cmap_door(glyph_to_cmap(glyph)) - || is_cmap_drawbridge(glyph_to_cmap(glyph)) - || glyph_to_cmap(glyph) == S_ndoor - || glyph_to_cmap(glyph) == S_room - || glyph_to_cmap(glyph) == S_darkroom - || glyph_to_cmap(glyph) == S_corr - || glyph_to_cmap(glyph) == S_litcorr) - && (IS_UNEXPLORED_LOC(x+1,y) - || IS_UNEXPLORED_LOC(x-1,y) - || IS_UNEXPLORED_LOC(x,y+1) - || IS_UNEXPLORED_LOC(x,y-1))); + case GLOC_MONS: + /* unlike '/M', this skips monsters revealed by + warning glyphs and remembered unseen ones */ + return (glyph_is_monster(glyph) + && glyph != monnum_to_glyph(PM_LONG_WORM_TAIL)); + case GLOC_OBJS: + return (glyph_is_object(glyph) + && glyph != objnum_to_glyph(BOULDER) + && glyph != objnum_to_glyph(ROCK)); + case GLOC_DOOR: + return (glyph_is_cmap(glyph) + && (is_cmap_door(glyph_to_cmap(glyph)) + || is_cmap_drawbridge(glyph_to_cmap(glyph)) + || glyph_to_cmap(glyph) == S_ndoor)); + case GLOC_EXPLORE: + return (glyph_is_cmap(glyph) + && (is_cmap_door(glyph_to_cmap(glyph)) + || is_cmap_drawbridge(glyph_to_cmap(glyph)) + || glyph_to_cmap(glyph) == S_ndoor + || glyph_to_cmap(glyph) == S_room + || glyph_to_cmap(glyph) == S_darkroom + || glyph_to_cmap(glyph) == S_corr + || glyph_to_cmap(glyph) == S_litcorr) + && (IS_UNEXPLORED_LOC(x + 1, y) + || IS_UNEXPLORED_LOC(x - 1, y) + || IS_UNEXPLORED_LOC(x, y + 1) + || IS_UNEXPLORED_LOC(x, y - 1))); } + /*NOTREACHED*/ return FALSE; } @@ -199,10 +212,8 @@ int gloc; for (pass = 0; pass < 2; pass++) { for (x = 1; x < COLNO; x++) for (y = 0; y < ROWNO; y++) { - /* unlike '/M', this skips monsters revealed by - warning glyphs and remembered invisible ones */ if ((x == u.ux && y == u.uy) - || gather_locs_interesting(x,y, gloc)) { + || gather_locs_interesting(x, y, gloc)) { if (!pass) { ++*cnt_p; } else { @@ -317,13 +328,14 @@ coord *ccp; boolean force; const char *goal; { + static const char pick_chars[] = ".,;:", + mMoOdDxX[] = "mMoOdDxX"; + const char *cp; int result = 0; int cx, cy, i, c; int sidx, tx, ty; boolean msg_given = TRUE; /* clear message window by default */ boolean show_goal_msg = FALSE; - static const char pick_chars[] = ".,;:"; - const char *cp; boolean hilite_state = FALSE; coord *garr[NUM_GLOCS] = DUMMY; int gcount[NUM_GLOCS] = DUMMY; @@ -437,6 +449,10 @@ const char *goal; } goto nxtc; } else if (c == '#') { + /* unfortunately, using '#' as a command means we can't move + cursor to sinks, iron bars, and poison clouds; perhaps + when autodescribe is already on, next '#' should try to + move to '#' rather than to toggle off? (or ask; ick...) */ iflags.autodescribe = !iflags.autodescribe; pline("Automatic description %sis %s.", flags.verbose ? "of features under cursor " : "", @@ -446,29 +462,25 @@ const char *goal; msg_given = TRUE; goto nxtc; } else if (c == '@') { /* return to hero's spot */ - /* reset 'm','M' and 'o','O'; otherwise, there's no way for player + /* reset 'm&M', 'o&O', &c; otherwise, there's no way for player to achieve that except by manually cycling through all spots */ for (i = 0; i < NUM_GLOCS; i++) gidx[i] = 0; cx = u.ux; cy = u.uy; goto nxtc; - } else if (c == 'm' || c == 'M' /* nearest or farthest monster */ - || c == 'o' || c == 'O' /* nearest or farthest object */ - || c == 'x' || c == 'X' /* unexplored area */ - || c == 'd' || c == 'D') { /* door/doorway */ - int gloc = (c == 'o' || c == 'O') ? GLOC_OBJS - : (c == 'd' || c == 'D') ? GLOC_DOOR - : (c == 'x' || c == 'X') ? GLOC_EXPLORE - : GLOC_MONS; + } else if ((cp = index(mMoOdDxX, c)) != 0) { /* 'm|M', 'o|O', &c */ + /* nearest or farthest monster or object or door or unexplored */ + int gtmp = (int) (cp - mMoOdDxX), /* 0..7 */ + gloc = gtmp >> 1; /* 0..3 */ if (!garr[gloc]) { gather_locs(&garr[gloc], &gcount[gloc], gloc); gidx[gloc] = 0; /* garr[][0] is hero's spot */ } - if (c == 'm' || c == 'o' || c == 'd' || c == 'x') { + if (!(gtmp & 1)) { /* c=='m' || c=='o' || c=='d' || c=='x') */ gidx[gloc] = (gidx[gloc] + 1) % gcount[gloc]; - } else { + } else { /* c=='M' || c=='O' || c=='D' || c=='X') */ if (--gidx[gloc] < 0) gidx[gloc] = gcount[gloc] - 1; } @@ -481,9 +493,17 @@ const char *goal; int pass, lo_x, lo_y, hi_x, hi_y, k = 0; (void) memset((genericptr_t) matching, 0, sizeof matching); - for (sidx = 1; sidx < MAXPCHARS; sidx++) + for (sidx = 1; sidx < MAXPCHARS; sidx++) { /* [0] left as 0 */ + if (IS_DOOR(sidx) || IS_WALL(sidx) + || sidx == SDOOR || sidx == SCORR + || glyph_to_cmap(k) == S_room + || glyph_to_cmap(k) == S_darkroom + || glyph_to_cmap(k) == S_corr + || glyph_to_cmap(k) == S_litcorr) + continue; if (c == defsyms[sidx].sym || c == (int) showsyms[sidx]) matching[sidx] = (char) ++k; + } if (k) { for (pass = 0; pass <= 1; pass++) { /* pass 0: just past current pos to lower right; @@ -494,35 +514,39 @@ const char *goal; lo_x = (pass == 0 && ty == lo_y) ? cx + 1 : 1; hi_x = (pass == 1 && ty == hi_y) ? cx : COLNO - 1; for (tx = lo_x; tx <= hi_x; tx++) { - /* look at dungeon feature, not at - user-visible glyph */ - k = back_to_glyph(tx, ty); - /* uninteresting background glyph */ + /* first, look at what is currently visible + (might be monster) */ + k = glyph_at(tx, ty); if (glyph_is_cmap(k) - && (IS_DOOR(levl[tx][ty].typ) - || glyph_to_cmap(k) == S_room - || glyph_to_cmap(k) == S_darkroom - || glyph_to_cmap(k) == S_corr - || glyph_to_cmap(k) == S_litcorr)) { - /* what hero remembers to be at tx,ty */ - k = glyph_at(tx, ty); + && matching[glyph_to_cmap(k)]) + goto foundc; + /* next, try glyph that's remembered here + (might be trap or object) */ + if (level.flags.hero_memory + /* !terrainmode: don't move to remembered + trap or object if not currently shown */ + && !iflags.terrainmode) { + k = levl[tx][ty].glyph; + if (glyph_is_cmap(k) + && matching[glyph_to_cmap(k)]) + goto foundc; } - if (glyph_is_cmap(k) - && matching[glyph_to_cmap(k)] - && (levl[tx][ty].seenv - || iflags.terrainmode) - && !IS_WALL(levl[tx][ty].typ) - && levl[tx][ty].typ != SDOOR - && glyph_to_cmap(k) != S_room - && glyph_to_cmap(k) != S_corr - && glyph_to_cmap(k) != S_litcorr) { - cx = tx, cy = ty; - if (msg_given) { - clear_nhwindow(WIN_MESSAGE); - msg_given = FALSE; - } - goto nxtc; + /* last, try actual terrain here (shouldn't + we be using lastseentyp[][] instead?) */ + if (levl[tx][ty].seenv) { + k = back_to_glyph(tx, ty); + if (glyph_is_cmap(k) + && matching[glyph_to_cmap(k)]) + goto foundc; } + continue; + foundc: + cx = tx, cy = ty; + if (msg_given) { + clear_nhwindow(WIN_MESSAGE); + msg_given = FALSE; + } + goto nxtc; } /* column */ } /* row */ } /* pass */ @@ -545,10 +569,8 @@ const char *goal; } /* !quitchars */ if (force) goto nxtc; - if (!iflags.terrainmode) { - pline("Done."); - msg_given = FALSE; /* suppress clear */ - } + pline("Done."); + msg_given = FALSE; /* suppress clear */ cx = -1; cy = 0; result = 0; /* not -1 */