diff --git a/dat/wizhelp b/dat/wizhelp index 5a7252028..6b38bc8ad 100644 --- a/dat/wizhelp +++ b/dat/wizhelp @@ -17,7 +17,6 @@ Debug-Mode Quick Reference: #polyself == polymorph self #seenv == show seen vectors #stats == show memory statistics -#terrain == show map topology #timeout == look at timeout queue #vision == show vision array #wmode == show wall modes diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index 218ad1865..ccd5a19a1 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -843,8 +843,10 @@ Ride (or stop riding) a monster. Rub a lamp or a stone. .lp "#sit " Sit down. +.lp #terrain +Show bare map without displaying monsters, objects, or traps. .lp "#tip " -Tip over a container to pour out its contents. +Tip over a container (bag or box) to pour out its contents. .lp #turn Turn undead. .lp #twoweapon diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index 0cff1d0b6..3e4cbdd5d 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -33,7 +33,7 @@ \begin{document} % % input file: guidebook.mn -% $Revision: 1.118 $ $Date: 2011/12/05 09:15:45 $ +% $Revision: 1.119 $ $Date: 2011/12/05 09:35:59 $ % %.ds h0 " %.ds h1 %.ds h2 \% @@ -1053,8 +1053,10 @@ Rub a lamp or a stone. \item[\tb{\#sit}] Sit down. %.lp +\item[\tb{\#terrain}] +Show bare map without displaying monsters, objects, or traps. \item[\tb{\#tip}] -Tip over a container to pour out its contents. +Tip over a container (bag or box) to pour out its contents. %.lp \item[\tb{\#turn}] Turn undead. diff --git a/doc/fixes35.0 b/doc/fixes35.0 index 1de294c31..7f23b82f3 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -468,7 +468,7 @@ display spell retention information in the spell menu tame ghouls can eat old eggs new effect for reading a scroll of light while confused allow digging an adjacent pit with wand of digging while trapped in a pit -#terrain command for debug mode +#terrain command to show unobstructed view of map (w/o mons, objs, traps) digging can activate or disarm some types of traps some monsters can eat tins in addition to corpses to cure some ailments add Roderick Schertler's pickup_thrown patch diff --git a/include/extern.h b/include/extern.h index 1d35b8bb5..b8173a5cc 100644 --- a/include/extern.h +++ b/include/extern.h @@ -261,6 +261,7 @@ E void FDECL(find_trap, (struct trap *)); E int FDECL(dosearch0, (int)); E int NDECL(dosearch); E void NDECL(sokoban_detect); +E void FDECL(reveal_terrain, (BOOLEAN_P)); /* ### dig.c ### */ diff --git a/src/cmd.c b/src/cmd.c index c894bc30c..67193ff78 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -126,6 +126,7 @@ STATIC_PTR int NDECL(domonability); STATIC_PTR int NDECL(dooverview_or_wiz_where); #endif /* DUNGEON_OVERVIEW */ STATIC_PTR int NDECL(dotravel); +STATIC_PTR int NDECL(doterrain); # ifdef WIZARD STATIC_PTR int NDECL(wiz_wish); STATIC_PTR int NDECL(wiz_identify); @@ -142,7 +143,8 @@ STATIC_PTR int NDECL(wiz_show_vision); STATIC_PTR int NDECL(wiz_smell); STATIC_PTR int NDECL(wiz_mon_polycontrol); STATIC_PTR int NDECL(wiz_show_wmodes); -STATIC_PTR int NDECL(wiz_map_terrain); +STATIC_DCL void NDECL(wiz_map_levltyp); +STATIC_DCL void NDECL(wiz_levltyp_legend); #if defined(__BORLANDC__) && !defined(_WIN32) extern void FDECL(show_borlandc_stats, (winid)); #endif @@ -820,9 +822,9 @@ wiz_show_wmodes(VOID_ARGS) return 0; } -/* #terrain command */ -STATIC_PTR int -wiz_map_terrain(VOID_ARGS) +/* wizard mode variant of #terrain; internal levl[][].typ values in base-36 */ +STATIC_OVL void +wiz_map_levltyp(VOID_ARGS) { winid win; int x, y, terrain; @@ -921,10 +923,91 @@ wiz_map_terrain(VOID_ARGS) } display_nhwindow(win, TRUE); - /* TODO? create legend of levl[][].typ codes and allow switching - back and forth between it and coded map display */ destroy_nhwindow(win); - return 0; + return; +} + +/* temporary? hack, since level type codes aren't the same as screen + symbols and only the latter have easily accessible descriptions */ +static const char *levltyp[] = { + "stone", + "vertical wall", + "horizontal wall", + "top-left corner wall", + "top-right corner wall", + "bottom-left corner wall", + "bottom-right corner wall", + "cross wall", + "tee-up wall", + "tee-down wall", + "tee-left wall", + "tee-right wall", + "drawbridge wall", + "tree", + "secret door", + "secret corridor", + "pool", + "moat", + "water", + "drawbridge up", + "lava pool", + "iron bars", + "door", + "corridor", + "room", + "stairs", + "ladder", + "fountain", + "throne", + "sink", + "grave", + "altar", + "ice", + "drawbridge down", + "air", + "cloud", + /* not a real terrain type, but used for undiggable stone + by wiz_map_levltyp() */ + "unreachable/undiggable", + /* padding in case the number of entries above is odd */ + "" +}; + +/* explanation of base-36 output from wiz_map_levltyp() */ +STATIC_OVL void +wiz_levltyp_legend(VOID_ARGS) +{ + winid win; + int i, j, last, c; + const char *dsc, *fmt; + char buf[BUFSZ]; + + win = create_nhwindow(NHW_TEXT); + putstr(win, 0, "#terrain encodings:"); + putstr(win, 0, ""); + fmt = " %c - %-28s"; /* TODO: include tab-separated variant for win32 */ + *buf = '\0'; + /* output in pairs, left hand column holds [0],[1],...,[N/2-1] + and right hand column holds [N/2],[N/2+1],...,[N-1]; + N ('last') will always be even, and may or may not include + the empty string entry to pad out the final pair, depending + upon how many other entries are present in levltyp[] */ + last = SIZE(levltyp) & ~1; + for (i = 0; i < last / 2; ++i) + for (j = i; j < last; j += last / 2) { + dsc = levltyp[j]; + c = !*dsc ? ' ' : !strncmp(dsc, "unreachable", 11) ? '*' : + /* same int-to-char conversion as wiz_map_levltyp() */ + (j < 10) ? '0' + j : (j < 36) ? 'a' + j - 10 : 'A' + j - 36; + Sprintf(eos(buf), fmt, c, dsc); + if (j > i) { + putstr(win, 0, buf); + *buf = '\0'; + } + } + display_nhwindow(win, TRUE); + destroy_nhwindow(win); + return; } /* #wizsmell command - test usmellmon(). */ @@ -983,6 +1066,71 @@ wiz_rumor_check(VOID_ARGS) } #endif /* WIZARD */ +/* #terrain command */ +STATIC_PTR int +doterrain(VOID_ARGS) +{ + int which = 1; /* show known map, ala crawl's '|' command */ + + if (discover || wizard) { + /* explore mode #terrain: choose between known map and full map; + wizard mode #terrain: choose between known map, full map, + a dump of the internal levl[][].typ codes w/ level flags, + and a legend for the levl[][].typ codes */ + winid men; + menu_item *sel; + anything any; + int n; + + men = create_nhwindow(NHW_MENU); + any = zeroany; + any.a_int = 1; + add_menu(men, NO_GLYPH, &any, 0, 0, ATR_NONE, + "known map without monsters, objects, and traps", + MENU_SELECTED); + any.a_int = 2; + add_menu(men, NO_GLYPH, &any, 0, 0, ATR_NONE, + "full map without monsters, objects, and traps", + MENU_UNSELECTED); +#ifdef WIZARD + if (wizard) { + any.a_int = 3; + add_menu(men, NO_GLYPH, &any, 0, 0, ATR_NONE, + "internal levl[][].typ codes in base-36", + MENU_UNSELECTED); + any.a_int = 4; + add_menu(men, NO_GLYPH, &any, 0, 0, ATR_NONE, + "legend of base-36 levl[][].typ codes", + MENU_UNSELECTED); + } +#endif + end_menu(men, "View which?"); + + n = select_menu(men, PICK_ONE, &sel); + destroy_nhwindow(men); + /* + * n < 0: player used ESC to cancel; + * n == 0: preselected entry was explicitly chosen and got toggled off; + * n == 1: preselected entry was implicitly chosen via |; + * n == 2: another entry was explicitly chosen, so skip preselected one + */ + which = (n < 0) ? -1 : (n == 0) ? 1 : sel[0].item.a_int; + if (n > 1 && which == 1) which = sel[1].item.a_int; + if (n > 0) free((genericptr_t)sel); + } /* discover || wizard */ + + switch (which) { + case 1: reveal_terrain(FALSE); break; /* known map */ + case 2: reveal_terrain(TRUE); break; /* full map */ +#ifdef WIZARD + case 3: wiz_map_levltyp(); break; /* map internals */ + case 4: wiz_levltyp_legend(); break; /* internal details */ +#endif + default: break; + } + return 0; /* no time elapses */ +} + /* -enlightenment and conduct- */ static winid en_win = WIN_ERR; @@ -2330,6 +2478,7 @@ struct ext_func_tab extcmdlist[] = { #endif {"rub", "rub a lamp or a stone", dorub, FALSE}, {"sit", "sit down", dosit, FALSE}, + {"terrain", "show map without obstructions", doterrain, TRUE}, {"tip", "empty a container", dotip, FALSE}, {"turn", "turn undead", doturn, TRUE}, {"twoweapon", "toggle two-weapon combat", dotwoweapon, FALSE}, @@ -2356,7 +2505,6 @@ struct ext_func_tab extcmdlist[] = { #endif {(char *)0, (char *)0, donull, TRUE}, /* seenv */ {(char *)0, (char *)0, donull, TRUE}, /* stats */ - {(char *)0, (char *)0, donull, TRUE}, /* terrain */ {(char *)0, (char *)0, donull, TRUE}, /* timeout */ {(char *)0, (char *)0, donull, TRUE}, /* vanquished */ {(char *)0, (char *)0, donull, TRUE}, /* vision */ @@ -2386,7 +2534,6 @@ static const struct ext_func_tab debug_extcmdlist[] = { #endif {"seenv", "show seen vectors", wiz_show_seenv, TRUE}, {"stats", "show memory statistics", wiz_show_stats, TRUE}, - {"terrain", "show map topology", wiz_map_terrain, TRUE}, {"timeout", "look at timeout queue", wiz_timeout_queue, TRUE}, {"vanquished", "list vanquished monsters", dovanquished, TRUE}, {"vision", "show vision array", wiz_show_vision, TRUE}, diff --git a/src/detect.c b/src/detect.c index 824105207..c36f3f581 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1377,5 +1377,55 @@ sokoban_detect() } } +/* idea from crawl; show known portion of map without any monsters, + objects, or traps occluding the view of the underlying terrain */ +void +reveal_terrain(full) +boolean full; /* wizard|explore modes allow player to request full map */ +{ + int x, y, glyph, S_stone_glyph; + uchar seenv; + struct monst *mtmp; + + if ((Hallucination || Stunned || Confusion) && !full) { + You("are too disoriented for this."); + } else { + iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied; + u.uinwater = u.uburied = 0; + S_stone_glyph = cmap_to_glyph(S_stone); + /* rewrite the map, displaying map background for seen spots + (all spots seen if 'full') and stone everywhere else */ + for (x = 1; x < COLNO; x++) + for (y = 0; y < ROWNO; y++) { + seenv = levl[x][y].seenv; + if (full) { + levl[x][y].seenv = SVALL; + glyph = back_to_glyph(x, y); + levl[x][y].seenv = seenv; + } else { + if (!level.flags.hero_memory && !cansee(x, y)) + seenv = 0; + glyph = seenv ? back_to_glyph(x, y) : S_stone_glyph; + /* need to show mimic-as-furniture so that #terrain can't + be used to spot mimics, but this is only approximate; + mimic might have moved and hid here after the player + last saw this spot as some other type of terrain */ + if (seenv && (mtmp = m_at(x, y)) != 0 && + mtmp->m_ap_type == M_AP_FURNITURE) + glyph = cmap_to_glyph(mtmp->mappearance); + } + show_glyph(x, y, glyph); + } + /* [TODO: highlight hero's location somehow] */ + u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied; + flush_screen(1); + pline("Showing underlying terrain only..."); + display_nhwindow(WIN_MAP, TRUE); /* give "--More--" prompt */ + docrt(); /* redraw the screen, restoring regular map */ + if (Underwater) under_water(2); + if (u.uburied) under_ground(2); + } + return; +} /*detect.c*/