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

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