diff --git a/doc/fixes37.0 b/doc/fixes37.0 index 3a8d41c26..7d6ca7349 100644 --- a/doc/fixes37.0 +++ b/doc/fixes37.0 @@ -1,4 +1,4 @@ -NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.554 $ $NHDT-Date: 1622363511 2021/05/30 08:31:51 $ +NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.555 $ $NHDT-Date: 1622421099 2021/05/31 00:31:39 $ General Fixes and Modified Features ----------------------------------- @@ -1015,6 +1015,8 @@ using 'f' while quiver is empty and 'autoquiver' is Off when wielding a to Maskerade monsters can see and remember hero resistances monsters can gain resistances by eating corpses +menu for what-is command supports /^ and /" to view a list of nearby or whole + level visible and remembered traps Platform- and/or Interface-Specific New Features diff --git a/src/pager.c b/src/pager.c index 0597b223d..9f8cf059a 100644 --- a/src/pager.c +++ b/src/pager.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 pager.c $NHDT-Date: 1620590081 2021/05/09 19:54:41 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.201 $ */ +/* NetHack 3.7 pager.c $NHDT-Date: 1622421100 2021/05/31 00:31:40 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.202 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -11,12 +11,14 @@ static boolean is_swallow_sym(int); static int append_str(char *, const char *); +static void trap_description(char *, int, int, int); static void look_at_object(char *, int, int, int); static void look_at_monster(char *, char *, struct monst *, int, int); static struct permonst *lookat(int, int, char *, char *); static void checkfile(char *, struct permonst *, boolean, boolean, char *); -static void look_all(boolean,boolean); +static void look_all(boolean, boolean); +static void look_traps(boolean); static void do_supplemental_info(char *, struct permonst *, boolean); static void whatdoes_help(void); static void docontact(void); @@ -127,6 +129,25 @@ monhealthdescr(struct monst *mon, boolean addspace, char *outbuf) return outbuf; } +/* copy a trap's description into outbuf[] */ +static void +trap_description(char *outbuf, int tnum, int x, int y) +{ + /* Trap detection displays a bear trap at locations having + * a trapped door or trapped container or both. + * + * TODO: we should create actual trap types for doors and + * chests so that they can have their own glyphs and tiles. + */ + if (trapped_chest_at(tnum, x, y)) + Strcpy(outbuf, "trapped chest"); /* might actually be a large box */ + else if (trapped_door_at(tnum, x, y)) + Strcpy(outbuf, "trapped door"); /* not "trap door"... */ + else + Strcpy(outbuf, trapname(tnum, FALSE)); + return; +} + /* describe a hidden monster; used for look_at during extended monster detection and for probing; also when looking at self */ void @@ -399,7 +420,8 @@ look_at_monster(char *buf, : (mW & M2_ELF & m2) ? "elf" : (mW & M2_ORC & m2) ? "orc" : (mW & M2_DEMON & m2) ? "demon" - : pmname(mtmp->data, Mgender(mtmp))); + : pmname(mtmp->data, + Mgender(mtmp))); Sprintf(eos(monbuf), "warned of %s", makeplural(whom)); } @@ -487,17 +509,7 @@ lookat(int x, int y, char *buf, char *monbuf) } else if (glyph_is_trap(glyph)) { int tnum = glyph_to_trap(glyph); - /* Trap detection displays a bear trap at locations having - * a trapped door or trapped container or both. - * TODO: we should create actual trap types for doors and - * chests so that they can have their own glyphs and tiles. - */ - if (trapped_chest_at(tnum, x, y)) - Strcpy(buf, "trapped chest"); /* might actually be a large box */ - else if (trapped_door_at(tnum, x, y)) - Strcpy(buf, "trapped door"); /* not "trap door"... */ - else - Strcpy(buf, trapname(tnum, FALSE)); + trap_description(buf, tnum, x, y); } else if (glyph_is_warning(glyph)) { int warnindx = glyph_to_warning(glyph); @@ -1140,7 +1152,8 @@ do_screen_description(coord cc, boolean looked, int sym, char *out_str, case SYM_PET_OVERRIDE + SYM_OFF_X: if (looked) { /* convert to symbol without override in effect */ - map_glyphinfo(cc.x, cc.y, glyph, MG_FLAG_NOOVERRIDE, &glyphinfo); + map_glyphinfo(cc.x, cc.y, glyph, MG_FLAG_NOOVERRIDE, + &glyphinfo); sym = glyphinfo.ttychar; goto check_monsters; } @@ -1285,6 +1298,14 @@ do_look(int mode, coord *click_cc) add_menu(win, &nul_glyphinfo, &any, flags.lootabc ? 0 : any.a_char, 0, ATR_NONE, "all objects shown on map", MENU_ITEMFLAGS_NONE); + any.a_char = '^'; + add_menu(win, &nul_glyphinfo, &any, + flags.lootabc ? 0 : any.a_char, 0, ATR_NONE, + "nearby traps", MENU_ITEMFLAGS_NONE); + any.a_char = '\"'; + add_menu(win, &nul_glyphinfo, &any, + flags.lootabc ? 0 : any.a_char, 0, ATR_NONE, + "all seen or remembered traps", MENU_ITEMFLAGS_NONE); } end_menu(win, "What do you want to look at:"); if (select_menu(win, PICK_ONE, &pick_list) > 0) { @@ -1351,6 +1372,12 @@ do_look(int mode, coord *click_cc) case 'O': look_all(FALSE, FALSE); /* list all objects */ return 0; + case '^': + look_traps(TRUE); /* list nearby traps */ + return 0; + case '\"': + look_traps(FALSE); /* list all traps (visible or remembered) */ + return 0; } } else { /* clicklook */ cc.x = click_cc->x; @@ -1524,6 +1551,73 @@ look_all(boolean nearby, /* True => within BOLTLIM, False => entire map */ destroy_nhwindow(win); } +/* give a /M style display of discovered traps, even when they're covered */ +static void +look_traps(boolean nearby) +{ + winid win; + struct trap *t; + int x, y, lo_x, lo_y, hi_x, hi_y, glyph, tnum, count = 0; + char lookbuf[BUFSZ], outbuf[BUFSZ]; + + win = create_nhwindow(NHW_TEXT); + lo_y = nearby ? max(u.uy - BOLT_LIM, 0) : 0; + lo_x = nearby ? max(u.ux - BOLT_LIM, 1) : 1; + hi_y = nearby ? min(u.uy + BOLT_LIM, ROWNO - 1) : ROWNO - 1; + hi_x = nearby ? min(u.ux + BOLT_LIM, COLNO - 1) : COLNO - 1; + for (y = lo_y; y <= hi_y; y++) { + for (x = lo_x; x <= hi_x; x++) { + lookbuf[0] = '\0'; + glyph = glyph_at(x, y); + if (glyph_is_trap(glyph)) { + tnum = glyph_to_trap(glyph); + trap_description(lookbuf, tnum, x, y); + ++count; + } else if ((t = t_at(x, y)) != 0 && t->tseen + /* can't use /" to track traps moved by bubbles or + clouds except when hero has direct line of sight */ + && ((!Is_waterlevel(&u.uz) && !Is_airlevel(&u.uz)) + || couldsee(x, y))) { + Strcpy(lookbuf, trapname(t->ttyp, FALSE)); + Sprintf(eos(lookbuf), ", obscured by %s", encglyph(glyph)); + glyph = trap_to_glyph(t); + ++count; + } + if (*lookbuf) { + char coordbuf[20], cmode; + + cmode = (iflags.getpos_coords != GPCOORDS_NONE) + ? iflags.getpos_coords : GPCOORDS_MAP; + if (count == 1) { + Sprintf(outbuf, "%sseen or remembered traps%s:", + nearby ? "nearby " : "", + nearby ? "" : " on this level"); + putstr(win, 0, upstart(outbuf)); + /* hack alert! Qt watches a text window for any line + with 4 consecutive spaces and renders the window + in a fixed-width font it if finds at least one */ + putstr(win, 0, " "); /* separator */ + } + /* prefix: "coords C " where 'C' is trap symbol */ + Sprintf(outbuf, (cmode == GPCOORDS_SCREEN) ? "%s " + : (cmode == GPCOORDS_MAP) ? "%8s " + : "%12s ", + coord_desc(x, y, coordbuf, cmode)); + Sprintf(eos(outbuf), "%s ", encglyph(glyph)); + /* guard against potential overflow */ + lookbuf[sizeof lookbuf - 1 - strlen(outbuf)] = '\0'; + Strcat(outbuf, lookbuf); + putmixed(win, 0, outbuf); + } + } + } + if (count) + display_nhwindow(win, TRUE); + else + pline("No traps seen or remembered%s.", nearby ? " nearby" : ""); + destroy_nhwindow(win); + } + static const char *suptext1[] = { "%s is a member of a marauding horde of orcs", "rumored to have brutally attacked and plundered",