add ^ and " choices to / command

Like /m for nearby monsters and /O for all objects, implement /^
and /" to view a list of nearby traps or all known traps.  Only
lists discovered traps (or mimics immitating traps, or detected
door or chest traps iff still shown as such on map), but lists
map traps even when an object or monster at the same location is
blocking view of them.

For traps on the Water and Air levels that have been mapped, they
will only be listed when within line of sight so that this feature
can't be used to track portal location as it moves around.  However,
when within line of sight it does allow the portal to be recognized
if that has become covered.
This commit is contained in:
PatR
2021-05-30 17:31:47 -07:00
parent 494b374e12
commit 53888a713c
2 changed files with 112 additions and 16 deletions

View File

@@ -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

View File

@@ -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",