item actions for '* ) [ = " (' commands

Make the various item-in-use commands put up a menu--which allows
choosing an item for context-sensitive item action--if/when preceded
by the 'm' prefix.  Some of them do that even without the prefix ('*',
'[', or '=' when more than one ring is worn).  By default '(' shows
primary weapon, then secondary one if dual-wielding.  'm (' shows a
menu of primary, alternate whether dual-wielding it or not, and quiver.
This commit is contained in:
PatR
2023-11-28 00:31:21 -08:00
parent 75104c69ab
commit e6a7eb25d4
5 changed files with 184 additions and 63 deletions

View File

@@ -46,7 +46,7 @@
.ds f0 \*(vr
.ds f1 \" empty
.\"DO NOT REMOVE NH_DATESUB .ds f2 DATE(%B %-d, %Y)
.ds f2 "November 13, 2023
.ds f2 "November 17, 2023
.
.\" A note on some special characters:
.\" \(lq = left double quote
@@ -1576,21 +1576,44 @@ Default key is \(oqs\(cq.
.lp "#seeall "
Show all equipment in use.
Default key is \(oq*\(cq.
.lp ""
Will display in-use items in a menu even when there is only one.
.lp #seeamulet
Show the amulet currently worn.
Default key is \(oq\(dq\(cq. \" double quote
.lp ""
Using the \(oq\f(CRm\fP\(cq prefix will force the display of a worn
amulet in a menu rather than with just a message.
.lp #seearmor
Show the armor currently worn.
Default key is \(oq[\(cq.
.lp ""
Will display worn armor in a menu even when there is only thing worn.
.lp #seerings
Show the ring(s) currently worn.
Default key is \(oq=\(cq.
.lp ""
Will display worn rings in a menu if there are two (or there is
just one and is a meat ring rather than a \(lqreal\(rq ring).
Use the \(oq\f(CRm\fP\(cq prefix to force a menu for one ring.
.lp #seetools
Show the tools currently in use.
Default key is \(oq(\(cq.
.lp ""
Will display the result in a message if there is one tool in use (worn
blindfold or towel or lenses, lit lamp(s) and/or candle(s), leashes
attached to pets).
Will display a menu if there are more than one or if the command is
preceded by the \(oq\f(CRm\fP\(cq prefix.
.lp #seeweapon
Show the weapon currently wielded.
Default key is \(oq)\(cq.
.lp ""
If dual-wielding, a separate message about the secondary weapon will be
given.
Using the \(oq\f(CRm\fP\(cq prefix will force a menu and it will include
primary weapon, alternate weapon even when not dual-wielding, and also
whatever is currently assigned to the quiver slot.
.lp "#shell "
Do a shell escape, switching from NetHack to a subprocess.
Can be disabled at the time the program is built.

View File

@@ -46,7 +46,7 @@
\author{Original version - Eric S. Raymond\\
(Edited and expanded for 3.7.0 by Mike Stephenson and others)}
%DO NOT REMOVE NH_DATESUB \date{DATE(%B %-d, %Y)}
\date{November 13, 2023}
\date{November 27, 2023}
\maketitle
@@ -1697,21 +1697,47 @@ Search for traps and secret doors around you. Default key is `{\tt s}'.
%.lp
\item[\tb{\#seeall}]
Show all equipment in use. Default key is `{\tt *}'.
%.lp ""
\\
Will display in-use items in a menu even when there is only one.
%.lp
\item[\tb{\#seeamulet}]
Show the amulet currently worn. Default key is `{\tt "}'.
%.lp ""
\\
Using the `{\tt m}' prefix will force the display of a worn
amulet in a menu rather than with just a message.
%.lp
\item[\tb{\#seearmor}]
Show the armor currently worn. Default key is `{\tt [}'.
%.lp ""
\\
Will display worn armor in a menu even when there is only thing worn.
%.lp
\item[\tb{\#seerings}]
Show the ring(s) currently worn. Default key is `{\tt =}'.
%.lp ""
Will display worn rings in a menu if there are two (or there is
just one and is a meat ring rather than a ``real'' ring).
Use the `{\tt m}' prefix to force a menu for one ring.
%.lp
\item[\tb{\#seetools}]
Show the tools currently in use. Default key is `{\tt (}'.
%.lp ""
Will display the result in a message if there is one tool in use (worn
blindfold or towel or lenses, lit lamp(s) and/or candle(s), leashes
attached to pets).
Will display a menu if there are more than one or if the command is
preceded by the `{\tt m}' prefix.
%.lp
\item[\tb{\#seeweapon}]
Show the weapon currently wielded. Default key is `{\tt )}'.
%.lp ""
If dual-wielding, a separate message about the secondary weapon will be
given.
Using the `{\tt m}' prefix will force a menu and it will include
primary weapon, alternate weapon even when not dual-wielding, and also
whatever is currently assigned to the quiver slot.
%.lp
\item[\tb{\#shell}]
Do a shell escape, switching from NetHack to a subprocess.

View File

@@ -2351,6 +2351,10 @@ the '*' command (list inventory items in use) now shows items in a specific
gloves, boots, shirt, lit lamps and candles, leashes attached to pets
instead of by object class (sortpack) or inventory letter (!sortpack);
new perm_invent+perminv_mode==inuse does the same
allow the ')', '[', '(', '=', '"', and '*' commands to be preceded by the 'm'
prefix to force a menu where the player can pick an item and choose
a context-sensitive item action for it; some give a menu even without
the prefix and for those, same item selection and action can be used
Platform- and/or Interface-Specific New Features

View File

@@ -2698,17 +2698,17 @@ struct ext_func_tab extcmdlist[] = {
{ 's', "search", "search for traps and secret doors",
dosearch, IFBURIED | CMD_M_PREFIX, "searching" },
{ '*', "seeall", "show all equipment in use",
doprinuse, IFBURIED, NULL },
doprinuse, IFBURIED | CMD_M_PREFIX, NULL },
{ AMULET_SYM, "seeamulet", "show the amulet currently worn",
dopramulet, IFBURIED, NULL },
dopramulet, IFBURIED | CMD_M_PREFIX, NULL },
{ ARMOR_SYM, "seearmor", "show the armor currently worn",
doprarm, IFBURIED, NULL },
doprarm, IFBURIED | CMD_M_PREFIX, NULL },
{ RING_SYM, "seerings", "show the ring(s) currently worn",
doprring, IFBURIED, NULL },
doprring, IFBURIED | CMD_M_PREFIX, NULL },
{ TOOL_SYM, "seetools", "show the tools currently in use",
doprtool, IFBURIED, NULL },
doprtool, IFBURIED | CMD_M_PREFIX, NULL },
{ WEAPON_SYM, "seeweapon", "show the weapon currently wielded",
doprwep, IFBURIED, NULL },
doprwep, IFBURIED | CMD_M_PREFIX, NULL },
{ '!', "shell", "leave game to enter a sub-shell ('exit' to come back)",
dosh_core, (IFBURIED | GENERALCMD | NOFUZZERCMD
#ifndef SHELL
@@ -2717,7 +2717,7 @@ struct ext_func_tab extcmdlist[] = {
), NULL },
/* $ is like ),=,&c but is not included with *, so not called "seegold" */
{ GOLD_SYM, "showgold", "show gold, possibly shop credit or debt",
doprgold, IFBURIED, NULL },
doprgold, IFBURIED | CMD_M_PREFIX, NULL },
{ SPBOOK_SYM, "showspells", "list and reorder known spells",
dovspell, IFBURIED, NULL },
{ '^', "showtrap", "describe an adjacent, discovered trap",

View File

@@ -24,6 +24,7 @@ static char *cinv_ansimpleoname(struct obj *);
static boolean only_here(struct obj *);
static void compactify(char *);
static boolean taking_off(const char *);
static void mime_action(const char *);
static int ckvalidcat(struct obj *);
static int ckunpaid(struct obj *);
static char *safeq_xprname(struct obj *);
@@ -44,7 +45,8 @@ static boolean item_naming_classification(struct obj *, char *, char *);
static int item_reading_classification(struct obj *, char *);
static void ia_addmenu(winid, int, char, const char *);
static void itemactions_pushkeys(struct obj *, int);
static void mime_action(const char *);
static int itemactions(struct obj *);
static int dispinv_with_action(char *, boolean, const char *);
/* enum and structs are defined in wintype.h */
static win_request_info wri_info;
@@ -62,8 +64,10 @@ static boolean in_perm_invent_toggled;
*/
static const char venom_inv[] = { VENOM_CLASS, 0 }; /* (constant) */
/* menu heading lines used instead of object classes when sorting by in-use */
static const char *const inuse_headers[] = { /* [4] shown first, [1] last */
/* menu heading lines used instead of object classes when sorting by in-use;
pointers aren't const because dispinv_with_action() might temporarily
change "Accessories" to "Rings" or "Amulet", then back again */
static const char *inuse_headers[] = { /* [4] shown first, [1] last */
"", "Miscellaneous", "Worn Armor",
"Wielded/Readied Weapons", "Accessories",
};
@@ -3362,13 +3366,40 @@ itemactions(struct obj *otmp)
return ECMD_OK;
}
/* the #inventory command */
int
ddoinv(void)
/* show some or all of inventory while allowing the picking of an item in
order to preform context-sensitive item action on it; always returns 'ok';
invent subsets specified by the ')', '[', '(', '=', '"', or '*' commands
when they're invoked with the 'm' prefix (or without it for '*') */
static int
dispinv_with_action(
char *lets, /* list of invlet values to include */
boolean use_inuse_ordering, /* affects sortloot() and header labels */
const char *alt_label) /* alternate value for in-use "Accessories" */
{
struct obj *otmp;
char c = display_inventory((char *) 0, TRUE);
const char *save_accessories = 0;
char c, save_sortloot = 0;
unsigned len = lets ? (unsigned) strlen(lets) : 0U;
boolean menumode = (len != 1 || iflags.menu_requested) ? TRUE : FALSE,
save_force_invmenu = iflags.force_invmenu;
if (use_inuse_ordering) {
save_accessories = inuse_headers[4];
save_sortloot = flags.sortloot;
flags.sortloot = 'i'; /* checked by display_pickinv() */
if (alt_label)
inuse_headers[4] = alt_label;
}
iflags.force_invmenu = FALSE;
c = display_inventory(lets, menumode);
if (use_inuse_ordering) {
flags.sortloot = save_sortloot;
inuse_headers[4] = save_accessories;
}
iflags.force_invmenu = save_force_invmenu;
if (c && c != '\033') {
for (otmp = gi.invent; otmp; otmp = otmp->nobj)
@@ -3378,6 +3409,13 @@ ddoinv(void)
return ECMD_OK;
}
/* the #inventory command (not much left...) */
int
ddoinv(void)
{
return dispinv_with_action((char *) 0, FALSE, NULL);
}
/*
* find_unpaid()
*
@@ -3515,7 +3553,7 @@ display_pickinv(
if (!flags.invlet_constant)
reassign();
if (n == 1 && !iflags.force_invmenu) {
if (n == 1 && !iflags.force_invmenu && !iflags.menu_requested) {
/* when only one item of interest, use pline instead of menus;
we actually use a fake message-line menu in order to allow
the user to perform selection at the --More-- prompt for tty */
@@ -4860,6 +4898,14 @@ doprgold(void)
You("have no money.");
}
shopper_financial_report();
if (umoney && iflags.menu_requested) {
char dollarsign[] = "$";
/* mustn't use TRUE or gold wouldn't show up unless it was quivered */
(void) dispinv_with_action(dollarsign, FALSE, NULL);
}
return ECMD_OK;
}
@@ -4869,10 +4915,24 @@ doprwep(void)
{
if (!uwep) {
You("are %s.", empty_handed());
} else {
} else if (!iflags.menu_requested) {
prinv((char *) 0, uwep, 0L);
if (u.twoweap)
prinv((char *) 0, uswapwep, 0L);
} else {
char lets[4]; /* 4: uwep, uswapwep, uquiver, terminator */
int ct = 0;
/* obj_to_let() will assign letters to all of invent if necessary
(for '!fixinv') so doesn't need to be repeated once called here */
lets[ct++] = obj_to_let(uwep);
if (uswapwep)
lets[ct++] = uswapwep->invlet;
if (uquiver)
lets[ct++] = uquiver->invlet;
lets[ct] = '\0';
(void) dispinv_with_action(lets, TRUE, NULL);
}
return ECMD_OK;
}
@@ -4904,8 +4964,6 @@ noarmor(boolean report_uskin)
int
doprarm(void)
{
char lets[8];
int ct = 0;
/*
* Note: players sometimes get here by pressing a function key which
* transmits ''ESC [ <something>'' rather than by pressing '[';
@@ -4915,22 +4973,30 @@ doprarm(void)
if (!wearing_armor()) {
noarmor(TRUE);
} else {
if (uarmu)
lets[ct++] = obj_to_let(uarmu);
char lets[8]; /* 8: up to 7 pieces of armor plus terminator */
int ct = 0;
/* obj_to_let() will assign letters to all of invent if necessary
(for '!fixinv') so doesn't need to be repeated once called, but
each armor slot doesn't know whether any that precede have made
that call so just do it for each one; use SORTPACK_INUSE order */
if (uarm)
lets[ct++] = obj_to_let(uarm);
if (uarmc)
lets[ct++] = obj_to_let(uarmc);
if (uarmh)
lets[ct++] = obj_to_let(uarmh);
if (uarms)
lets[ct++] = obj_to_let(uarms);
if (uarmh)
lets[ct++] = obj_to_let(uarmh);
if (uarmg)
lets[ct++] = obj_to_let(uarmg);
if (uarmf)
lets[ct++] = obj_to_let(uarmf);
if (uarmu)
lets[ct++] = obj_to_let(uarmu);
lets[ct] = 0;
(void) display_inventory(lets, FALSE);
(void) dispinv_with_action(lets, TRUE, NULL);
}
return ECMD_OK;
}
@@ -4942,15 +5008,32 @@ doprring(void)
if (!uleft && !uright) {
You("are not wearing any rings.");
} else {
char lets[3];
char lets[3]; /* 3: uright, uleft, terminator */
boolean use_inuse_mode = FALSE;
int ct = 0;
if (uleft)
lets[ct++] = obj_to_let(uleft);
if (uright)
/* if either ring is a meat ring, switch to use_inuse_mode in order
to label it/them as "Rings" rather than "Comestibles" */
if (uright) {
lets[ct++] = obj_to_let(uright);
lets[ct] = 0;
(void) display_inventory(lets, FALSE);
if (uright->oclass != RING_CLASS)
use_inuse_mode = TRUE;
}
if (uleft) {
lets[ct++] = obj_to_let(uleft);
if (uleft->oclass != RING_CLASS)
use_inuse_mode = TRUE;
}
lets[ct] = '\0';
/* also switch to use_inuse_mode if there are two rings or player
used the 'm' prefix */
if (ct > 1 || iflags.menu_requested)
use_inuse_mode = TRUE;
(void) dispinv_with_action(lets, use_inuse_mode,
/* note; alternate label will be ignored
if 'use_inuse_mode' is False */
(ct == 1) ? "Ring" : "Rings");
}
return ECMD_OK;
}
@@ -4959,10 +5042,18 @@ doprring(void)
int
dopramulet(void)
{
if (!uamul)
if (!uamul) {
You("are not wearing an amulet.");
else
prinv((char *) 0, uamul, 0L);
} else {
char lets[2];
/* using display_inventory() instead of prinv() allows player
to use 'm "' to force and menu and be able to choose amulet
in order to perform a context-sensitve item action */
lets[0] = obj_to_let(uamul), lets[1] = '\0';
(void) dispinv_with_action(lets, TRUE, "Amulet");
}
return ECMD_OK;
}
@@ -5003,7 +5094,7 @@ doprtool(void)
if (!ct)
You("are not using any tools.");
else
(void) display_inventory(lets, FALSE);
(void) dispinv_with_action(lets, TRUE, NULL);
return ECMD_OK;
}
@@ -5014,41 +5105,18 @@ doprinuse(void)
{
struct obj *otmp;
int ct = 0;
#if 0 /* old doprinuse() */
char lets[52 + 1];
for (otmp = gi.invent; otmp; otmp = otmp->nobj)
if (is_inuse(otmp)) {
/* we could be carrying more than 52 items; theoretically they
might all be lit candles so avoid potential lets[] overflow */
if (ct >= (int) sizeof lets - 1)
break;
lets[ct++] = obj_to_let(otmp);
}
lets[ct] = '\0';
if (ct)
(void) display_inventory(lets, FALSE);
#else /* new */
/* no longer need to collect letters; sortloot() takes care of it, but
still need to count far enough to know whether anything is in use */
still want to count far enough to know whether anything is in use */
for (otmp = gi.invent; otmp; otmp = otmp->nobj)
if (is_inuse(otmp)) {
++ct;
break;
}
if (ct) {
char save_sortloot = flags.sortloot;
flags.sortloot = 'i';
/* bypass display_inventory() and go straight to display_pickinv() */
(void) display_pickinv((char *) 0, (char *) 0, (char *) 0,
/* 'want_reply' forces window other than WIN_INVENT */
TRUE, (long *) 0);
flags.sortloot = save_sortloot;
}
#endif
else
if (!ct)
You("are not wearing or wielding anything.");
else
(void) dispinv_with_action((char *) 0, TRUE, NULL);
return ECMD_OK;
}